Cycles: add "density", "flame" and "color" attributes for smoke domains.
[blender.git] / intern / cycles / blender / blender_mesh.cpp
index c61a7fafb57f8b00da76b2084b36fab33960b62f..fb667d1ba2f9535d0fb34650b6bcad028eb4c708 100644 (file)
@@ -1,19 +1,17 @@
 /*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * 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
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * 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
  */
 
  
@@ -82,15 +80,21 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float
        MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
        BL::MeshTextureFace tf = userdata->layer.data[face_num];
        float3 tfuv;
-
-       if(vert_num == 0)
-               tfuv = get_float3(tf.uv1());
-       else if(vert_num == 1)
-               tfuv = get_float3(tf.uv2());
-       else if(vert_num == 2)
-               tfuv = get_float3(tf.uv3());
-       else
-               tfuv = get_float3(tf.uv4());
+       
+       switch (vert_num) {
+               case 0:
+                       tfuv = get_float3(tf.uv1());
+                       break;
+               case 1:
+                       tfuv = get_float3(tf.uv2());
+                       break;
+               case 2:
+                       tfuv = get_float3(tf.uv3());
+                       break;
+               default:
+                       tfuv = get_float3(tf.uv4());
+                       break;
+       }
        
        uv[0] = tfuv.x;
        uv[1] = tfuv.y;
@@ -100,9 +104,16 @@ static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const
 {
        MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
        BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
-       int4 vi = get_int4(f.vertices_raw());
-       BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
-       float3 vN = get_float3(v.normal());
+       float3 vN;
+
+       if(f.use_smooth()) {
+               int4 vi = get_int4(f.vertices_raw());
+               BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
+               vN = get_float3(v.normal());
+       }
+       else {
+               vN = get_float3(f.normal());
+       }
 
        N[0] = vN.x;
        N[1] = vN.y;
@@ -195,17 +206,65 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
        }
 }
 
+/* Create Volume Attribute */
+
+static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std)
+{
+       BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+
+       if(!b_domain)
+               return;
+       
+       Attribute *attr = mesh->attributes.add(std);
+       VoxelAttribute *volume_data = attr->data_voxel();
+       bool is_float, is_linear;
+       bool animated = false;
+
+       volume_data->manager = image_manager;
+       volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
+               b_ob.ptr.data, animated, is_float, is_linear, INTERPOLATION_LINEAR);
+}
+
+static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh)
+{
+       /* 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);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY);
+}
+
 /* Create Mesh */
 
 static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
 {
-       /* create vertices */
+       /* count vertices and faces */
+       int numverts = b_mesh.vertices.length();
+       int numfaces = b_mesh.tessfaces.length();
+       int numtris = 0;
+
        BL::Mesh::vertices_iterator v;
+       BL::Mesh::tessfaces_iterator f;
 
-       for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
-               mesh->verts.push_back(get_float3(v->co()));
+       for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
+               int4 vi = get_int4(f->vertices_raw());
+               numtris += (vi[3] == 0)? 1: 2;
+       }
+
+       /* reserve memory */
+       mesh->reserve(numverts, numtris, 0, 0);
+
+       /* create vertex coordinates and normals */
+       int i = 0;
+       for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
+               mesh->verts[i] = get_float3(v->co());
 
-       /* create vertex normals */
        Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
        float3 *N = attr_N->data_float3();
 
@@ -213,10 +272,10 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                *N = get_float3(v->normal());
 
        /* create faces */
-       BL::Mesh::tessfaces_iterator f;
-       vector<int> nverts;
+       vector<int> nverts(numfaces);
+       int fi = 0, ti = 0;
 
-       for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
+       for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
                int4 vi = get_int4(f->vertices_raw());
                int n = (vi[3] == 0)? 3: 4;
                int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
@@ -224,20 +283,20 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                bool smooth = f->use_smooth();
 
                if(n == 4) {
-                       if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f ||
-                               len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) {
-                               mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
-                               mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
+                       if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
+                               is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) {
+                               mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
+                               mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
                        }
                        else {
-                               mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
-                               mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
+                               mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
+                               mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
                        }
                }
                else
-                       mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
+                       mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
 
