Merging r46111 through r46136 from trunk into soc-2011-tomato
[blender-staging.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<float4> d_output;
93         d_output.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_output, MEM_WRITE_ONLY);
98
99         DeviceTask task(DeviceTask::SHADER);
100         task.shader_input = d_input.device_pointer;
101         task.shader_output = d_output.device_pointer;
102         task.shader_eval_type = SHADER_EVAL_DISPLACE;
103         task.shader_x = 0;
104         task.shader_w = d_input.size();
105
106         device->task_add(task);
107         device->task_wait();
108
109         device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
110         device->mem_free(d_input);
111         device->mem_free(d_output);
112
113         if(progress.get_cancel())
114                 return false;
115
116         /* read result */
117         done.clear();
118         done.resize(mesh->verts.size(), false);
119         int k = 0;
120
121         float4 *offset = (float4*)d_output.data_pointer;
122
123         for(size_t i = 0; i < mesh->triangles.size(); i++) {
124                 Mesh::Triangle t = mesh->triangles[i];
125                 Shader *shader = scene->shaders[mesh->shader[i]];
126
127                 if(!shader->has_displacement)
128                         continue;
129
130                 for(int j = 0; j < 3; j++) {
131                         if(!done[t.v[j]]) {
132                                 done[t.v[j]] = true;
133                                 float3 off = float4_to_float3(offset[k++]);
134                                 mesh->verts[t.v[j]] += off;
135                         }
136                 }
137         }
138
139         /* for displacement method both, we only need to recompute the face
140          * normals, as bump mapping in the shader will already alter the
141          * vertex normal, so we start from the non-displaced vertex normals
142          * to avoid applying the perturbation twice. */
143         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
144         mesh->add_face_normals();
145
146         if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
147                 mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
148                 mesh->add_vertex_normals();
149         }
150
151         return true;
152 }
153
154 CCL_NAMESPACE_END
155