9214882bb9b08d4bbd377230c79fa9551df5cabb
[blender-staging.git] / intern / cycles / blender / blender_curves.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "attribute.h"
18 #include "camera.h"
19 #include "curves.h"
20 #include "mesh.h"
21 #include "object.h"
22 #include "scene.h"
23
24 #include "blender_sync.h"
25 #include "blender_util.h"
26
27 #include "util_foreach.h"
28 #include "util_logging.h"
29
30 CCL_NAMESPACE_BEGIN
31
32 ParticleCurveData::ParticleCurveData()
33 {
34 }
35
36 ParticleCurveData::~ParticleCurveData()
37 {
38 }
39
40 static void interp_weights(float t, float data[4])
41 {
42         /* Cardinal curve interpolation */
43         float t2 = t * t;
44         float t3 = t2 * t;
45         float fc = 0.71f;
46
47         data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
48         data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
49         data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
50         data[3] =  fc          * t3  - fc * t2;
51 }
52
53 static void curveinterp_v3_v3v3v3v3(float3 *p,
54                                     float3 *v1, float3 *v2, float3 *v3, float3 *v4,
55                                     const float w[4])
56 {
57         p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
58         p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
59         p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
60 }
61
62 static float shaperadius(float shape, float root, float tip, float time)
63 {
64         float radius = 1.0f - time;
65
66         if(shape != 0.0f) {
67                 if(shape < 0.0f)
68                         radius = powf(radius, 1.0f + shape);
69                 else
70                         radius = powf(radius, 1.0f / (1.0f - shape));
71         }
72         return (radius * (root - tip)) + tip;
73 }
74
75 /* curve functions */
76
77 static void InterpolateKeySegments(int seg,
78                                    int segno,
79                                    int key,
80                                    int curve,
81                                    float3 *keyloc,
82                                    float *time,
83                                    ParticleCurveData *CData)
84 {
85         float3 ckey_loc1 = CData->curvekey_co[key];
86         float3 ckey_loc2 = ckey_loc1;
87         float3 ckey_loc3 = CData->curvekey_co[key+1];
88         float3 ckey_loc4 = ckey_loc3;
89
90         if(key > CData->curve_firstkey[curve])
91                 ckey_loc1 = CData->curvekey_co[key - 1];
92
93         if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
94                 ckey_loc4 = CData->curvekey_co[key + 2];
95
96         float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
97         float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
98
99         float dfra = (time2 - time1) / (float)segno;
100
101         if(time)
102                 *time = (dfra * seg) + time1;
103
104         float t[4];
105
106         interp_weights((float)seg / (float)segno, t);
107
108         if(keyloc)
109                 curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
110 }
111
112 static bool ObtainCacheParticleData(Mesh *mesh,
113                                     BL::Mesh *b_mesh,
114                                     BL::Object *b_ob,
115                                     ParticleCurveData *CData,
116                                     bool background)
117 {
118         int curvenum = 0;
119         int keyno = 0;
120
121         if(!(mesh && b_mesh && b_ob && CData))
122                 return false;
123
124         Transform tfm = get_transform(b_ob->matrix_world());
125         Transform itfm = transform_quick_inverse(tfm);
126
127         BL::Object::modifiers_iterator b_mod;
128         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
129                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
130                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
131                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
132                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
133
134                         if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
135                                 int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
136                                 int draw_step = background ? b_part.render_step() : b_part.draw_step();
137                                 int totparts = b_psys.particles.length();
138                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
139                                 int totcurves = totchild;
140
141                                 if(b_part.child_type() == 0 || totchild == 0)
142                                         totcurves += totparts;
143
144                                 if(totcurves == 0)
145                                         continue;
146
147                                 int ren_step = (1 << draw_step) + 1;
148                                 if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
149                                         ren_step += b_part.kink_extra_steps();
150
151                                 PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
152
153                                 CData->psys_firstcurve.push_back_slow(curvenum);
154                                 CData->psys_curvenum.push_back_slow(totcurves);
155                                 CData->psys_shader.push_back_slow(shader);
156
157                                 float radius = get_float(cpsys, "radius_scale") * 0.5f;
158
159                                 CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width"));
160                                 CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width"));
161                                 CData->psys_shape.push_back_slow(get_float(cpsys, "shape"));
162                                 CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip"));
163
164                                 int pa_no = 0;
165                                 if(!(b_part.child_type() == 0) && totchild != 0)
166                                         pa_no = totparts;
167
168                                 int num_add = (totparts+totchild - pa_no);
169                                 CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
170                                 CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
171                                 CData->curve_length.reserve(CData->curve_length.size() + num_add);
172                                 CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
173                                 CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
174
175                                 for(; pa_no < totparts+totchild; pa_no++) {
176                                         int keynum = 0;
177                                         CData->curve_firstkey.push_back_slow(keyno);
178
179                                         float curve_length = 0.0f;
180                                         float3 pcKey;
181                                         for(int step_no = 0; step_no < ren_step; step_no++) {
182                                                 float nco[3];
183                                                 b_psys.co_hair(*b_ob, pa_no, step_no, nco);
184                                                 float3 cKey = make_float3(nco[0], nco[1], nco[2]);
185                                                 cKey = transform_point(&itfm, cKey);
186                                                 if(step_no > 0) {
187                                                         float step_length = len(cKey - pcKey);
188                                                         if(step_length == 0.0f)
189                                                                 continue;
190                                                         curve_length += step_length;
191                                                 }
192                                                 CData->curvekey_co.push_back_slow(cKey);
193                                                 CData->curvekey_time.push_back_slow(curve_length);
194                                                 pcKey = cKey;
195                                                 keynum++;
196                                         }
197                                         keyno += keynum;
198
199                                         CData->curve_keynum.push_back_slow(keynum);
200                                         CData->curve_length.push_back_slow(curve_length);
201                                         curvenum++;
202                                 }
203                         }
204                 }
205         }
206
207         return true;
208 }
209
210 static bool ObtainCacheParticleUV(Mesh *mesh,
211                                   BL::Mesh *b_mesh,
212                                   BL::Object *b_ob,
213                                   ParticleCurveData *CData,
214                                   bool background,
215                                   int uv_num)
216 {
217         if(!(mesh && b_mesh && b_ob && CData))
218                 return false;
219
220         CData->curve_uv.clear();
221
222         BL::Object::modifiers_iterator b_mod;
223         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
224                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
225                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
226                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
227                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
228
229                         if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
230                                 int totparts = b_psys.particles.length();
231                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
232                                 int totcurves = totchild;
233
234                                 if(b_part.child_type() == 0 || totchild == 0)
235                                         totcurves += totparts;
236
237                                 if(totcurves == 0)
238                                         continue;
239
240                                 int pa_no = 0;
241                                 if(!(b_part.child_type() == 0) && totchild != 0)
242                                         pa_no = totparts;
243
244                                 int num_add = (totparts+totchild - pa_no);
245                                 CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
246
247                                 BL::ParticleSystem::particles_iterator b_pa;
248                                 b_psys.particles.begin(b_pa);
249                                 for(; pa_no < totparts+totchild; pa_no++) {
250                                         /* Add UVs */
251                                         BL::Mesh::tessface_uv_textures_iterator l;
252                                         b_mesh->tessface_uv_textures.begin(l);
253
254                                         float3 uv = make_float3(0.0f, 0.0f, 0.0f);
255                                         if(b_mesh->tessface_uv_textures.length())
256                                                 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
257                                         CData->curve_uv.push_back_slow(uv);
258
259                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
260                                                 ++b_pa;
261                                 }
262                         }
263                 }
264         }
265
266         return true;
267 }
268
269 static bool ObtainCacheParticleVcol(Mesh *mesh,
270                                     BL::Mesh *b_mesh,
271                                     BL::Object *b_ob,
272                                     ParticleCurveData *CData,
273                                     bool background,
274                                     int vcol_num)
275 {
276         if(!(mesh && b_mesh && b_ob && CData))
277                 return false;
278
279         CData->curve_vcol.clear();
280
281         BL::Object::modifiers_iterator b_mod;
282         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
283                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
284                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
285                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
286                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
287
288                         if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
289                                 int totparts = b_psys.particles.length();
290                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
291                                 int totcurves = totchild;
292
293                                 if(b_part.child_type() == 0 || totchild == 0)
294                                         totcurves += totparts;
295
296                                 if(totcurves == 0)
297                                         continue;
298
299                                 int pa_no = 0;
300                                 if(!(b_part.child_type() == 0) && totchild != 0)
301                                         pa_no = totparts;
302
303                                 int num_add = (totparts+totchild - pa_no);
304                                 CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
305
306                                 BL::ParticleSystem::particles_iterator b_pa;
307                                 b_psys.particles.begin(b_pa);
308                                 for(; pa_no < totparts+totchild; pa_no++) {
309                                         /* Add vertex colors */
310                                         BL::Mesh::tessface_vertex_colors_iterator l;
311                                         b_mesh->tessface_vertex_colors.begin(l);
312
313                                         float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
314                                         if(b_mesh->tessface_vertex_colors.length())
315                                                 b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
316                                         CData->curve_vcol.push_back_slow(vcol);
317
318                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
319                                                 ++b_pa;
320                                 }
321                         }
322                 }
323         }
324
325         return true;
326 }
327
328 static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
329 {
330         BL::Object::modifiers_iterator b_mod;
331         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
332                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
333                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
334                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
335                         b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
336                 }
337         }
338 }
339
340 static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
341                                       float3 RotCam, bool is_ortho)
342 {
343         int vertexno = mesh->verts.size();
344         int vertexindex = vertexno;
345         int numverts = 0, numtris = 0;
346
347         /* compute and reserve size of arrays */
348         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
349                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
350                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
351                                 continue;
352
353                         numverts += 2 + (CData->curve_keynum[curve] - 1)*2;
354                         numtris += (CData->curve_keynum[curve] - 1)*2;
355                 }
356         }
357
358         mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
359
360         /* actually export */
361         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
362                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
363                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
364                                 continue;
365
366                         float3 xbasis;
367                         float3 v1;
368                         float time = 0.0f;
369                         float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]];
370                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f);
371                         v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]];
372                         if(is_ortho)
373                                 xbasis = normalize(cross(RotCam, v1));
374                         else
375                                 xbasis = normalize(cross(RotCam - ickey_loc, v1));
376                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
377                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
378                         mesh->add_vertex(ickey_loc_shfl);
379                         mesh->add_vertex(ickey_loc_shfr);
380                         vertexindex += 2;
381
382                         for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
383                                 ickey_loc = CData->curvekey_co[curvekey];
384
385                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
386                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])];
387                                 else
388                                         v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
389
390                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
391                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
392
393                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
394                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
395
396                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
397                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
398
399                                 if(is_ortho)
400                                         xbasis = normalize(cross(RotCam, v1));
401                                 else
402                                         xbasis = normalize(cross(RotCam - ickey_loc, v1));
403                                 float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
404                                 float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
405                                 mesh->add_vertex(ickey_loc_shfl);
406                                 mesh->add_vertex(ickey_loc_shfr);
407                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
408                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
409                                 vertexindex += 2;
410                         }
411                 }
412         }
413
414         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
415         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
416         mesh->add_face_normals();
417         mesh->add_vertex_normals();
418         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
419
420         /* texture coords still needed */
421 }
422
423 static void ExportCurveTriangleGeometry(Mesh *mesh,
424                                         ParticleCurveData *CData,
425                                         int resolution)
426 {
427         int vertexno = mesh->verts.size();
428         int vertexindex = vertexno;
429         int numverts = 0, numtris = 0;
430
431         /* compute and reserve size of arrays */
432         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
433                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
434                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
435                                 continue;
436
437                         numverts += (CData->curve_keynum[curve] - 2)*2*resolution + resolution;
438                         numtris += (CData->curve_keynum[curve] - 2)*resolution;
439                 }
440         }
441
442         mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
443
444         /* actually export */
445         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
446                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
447                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
448                                 continue;
449
450                         float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]);
451                         if(!is_zero(firstxbasis))
452                                 firstxbasis = normalize(firstxbasis);
453                         else
454                                 firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]));
455
456                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
457                                 float3 xbasis = firstxbasis;
458                                 float3 v1;
459                                 float3 v2;
460
461                                 if(curvekey == CData->curve_firstkey[curve]) {
462                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
463                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
464                                 }
465                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
466                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
467                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
468                                 }
469                                 else {
470                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
471                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
472                                 }
473
474                                 xbasis = cross(v1, v2);
475
476                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
477                                         firstxbasis = normalize(xbasis);
478                                         break;
479                                 }
480                         }
481
482                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
483                                 int subv = 1;
484                                 float3 xbasis;
485                                 float3 ybasis;
486                                 float3 v1;
487                                 float3 v2;
488
489                                 if(curvekey == CData->curve_firstkey[curve]) {
490                                         subv = 0;
491                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
492                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
493                                 }
494                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
495                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
496                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
497                                 }
498                                 else {
499                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
500                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
501                                 }
502
503                                 xbasis = cross(v1, v2);
504
505                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
506                                         xbasis = normalize(xbasis);
507                                         firstxbasis = xbasis;
508                                 }
509                                 else
510                                         xbasis = firstxbasis;
511
512                                 ybasis = normalize(cross(xbasis, v2));
513
514                                 for(; subv <= 1; subv++) {
515                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
516                                         float time = 0.0f;
517
518                                         InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData);
519
520                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
521
522                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1))
523                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
524
525                                         if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
526                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
527
528                                         float angle = M_2PI_F / (float)resolution;
529                                         for(int section = 0; section < resolution; section++) {
530                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
531                                                 mesh->add_vertex(ickey_loc_shf);
532                                         }
533
534                                         if(subv != 0) {
535                                                 for(int section = 0; section < resolution - 1; section++) {
536                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true);
537                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true);
538                                                 }
539                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true);
540                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true);
541                                         }
542                                         vertexindex += resolution;
543                                 }
544                         }
545                 }
546         }
547
548         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
549         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
550         mesh->add_face_normals();
551         mesh->add_vertex_normals();
552         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
553
554         /* texture coords still needed */
555 }
556
557 static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
558 {
559         int num_keys = 0;
560         int num_curves = 0;
561
562         if(mesh->num_curves())
563                 return;
564
565         Attribute *attr_intercept = NULL;
566
567         if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
568                 attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
569
570         /* compute and reserve size of arrays */
571         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
572                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
573                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
574                                 continue;
575
576                         num_keys += CData->curve_keynum[curve];
577                         num_curves++;
578                 }
579         }
580
581         if(num_curves > 0) {
582                 VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
583         }
584
585         mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
586
587         num_keys = 0;
588         num_curves = 0;
589
590         /* actually export */
591         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
592                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
593                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
594                                 continue;
595
596                         size_t num_curve_keys = 0;
597
598                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
599                                 float3 ickey_loc = CData->curvekey_co[curvekey];
600                                 float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
601                                 float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
602
603                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
604                                         radius = 0.0f;
605
606                                 mesh->add_curve_key(ickey_loc, radius);
607                                 if(attr_intercept)
608                                         attr_intercept->add(time);
609
610                                 num_curve_keys++;
611                         }
612
613                         mesh->add_curve(num_keys, CData->psys_shader[sys]);
614                         num_keys += num_curve_keys;
615                         num_curves++;
616                 }
617         }
618
619         /* check allocation */
620         if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
621                 VLOG(1) << "Allocation failed, clearing data";
622                 mesh->clear();
623         }
624 }
625
626 static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
627 {
628         VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
629                 << ", time index " << time_index;
630
631         /* find attribute */
632         Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
633         bool new_attribute = false;
634
635         /* add new attribute if it doesn't exist already */
636         if(!attr_mP) {
637                 VLOG(1) << "Creating new motion vertex position attribute";
638                 attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
639                 new_attribute = true;
640         }
641
642         /* export motion vectors for curve keys */
643         size_t numkeys = mesh->curve_keys.size();
644         float4 *mP = attr_mP->data_float4() + time_index*numkeys;
645         bool have_motion = false;
646         int i = 0;
647
648         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
649                 if(CData->psys_curvenum[sys] == 0)
650                         continue;
651
652                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
653                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
654                                 continue;
655
656                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
657                                 if(i < mesh->curve_keys.size()) {
658                                         float3 ickey_loc = CData->curvekey_co[curvekey];
659                                         float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
660                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
661
662                                         if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
663                                                 radius = 0.0f;
664
665                                         /* curve motion keys store both position and radius in float4 */
666                                         mP[i] = float3_to_float4(ickey_loc);
667                                         mP[i].w = radius;
668
669                                         /* unlike mesh coordinates, these tend to be slightly different
670                                          * between frames due to particle transforms into/out of object
671                                          * space, so we use an epsilon to detect actual changes */
672                                         float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
673                                         curve_key.w = mesh->curve_radius[i];
674                                         if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
675                                                 have_motion = true;
676                                 }
677
678                                 i++;
679                         }
680                 }
681         }
682
683         /* in case of new attribute, we verify if there really was any motion */
684         if(new_attribute) {
685                 if(i != numkeys || !have_motion) {
686                         /* No motion or hair "topology" changed, remove attributes again. */
687                         if(i != numkeys) {
688                                 VLOG(1) << "Hair topology changed, removing attribute.";
689                         }
690                         else {
691                                 VLOG(1) << "No motion, removing attribute.";
692                         }
693                         mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
694                 }
695                 else if(time_index > 0) {
696                         VLOG(1) << "Filling in new motion vertex position for time_index "
697                                 << time_index;
698                         /* motion, fill up previous steps that we might have skipped because
699                          * they had no motion, but we need them anyway now */
700                         for(int step = 0; step < time_index; step++) {
701                                 float4 *mP = attr_mP->data_float4() + step*numkeys;
702
703                                 for(int key = 0; key < numkeys; key++) {
704                                         mP[key] = float3_to_float4(mesh->curve_keys[key]);
705                                         mP[key].w = mesh->curve_radius[key];
706                                 }
707                         }
708                 }
709         }
710 }
711
712 static void ExportCurveTriangleUV(ParticleCurveData *CData,
713                                   int vert_offset,
714                                   int resol,
715                                   float3 *uvdata)
716 {
717         if(uvdata == NULL)
718                 return;
719
720         float time = 0.0f;
721         float prevtime = 0.0f;
722
723         int vertexindex = vert_offset;
724
725         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
726                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
727                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
728                                 continue;
729
730                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
731                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
732
733                                 for(int section = 0; section < resol; section++) {
734                                         uvdata[vertexindex] = CData->curve_uv[curve];
735                                         uvdata[vertexindex].z = prevtime;
736                                         vertexindex++;
737                                         uvdata[vertexindex] = CData->curve_uv[curve];
738                                         uvdata[vertexindex].z = time;
739                                         vertexindex++;
740                                         uvdata[vertexindex] = CData->curve_uv[curve];
741                                         uvdata[vertexindex].z = prevtime;
742                                         vertexindex++;
743                                         uvdata[vertexindex] = CData->curve_uv[curve];
744                                         uvdata[vertexindex].z = time;
745                                         vertexindex++;
746                                         uvdata[vertexindex] = CData->curve_uv[curve];
747                                         uvdata[vertexindex].z = prevtime;
748                                         vertexindex++;
749                                         uvdata[vertexindex] = CData->curve_uv[curve];
750                                         uvdata[vertexindex].z = time;
751                                         vertexindex++;
752                                 }
753
754                                 prevtime = time;
755                         }
756                 }
757         }
758 }
759
760 static void ExportCurveTriangleVcol(ParticleCurveData *CData,
761                                     int vert_offset,
762                                     int resol,
763                                     uchar4 *cdata)
764 {
765         if(cdata == NULL)
766                 return;
767
768         int vertexindex = vert_offset;
769
770         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
771                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
772                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
773                                 continue;
774
775                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
776                                 for(int section = 0; section < resol; section++) {
777                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
778                                         vertexindex++;
779                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
780                                         vertexindex++;
781                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
782                                         vertexindex++;
783                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
784                                         vertexindex++;
785                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
786                                         vertexindex++;
787                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
788                                         vertexindex++;
789                                 }
790                         }
791                 }
792         }
793 }
794
795 /* Hair Curve Sync */
796
797 void BlenderSync::sync_curve_settings()
798 {
799         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
800
801         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
802         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
803
804         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
805         curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
806         curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
807
808         curve_system_manager->primitive =
809                 (CurvePrimitiveType)get_enum(csscene,
810                                              "primitive",
811                                              CURVE_NUM_PRIMITIVE_TYPES,
812                                              CURVE_LINE_SEGMENTS);
813         curve_system_manager->curve_shape =
814                 (CurveShapeType)get_enum(csscene,
815                                          "shape",
816                                          CURVE_NUM_SHAPE_TYPES,
817                                          CURVE_THICK);
818         curve_system_manager->resolution = get_int(csscene, "resolution");
819         curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
820         curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
821
822         /* Triangles */
823         if(curve_system_manager->primitive == CURVE_TRIANGLES) {
824                 /* camera facing planes */
825                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
826                         curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
827                         curve_system_manager->resolution = 1;
828                 }
829                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
830                         curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
831                 }
832         }
833         /* Line Segments */
834         else if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS) {
835                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
836                         /* tangent shading */
837                         curve_system_manager->line_method = CURVE_UNCORRECTED;
838                         curve_system_manager->use_encasing = true;
839                         curve_system_manager->use_backfacing = false;
840                         curve_system_manager->use_tangent_normal_geometry = true;
841                 }
842                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
843                         curve_system_manager->line_method = CURVE_ACCURATE;
844                         curve_system_manager->use_encasing = false;
845                         curve_system_manager->use_tangent_normal_geometry = false;
846                 }
847         }
848         /* Curve Segments */
849         else if(curve_system_manager->primitive == CURVE_SEGMENTS) {
850                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
851                         curve_system_manager->primitive = CURVE_RIBBONS;
852                         curve_system_manager->use_backfacing = false;
853                 }
854         }
855
856         if(curve_system_manager->modified_mesh(prev_curve_system_manager)) {
857                 BL::BlendData::objects_iterator b_ob;
858
859                 for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
860                         if(object_is_mesh(*b_ob)) {
861                                 BL::Object::particle_systems_iterator b_psys;
862                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
863                                         if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) {
864                                                 BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
865                                                 mesh_map.set_recalc(key);
866                                                 object_map.set_recalc(*b_ob);
867                                         }
868                                 }
869                         }
870                 }
871         }
872
873         if(curve_system_manager->modified(prev_curve_system_manager))
874                 curve_system_manager->tag_update(scene);
875 }
876
877 void BlenderSync::sync_curves(Mesh *mesh,
878                               BL::Mesh& b_mesh,
879                               BL::Object& b_ob,
880                               bool motion,
881                               int time_index)
882 {
883         if(!motion) {
884                 /* Clear stored curve data */
885                 mesh->curve_keys.clear();
886                 mesh->curve_radius.clear();
887                 mesh->curve_first_key.clear();
888                 mesh->curve_shader.clear();
889                 mesh->curve_attributes.clear();
890         }
891
892         /* obtain general settings */
893         const bool use_curves = scene->curve_system_manager->use_curves;
894
895         if(!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) {
896                 if(!motion)
897                         mesh->compute_bounds();
898                 return;
899         }
900
901         const int primitive = scene->curve_system_manager->primitive;
902         const int triangle_method = scene->curve_system_manager->triangle_method;
903         const int resolution = scene->curve_system_manager->resolution;
904         const size_t vert_num = mesh->verts.size();
905         const size_t tri_num = mesh->num_triangles();
906         int used_res = 1;
907
908         /* extract particle hair data - should be combined with connecting to mesh later*/
909
910         ParticleCurveData CData;
911
912         if(!preview)
913                 set_resolution(&b_ob, &b_scene, true);
914
915         ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
916
917         /* add hair geometry to mesh */
918         if(primitive == CURVE_TRIANGLES) {
919                 if(triangle_method == CURVE_CAMERA_TRIANGLES) {
920                         /* obtain camera parameters */
921                         float3 RotCam;
922                         Camera *camera = scene->camera;
923                         Transform &ctfm = camera->matrix;
924                         if(camera->type == CAMERA_ORTHOGRAPHIC) {
925                                 RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
926                         }
927                         else {
928                                 Transform tfm = get_transform(b_ob.matrix_world());
929                                 Transform itfm = transform_quick_inverse(tfm);
930                                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
931                                                                             ctfm.y.w,
932                                                                             ctfm.z.w));
933                         }
934                         bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
935                         ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
936                 }
937                 else {
938                         ExportCurveTriangleGeometry(mesh, &CData, resolution);
939                         used_res = resolution;
940                 }
941         }
942         else {
943                 if(motion)
944                         ExportCurveSegmentsMotion(mesh, &CData, time_index);
945                 else
946                         ExportCurveSegments(scene, mesh, &CData);
947         }
948
949         /* generated coordinates from first key. we should ideally get this from
950          * blender to handle deforming objects */
951         if(!motion) {
952                 if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
953                         float3 loc, size;
954                         mesh_texture_space(b_mesh, loc, size);
955
956                         if(primitive == CURVE_TRIANGLES) {
957                                 Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
958                                 float3 *generated = attr_generated->data_float3();
959
960                                 for(size_t i = vert_num; i < mesh->verts.size(); i++)
961                                         generated[i] = mesh->verts[i]*size - loc;
962                         }
963                         else {
964                                 Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
965                                 float3 *generated = attr_generated->data_float3();
966
967                                 for(size_t i = 0; i < mesh->num_curves(); i++) {
968                                         float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
969                                         generated[i] = co*size - loc;
970                                 }
971                         }
972                 }
973         }
974
975         /* create vertex color attributes */
976         if(!motion) {
977                 BL::Mesh::tessface_vertex_colors_iterator l;
978                 int vcol_num = 0;
979
980                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
981                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
982                                 continue;
983
984                         ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
985
986                         if(primitive == CURVE_TRIANGLES) {
987                                 Attribute *attr_vcol = mesh->attributes.add(
988                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
989
990                                 uchar4 *cdata = attr_vcol->data_uchar4();
991
992                                 ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
993                         }
994                         else {
995                                 Attribute *attr_vcol = mesh->curve_attributes.add(
996                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
997
998                                 float3 *fdata = attr_vcol->data_float3();
999
1000                                 if(fdata) {
1001                                         size_t i = 0;
1002
1003                                         for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
1004                                                 if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
1005                                                         fdata[i++] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
1006                                 }
1007                         }
1008                 }
1009         }
1010
1011         /* create UV attributes */
1012         if(!motion) {
1013                 BL::Mesh::tessface_uv_textures_iterator l;
1014                 int uv_num = 0;
1015
1016                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
1017                         bool active_render = l->active_render();
1018                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
1019                         ustring name = ustring(l->name().c_str());
1020
1021                         /* UV map */
1022                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
1023                                 Attribute *attr_uv;
1024
1025                                 ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
1026
1027                                 if(primitive == CURVE_TRIANGLES) {
1028                                         if(active_render)
1029                                                 attr_uv = mesh->attributes.add(std, name);
1030                                         else
1031                                                 attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
1032
1033                                         float3 *uv = attr_uv->data_float3();
1034
1035                                         ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
1036                                 }
1037                                 else {
1038                                         if(active_render)
1039                                                 attr_uv = mesh->curve_attributes.add(std, name);
1040                                         else
1041                                                 attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
1042
1043                                         float3 *uv = attr_uv->data_float3();
1044
1045                                         if(uv) {
1046                                                 size_t i = 0;
1047
1048                                                 for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
1049                                                         if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
1050                                                                 uv[i++] = CData.curve_uv[curve];
1051                                         }
1052                                 }
1053                         }
1054                 }
1055         }
1056
1057         if(!preview)
1058                 set_resolution(&b_ob, &b_scene, false);
1059
1060         mesh->compute_bounds();
1061 }
1062
1063 CCL_NAMESPACE_END