-               nverts.push_back(n);
+               nverts[fi] = n;
        }
 
        /* create vertex color attributes */
@@ -323,9 +382,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                }
        }
 
-       /* create generated coordinates. todo: we should actually get the orco
-        * coordinates from modifiers, for now we use texspace loc/size which
-        * is available in the api. */
+       /* create generated coordinates from undeformed coordinates */
        if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
                Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
 
@@ -336,11 +393,24 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                size_t i = 0;
 
                for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
-                       generated[i++] = get_float3(v->co())*size - loc;
+                       generated[i++] = get_float3(v->undeformed_co())*size - loc;
+       }
+
+       /* 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 */
+       if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
+               Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
+               Transform *tfm = attr->data_transform();
+
+               float3 loc, size;
+               mesh_texture_space(b_mesh, loc, size);
+
+               *tfm = transform_translate(-loc)*transform_scale(size);
        }
 }
 
-static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
+static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
 {
        /* create subd mesh */
        SubdMesh sdmesh;
@@ -361,21 +431,25 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con
 
                if(n == 4)
                        sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
-#if 0
                else
                        sdmesh.add_face(vi[0], vi[1], vi[2]);
-#endif
        }
 
        /* finalize subd mesh */
-       sdmesh.link_boundary();
+       sdmesh.finish();
 
-       /* subdivide */
-       DiagSplit dsplit;
-       dsplit.camera = NULL;
-       dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
+       /* parameters */
+       bool need_ptex = mesh->need_attribute(scene, ATTR_STD_PTEX_FACE_ID) ||
+                        mesh->need_attribute(scene, ATTR_STD_PTEX_UV);
 
-       sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true);
+       SubdParams sdparams(mesh, used_shaders[0], true, need_ptex);
+       sdparams.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
+       //scene->camera->update();
+       //sdparams.camera = scene->camera;
+
+       /* tesselate */
+       DiagSplit dsplit(sdparams);
+       sdmesh.tessellate(&dsplit);
 }
 
 /* Sync */
