add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[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 "object.h"
23 #include "scene.h"
24 #include "shader.h"
25
26 #include "util_foreach.h"
27 #include "util_progress.h"
28
29 CCL_NAMESPACE_BEGIN
30
31 bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
32 {
33         /* verify if we have a displacement shader */
34         bool has_displacement = false;
35
36         if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
37                 foreach(uint sindex, mesh->used_shaders)
38                         if(scene->shaders[sindex]->has_displacement)
39                                 has_displacement = true;
40         }
41         
42         if(!has_displacement)
43                 return false;
44
45         string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
46         progress.set_status("Updating Mesh", msg);
47
48         /* find object index. todo: is arbitrary */
49         size_t object_index = ~0;
50
51         for(size_t i = 0; i < scene->objects.size(); i++) {
52                 if(scene->objects[i]->mesh == mesh) {
53                         object_index = i;
54                         break;
55                 }
56         }
57
58         /* setup input for device task */
59         vector<bool> done(mesh->verts.size(), false);
60         device_vector<uint4> d_input;
61         uint4 *d_input_data = d_input.resize(mesh->verts.size());
62         size_t d_input_size = 0;
63
64         for(size_t i = 0; i < mesh->triangles.size(); i++) {
65                 Mesh::Triangle t = mesh->triangles[i];
66                 Shader *shader = scene->shaders[mesh->shader[i]];
67
68                 if(!shader->has_displacement)
69                         continue;
70
71                 for(int j = 0; j < 3; j++) {
72                         if(done[t.v[j]])
73                                 continue;
74
75                         done[t.v[j]] = true;
76
77                         /* set up object, primitive and barycentric coordinates */
78                         /* when used, non-instanced convention: object = ~object */
79                         int object = ~object_index;
80                         int prim = mesh->tri_offset + i;
81                         float u, v;
82                         
83                         switch (j) {
84                                 case 0:
85                                         u = 1.0f;
86                                         v = 0.0f;
87                                         break;
88                                 case 1:
89                                         u = 0.0f;
90                                         v = 1.0f;
91                                         break;
92                                 default:
93                                         u = 0.0f;
94                                         v = 0.0f;
95                                         break;
96                         }
97
98                         /* back */
99                         uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
100                         d_input_data[d_input_size++] = in;
101                 }
102         }
103
104         if(d_input_size == 0)
105                 return false;
106         
107         /* run device task */
108         device_vector<float4> d_output;
109         d_output.resize(d_input_size);
110
111         /* needs to be up to data for attribute access */
112         device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
113
114         device->mem_alloc(d_input, MEM_READ_ONLY);
115         device->mem_copy_to(d_input);
116         device->mem_alloc(d_output, MEM_WRITE_ONLY);
117
118         DeviceTask task(DeviceTask::SHADER);
119         task.shader_input = d_input.device_pointer;
120         task.shader_output = d_output.device_pointer;
121         task.shader_eval_type = SHADER_EVAL_DISPLACE;
122         task.shader_x = 0;
123         task.shader_w = d_output.size();
124
125         device->task_add(task);
126         device->task_wait();
127
128         device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
129         device->mem_free(d_input);
130         device->mem_free(d_output);
131
132         if(progress.get_cancel())
133                 return false;
134
135         /* read result */
136         done.clear();
137         done.resize(mesh->verts.size(), false);
138         int k = 0;
139
140         float4 *offset = (float4*)d_output.data_pointer;
141
142         for(size_t i = 0; i < mesh->triangles.size(); i++) {
143                 Mesh::Triangle t = mesh->triangles[i];
144                 Shader *shader = scene->shaders[mesh->shader[i]];
145
146                 if(!shader->has_displacement)
147                         continue;
148
149                 for(int j = 0; j < 3; j++) {
150                         if(!done[t.v[j]]) {
151                                 done[t.v[j]] = true;
152                                 float3 off = float4_to_float3(offset[k++]);
153                                 mesh->verts[t.v[j]] += off;
154                         }
155                 }
156         }
157
158         /* for displacement method both, we only need to recompute the face
159          * normals, as bump mapping in the shader will already alter the
160          * vertex normal, so we start from the non-displaced vertex normals
161          * to avoid applying the perturbation twice. */
162         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
163         mesh->add_face_normals();
164
165         if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
166                 mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
167                 mesh->add_vertex_normals();
168         }
169
170         return true;
171 }
172
173 CCL_NAMESPACE_END
174