Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / cycles / render / mesh_displace.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "device.h"
20
21 #include "mesh.h"
22 #include "scene.h"
23 #include "shader.h"
24
25 #include "util_foreach.h"
26 #include "util_progress.h"
27
28 CCL_NAMESPACE_BEGIN
29
30 bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& progress)
31 {
32         /* verify if we have a displacement shader */
33         bool has_displacement = false;
34
35         if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
36                 foreach(uint sindex, mesh->used_shaders)
37                         if(scene->shaders[sindex]->has_displacement)
38                                 has_displacement = true;
39         }
40         
41         if(!has_displacement)
42                 return false;
43
44         /* setup input for device task */
45         vector<bool> done(mesh->verts.size(), false);
46         device_vector<uint4> d_input;
47         uint4 *d_input_data = d_input.resize(mesh->verts.size());
48         size_t d_input_offset = 0;
49
50         for(size_t i = 0; i < mesh->triangles.size(); i++) {
51                 Mesh::Triangle t = mesh->triangles[i];
52                 Shader *shader = scene->shaders[mesh->shader[i]];
53
54                 if(!shader->has_displacement)
55                         continue;
56
57                 for(int j = 0; j < 3; j++) {
58                         if(done[t.v[j]])
59                                 continue;
60
61                         done[t.v[j]] = true;
62
63                         /* set up object, primitive and barycentric coordinates */
64                         /* when used, non-instanced convention: object = -object-1; */
65                         int object = ~0; /* todo */
66                         int prim = mesh->tri_offset + i;
67                         float u, v;
68
69                         if(j == 0) {
70                                 u = 1.0f;
71                                 v = 0.0f;
72                         }
73                         else if(j == 1) {
74                                 u = 0.0f;
75                                 v = 1.0f;
76                         }
77                         else {
78                                 u = 0.0f;
79                                 v = 0.0f;
80                         }
81
82                         /* back */
83                         uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
84                         d_input_data[d_input_offset++] = in;
85                 }
86         }
87
88         if(d_input_offset == 0)
89                 return false;
90         
91         /* run device task */
92         device_vector<float3> d_offset;
93         d_offset.resize(d_input.size());
94
95         device->mem_alloc(d_input, MEM_READ_ONLY);
96         device->mem_copy_to(d_input);
97         device->mem_alloc(d_offset, MEM_WRITE_ONLY);
98
99         DeviceTask task(DeviceTask::DISPLACE);
100         task.displace_input = d_input.device_pointer;
101         task.displace_offset = d_offset.device_pointer;
102         task.displace_x = 0;
103         task.displace_w = d_input.size();
104
105         device->task_add(task);
106         device->task_wait();
107
108         device->mem_copy_from(d_offset, 0, sizeof(float3)*d_offset.size());
109         device->mem_free(d_input);
110         device->mem_free(d_offset);
111
112         if(progress.get_cancel())
113                 return false;
114
115         /* read result */
116         done.clear();
117         done.resize(mesh->verts.size(), false);
118         int k = 0;
119
120         float3 *offset = (float3*)d_offset.data_pointer;
121
122         for(size_t i = 0; i < mesh->triangles.size(); i++) {
123                 Mesh::Triangle t = mesh->triangles[i];
124                 Shader *shader = scene->shaders[mesh->shader[i]];
125
126                 if(!shader->has_displacement)
127                         continue;
128
129                 for(int j = 0; j < 3; j++) {
130                         if(!done[t.v[j]]) {
131                                 done[t.v[j]] = true;
132                                 mesh->verts[t.v[j]] += offset[k++];
133                         }
134                 }
135         }
136
137         /* for displacement method both, we only need to recompute the face
138          * normals, as bump mapping in the shader will already alter the
139          * vertex normal, so we start from the non-displaced vertex normals
140          * to avoid applying the perturbation twice. */
141         mesh->attributes.remove(Attribute::STD_FACE_NORMAL);
142         mesh->add_face_normals();
143
144         if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
145                 mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
146                 mesh->add_vertex_normals();
147         }
148
149         return true;
150 }
151
152 CCL_NAMESPACE_END
153