@@ -409,6 +483,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        Mesh *mesh;
 
        if(!mesh_map.sync(&mesh, 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
@@ -435,36 +510,46 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        mesh_synced.insert(mesh);
 
        /* create derived mesh */
-       BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview);
        PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
 
        vector<Mesh::Triangle> oldtriangle = mesh->triangles;
        
-       /* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/
-       vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
+       /* compares curve_keys rather than strands in order to handle quick hair
+        * adjustsments in dynamic BVH - other methods could probably do this better*/
+       vector<float4> oldcurve_keys = mesh->curve_keys;
 
        mesh->clear();
        mesh->used_shaders = used_shaders;
        mesh->name = ustring(b_ob_data.name().c_str());
 
-       if(b_mesh) {
-               if(!(hide_tris && experimental && is_cpu)) {
-                       if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
-                               create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
-                       else
-                               create_mesh(scene, mesh, b_mesh, used_shaders);
-               }
+       if(render_layer.use_surfaces || render_layer.use_hair) {
+               if(preview)
+                       b_ob.update_from_editmode();
+
+               bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
+               BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
+
+               if(b_mesh) {
+                       if(render_layer.use_surfaces && !hide_tris) {
+                               if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
+                                       create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
+                               else
+                                       create_mesh(scene, mesh, b_mesh, used_shaders);
+
+                               create_mesh_volume_attributes(scene, b_ob, mesh);
+                       }
 
-               if(experimental && is_cpu)
-                       sync_curves(mesh, b_mesh, b_ob, object_updated);
+                       if(render_layer.use_hair)
+                               sync_curves(mesh, b_mesh, b_ob, false);
 
-               /* free derived mesh */
-               b_data.meshes.remove(b_mesh);
+                       /* free derived mesh */
+                       b_data.meshes.remove(b_mesh);
+               }
        }
 
        /* displacement method */
        if(cmesh.data) {
-               int method = RNA_enum_get(&cmesh, "displacement_method");
+               const int method = RNA_enum_get(&cmesh, "displacement_method");
 
                if(method == 0 || !experimental)
                        mesh->displacement_method = Mesh::DISPLACE_BUMP;
@@ -487,7 +572,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        if(oldcurve_keys.size() != mesh->curve_keys.size())
                rebuild = true;
        else if(oldcurve_keys.size()) {
-               if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0)
+               if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
                        rebuild = true;
        }
        
@@ -496,36 +581,119 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        return mesh;
 }
 
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
+void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
 {
-       /* todo: displacement, subdivision */
-       size_t size = mesh->verts.size();
+       /* ensure we only sync instanced meshes once */
+       Mesh *mesh = object->mesh;
 
-       /* skip objects without deforming modifiers. this is not a totally reliable,
-        * would need a more extensive check to see which objects are animated */
-       if(!size || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
+       if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
                return;
 
+       mesh_motion_synced.insert(mesh);
+
+       /* for motion pass always compute, for motion blur it can be disabled */
+       int time_index = 0;
+
+       if(scene->need_motion() == Scene::MOTION_BLUR) {
+               if(!mesh->use_motion_blur)
+                       return;
+               
+               /* see if this mesh needs motion data at this time */
+               vector<float> object_times = object->motion_times();
+               bool found = false;
+
+               foreach(float object_time, object_times) {
+                       if(motion_time == object_time) {
+                               found = true;
+                               break;
+                       }
+                       else
+                               time_index++;
+               }
+
+               if(!found)
+                       return;
+       }
+       else {
+               if(motion_time == -1.0f)
+                       time_index = 0;
+               else if(motion_time == 1.0f)
+                       time_index = 1;
+               else
+                       return;
+       }
+
+       /* skip objects without deforming modifiers. this is not totally reliable,
+        * would need a more extensive check to see which objects are animated */
+       size_t numverts = mesh->verts.size();
+       size_t numkeys = mesh->curve_keys.size();
+
+       if((!numverts && !numkeys) || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
+               return;
+       
        /* get derived mesh */
-       BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview);
+       BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
 
-       if(b_mesh) {
-               BL::Mesh::vertices_iterator v;
-               AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
-               Attribute *attr_M = mesh->attributes.add(std);
-               float3 *M = attr_M->data_float3(), *cur_M;
-               size_t i = 0;
+       if(!b_mesh)
+               return;
+       
+       if(numverts) {
+               /* find attributes */
+               Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+               Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+               bool new_attribute = false;
+
+               /* add new attributes if they don't exist already */
+               if(!attr_mP) {
+                       attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+                       if(attr_N)
+                               attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+                       new_attribute = true;
+               }
 
-               for(b_mesh.vertices.begin(v), cur_M = M; v != b_mesh.vertices.end() && i < size; ++v, cur_M++, i++)
-                       *cur_M = get_float3(v->co());
+               /* load vertex data from mesh */
+               float3 *mP = attr_mP->data_float3() + time_index*numverts;
+               float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
 
-               /* if number of vertices changed, or if coordinates stayed the same, drop it */
-               if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
-                       mesh->attributes.remove(std);
+               BL::Mesh::vertices_iterator v;
+               int i = 0;
+
+               for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
+                       mP[i] = get_float3(v->co());
+                       if(mN)
+                               mN[i] = get_float3(v->normal());
+               }
 
-               /* free derived mesh */
-               b_data.meshes.remove(b_mesh);
+               /* in case of new attribute, we verify if there really was any motion */
+               if(new_attribute) {
+                       if(i != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) {
+                               /* no motion, remove attributes again */
+                               mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+                               if(attr_mN)
+                                       mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
+                       }
+                       else if(time_index > 0) {
+                               /* motion, fill up previous steps that we might have skipped because
+                                * they had no motion, but we need them anyway now */
+                               float3 *P = &mesh->verts[0];
+                               float3 *N = (attr_N)? attr_N->data_float3(): NULL;
+
+                               for(int step = 0; step < time_index; step++) {
+                                       memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
+                                       memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
+                               }
+                       }
+               }
        }
+
+       /* hair motion */
+       if(numkeys)
+               sync_curves(mesh, b_mesh, b_ob, true, time_index);
+
+       /* free derived mesh */
+       b_data.meshes.remove(b_mesh);
 }
 
 CCL_NAMESPACE_END