63b07936426d8ef778c76e4bcf2eca6227b0c4e9
[blender.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 "render/attribute.h"
18 #include "render/camera.h"
19 #include "render/curves.h"
20 #include "render/mesh.h"
21 #include "render/object.h"
22 #include "render/scene.h"
23
24 #include "blender/blender_sync.h"
25 #include "blender/blender_util.h"
26
27 #include "util/util_foreach.h"
28 #include "util/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, BL::SceneLayer *sl, 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, *sl, *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->resize_mesh(mesh->verts.size(), mesh->num_triangles());
415         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
416         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
417         mesh->add_face_normals();
418         mesh->add_vertex_normals();
419         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
420
421         /* texture coords still needed */
422 }
423
424 static void ExportCurveTriangleGeometry(Mesh *mesh,
425                                         ParticleCurveData *CData,
426                                         int resolution)
427 {
428         int vertexno = mesh->verts.size();
429         int vertexindex = vertexno;
430         int numverts = 0, numtris = 0;
431
432         /* compute and reserve size of arrays */
433         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
434                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
435                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
436                                 continue;
437
438                         numverts += (CData->curve_keynum[curve] - 1)*resolution + resolution;
439                         numtris += (CData->curve_keynum[curve] - 1)*2*resolution;
440                 }
441         }
442
443         mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
444
445         /* actually export */
446         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
447                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
448                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
449                                 continue;
450
451                         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]]);
452                         if(!is_zero(firstxbasis))
453                                 firstxbasis = normalize(firstxbasis);
454                         else
455                                 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]]));
456
457                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
458                                 float3 xbasis = firstxbasis;
459                                 float3 v1;
460                                 float3 v2;
461
462                                 if(curvekey == CData->curve_firstkey[curve]) {
463                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
464                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
465                                 }
466                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
467                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
468                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
469                                 }
470                                 else {
471                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
472                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
473                                 }
474
475                                 xbasis = cross(v1, v2);
476
477                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
478                                         firstxbasis = normalize(xbasis);
479                                         break;
480                                 }
481                         }
482
483                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
484                                 int subv = 1;
485                                 float3 xbasis;
486                                 float3 ybasis;
487                                 float3 v1;
488                                 float3 v2;
489
490                                 if(curvekey == CData->curve_firstkey[curve]) {
491                                         subv = 0;
492                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
493                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
494                                 }
495                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
496                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
497                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
498                                 }
499                                 else {
500                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
501                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
502                                 }
503
504                                 xbasis = cross(v1, v2);
505
506                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
507                                         xbasis = normalize(xbasis);
508                                         firstxbasis = xbasis;
509                                 }
510                                 else
511                                         xbasis = firstxbasis;
512
513                                 ybasis = normalize(cross(xbasis, v2));
514
515                                 for(; subv <= 1; subv++) {
516                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
517                                         float time = 0.0f;
518
519                                         InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData);
520
521                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
522
523                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1))
524                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
525
526                                         if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
527                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
528
529                                         float angle = M_2PI_F / (float)resolution;
530                                         for(int section = 0; section < resolution; section++) {
531                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
532                                                 mesh->add_vertex(ickey_loc_shf);
533                                         }
534
535                                         if(subv != 0) {
536                                                 for(int section = 0; section < resolution - 1; section++) {
537                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true);
538                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true);
539                                                 }
540                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true);
541                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true);
542                                         }
543                                         vertexindex += resolution;
544                                 }
545                         }
546                 }
547         }
548
549         mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles());
550         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
551         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
552         mesh->add_face_normals();
553         mesh->add_vertex_normals();
554         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
555
556         /* texture coords still needed */
557 }
558
559 static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
560 {
561         int num_keys = 0;
562         int num_curves = 0;
563
564         if(mesh->num_curves())
565                 return;
566
567         Attribute *attr_intercept = NULL;
568
569         if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
570                 attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
571
572         /* compute and reserve size of arrays */
573         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
574                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
575                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
576                                 continue;
577
578                         num_keys += CData->curve_keynum[curve];
579                         num_curves++;
580                 }
581         }
582
583         if(num_curves > 0) {
584                 VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
585         }
586
587         mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
588
589         num_keys = 0;
590         num_curves = 0;
591
592         /* actually export */
593         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
594                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
595                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
596                                 continue;
597
598                         size_t num_curve_keys = 0;
599
600                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
601                                 float3 ickey_loc = CData->curvekey_co[curvekey];
602                                 float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
603                                 float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
604
605                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
606                                         radius = 0.0f;
607
608                                 mesh->add_curve_key(ickey_loc, radius);
609                                 if(attr_intercept)
610                                         attr_intercept->add(time);
611
612                                 num_curve_keys++;
613                         }
614
615                         mesh->add_curve(num_keys, CData->psys_shader[sys]);
616                         num_keys += num_curve_keys;
617                         num_curves++;
618                 }
619         }
620
621         /* check allocation */
622         if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
623                 VLOG(1) << "Allocation failed, clearing data";
624                 mesh->clear();
625         }
626 }
627
628 static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
629 {
630         VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
631                 << ", time index " << time_index;
632
633         /* find attribute */
634         Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
635         bool new_attribute = false;
636
637         /* add new attribute if it doesn't exist already */
638         if(!attr_mP) {
639                 VLOG(1) << "Creating new motion vertex position attribute";
640                 attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
641                 new_attribute = true;
642         }
643
644         /* export motion vectors for curve keys */
645         size_t numkeys = mesh->curve_keys.size();
646         float4 *mP = attr_mP->data_float4() + time_index*numkeys;
647         bool have_motion = false;
648         int i = 0;
649
650         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
651                 if(CData->psys_curvenum[sys] == 0)
652                         continue;
653
654                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
655                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
656                                 continue;
657
658                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
659                                 if(i < mesh->curve_keys.size()) {
660                                         float3 ickey_loc = CData->curvekey_co[curvekey];
661                                         float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
662                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
663
664                                         if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
665                                                 radius = 0.0f;
666
667                                         /* curve motion keys store both position and radius in float4 */
668                                         mP[i] = float3_to_float4(ickey_loc);
669                                         mP[i].w = radius;
670
671                                         /* unlike mesh coordinates, these tend to be slightly different
672                                          * between frames due to particle transforms into/out of object
673                                          * space, so we use an epsilon to detect actual changes */
674                                         float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
675                                         curve_key.w = mesh->curve_radius[i];
676                                         if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
677                                                 have_motion = true;
678                                 }
679
680                                 i++;
681                         }
682                 }
683         }
684
685         /* in case of new attribute, we verify if there really was any motion */
686         if(new_attribute) {
687                 if(i != numkeys || !have_motion) {
688                         /* No motion or hair "topology" changed, remove attributes again. */
689                         if(i != numkeys) {
690                                 VLOG(1) << "Hair topology changed, removing attribute.";
691                         }
692                         else {
693                                 VLOG(1) << "No motion, removing attribute.";
694                         }
695                         mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
696                 }
697                 else if(time_index > 0) {
698                         VLOG(1) << "Filling in new motion vertex position for time_index "
699                                 << time_index;
700                         /* motion, fill up previous steps that we might have skipped because
701                          * they had no motion, but we need them anyway now */
702                         for(int step = 0; step < time_index; step++) {
703                                 float4 *mP = attr_mP->data_float4() + step*numkeys;
704
705                                 for(int key = 0; key < numkeys; key++) {
706                                         mP[key] = float3_to_float4(mesh->curve_keys[key]);
707                                         mP[key].w = mesh->curve_radius[key];
708                                 }
709                         }
710                 }
711         }
712 }
713
714 static void ExportCurveTriangleUV(ParticleCurveData *CData,
715                                   int vert_offset,
716                                   int resol,
717                                   float3 *uvdata)
718 {
719         if(uvdata == NULL)
720                 return;
721
722         float time = 0.0f;
723         float prevtime = 0.0f;
724
725         int vertexindex = vert_offset;
726
727         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
728                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
729                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
730                                 continue;
731
732                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
733                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
734
735                                 for(int section = 0; section < resol; section++) {
736                                         uvdata[vertexindex] = CData->curve_uv[curve];
737                                         uvdata[vertexindex].z = prevtime;
738                                         vertexindex++;
739                                         uvdata[vertexindex] = CData->curve_uv[curve];
740                                         uvdata[vertexindex].z = time;
741                                         vertexindex++;
742                                         uvdata[vertexindex] = CData->curve_uv[curve];
743                                         uvdata[vertexindex].z = prevtime;
744                                         vertexindex++;
745                                         uvdata[vertexindex] = CData->curve_uv[curve];
746                                         uvdata[vertexindex].z = time;
747                                         vertexindex++;
748                                         uvdata[vertexindex] = CData->curve_uv[curve];
749                                         uvdata[vertexindex].z = prevtime;
750                                         vertexindex++;
751                                         uvdata[vertexindex] = CData->curve_uv[curve];
752                                         uvdata[vertexindex].z = time;
753                                         vertexindex++;
754                                 }
755
756                                 prevtime = time;
757                         }
758                 }
759         }
760 }
761
762 static void ExportCurveTriangleVcol(ParticleCurveData *CData,
763                                     int vert_offset,
764                                     int resol,
765                                     uchar4 *cdata)
766 {
767         if(cdata == NULL)
768                 return;
769
770         int vertexindex = vert_offset;
771
772         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
773                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
774                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
775                                 continue;
776
777                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
778                                 for(int section = 0; section < resol; section++) {
779                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
780                                         vertexindex++;
781                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
782                                         vertexindex++;
783                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
784                                         vertexindex++;
785                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
786                                         vertexindex++;
787                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
788                                         vertexindex++;
789                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
790                                         vertexindex++;
791                                 }
792                         }
793                 }
794         }
795 }
796
797 /* Hair Curve Sync */
798
799 void BlenderSync::sync_curve_settings()
800 {
801         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
802
803         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
804         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
805
806         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
807         curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
808         curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
809
810         curve_system_manager->primitive =
811                 (CurvePrimitiveType)get_enum(csscene,
812                                              "primitive",
813                                              CURVE_NUM_PRIMITIVE_TYPES,
814                                              CURVE_LINE_SEGMENTS);
815         curve_system_manager->curve_shape =
816                 (CurveShapeType)get_enum(csscene,
817                                          "shape",
818                                          CURVE_NUM_SHAPE_TYPES,
819                                          CURVE_THICK);
820         curve_system_manager->resolution = get_int(csscene, "resolution");
821         curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
822         curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
823
824         /* Triangles */
825         if(curve_system_manager->primitive == CURVE_TRIANGLES) {
826                 /* camera facing planes */
827                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
828                         curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
829                         curve_system_manager->resolution = 1;
830                 }
831                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
832                         curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
833                 }
834         }
835         /* Line Segments */
836         else if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS) {
837                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
838                         /* tangent shading */
839                         curve_system_manager->line_method = CURVE_UNCORRECTED;
840                         curve_system_manager->use_encasing = true;
841                         curve_system_manager->use_backfacing = false;
842                         curve_system_manager->use_tangent_normal_geometry = true;
843                 }
844                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
845                         curve_system_manager->line_method = CURVE_ACCURATE;
846                         curve_system_manager->use_encasing = false;
847                         curve_system_manager->use_tangent_normal_geometry = false;
848                 }
849         }
850         /* Curve Segments */
851         else if(curve_system_manager->primitive == CURVE_SEGMENTS) {
852                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
853                         curve_system_manager->primitive = CURVE_RIBBONS;
854                         curve_system_manager->use_backfacing = false;
855                 }
856         }
857
858         if(curve_system_manager->modified_mesh(prev_curve_system_manager)) {
859                 BL::BlendData::objects_iterator b_ob;
860
861                 for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
862                         if(object_is_mesh(*b_ob)) {
863                                 BL::Object::particle_systems_iterator b_psys;
864                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
865                                         if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) {
866                                                 BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
867                                                 mesh_map.set_recalc(key);
868                                                 object_map.set_recalc(*b_ob);
869                                         }
870                                 }
871                         }
872                 }
873         }
874
875         if(curve_system_manager->modified(prev_curve_system_manager))
876                 curve_system_manager->tag_update(scene);
877 }
878
879 void BlenderSync::sync_curves(Mesh *mesh,
880                               BL::Mesh& b_mesh,
881                               BL::Object& b_ob,
882                               bool motion,
883                               int time_index)
884 {
885         if(!motion) {
886                 /* Clear stored curve data */
887                 mesh->curve_keys.clear();
888                 mesh->curve_radius.clear();
889                 mesh->curve_first_key.clear();
890                 mesh->curve_shader.clear();
891                 mesh->curve_attributes.clear();
892         }
893
894         /* obtain general settings */
895         const bool use_curves = scene->curve_system_manager->use_curves;
896
897         if(!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) {
898                 if(!motion)
899                         mesh->compute_bounds();
900                 return;
901         }
902
903         const int primitive = scene->curve_system_manager->primitive;
904         const int triangle_method = scene->curve_system_manager->triangle_method;
905         const int resolution = scene->curve_system_manager->resolution;
906         const size_t vert_num = mesh->verts.size();
907         const size_t tri_num = mesh->num_triangles();
908         int used_res = 1;
909
910         /* extract particle hair data - should be combined with connecting to mesh later*/
911
912         ParticleCurveData CData;
913
914         if(!preview)
915                 set_resolution(&b_ob, &b_scene, &b_scene_layer, true);
916
917         ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
918
919         /* add hair geometry to mesh */
920         if(primitive == CURVE_TRIANGLES) {
921                 if(triangle_method == CURVE_CAMERA_TRIANGLES) {
922                         /* obtain camera parameters */
923                         float3 RotCam;
924                         Camera *camera = scene->camera;
925                         Transform &ctfm = camera->matrix;
926                         if(camera->type == CAMERA_ORTHOGRAPHIC) {
927                                 RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
928                         }
929                         else {
930                                 Transform tfm = get_transform(b_ob.matrix_world());
931                                 Transform itfm = transform_quick_inverse(tfm);
932                                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
933                                                                             ctfm.y.w,
934                                                                             ctfm.z.w));
935                         }
936                         bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
937                         ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
938                 }
939                 else {
940                         ExportCurveTriangleGeometry(mesh, &CData, resolution);
941                         used_res = resolution;
942                 }
943         }
944         else {
945                 if(motion)
946                         ExportCurveSegmentsMotion(mesh, &CData, time_index);
947                 else
948                         ExportCurveSegments(scene, mesh, &CData);
949         }
950
951         /* generated coordinates from first key. we should ideally get this from
952          * blender to handle deforming objects */
953         if(!motion) {
954                 if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
955                         float3 loc, size;
956                         mesh_texture_space(b_mesh, loc, size);
957
958                         if(primitive == CURVE_TRIANGLES) {
959                                 Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
960                                 float3 *generated = attr_generated->data_float3();
961
962                                 for(size_t i = vert_num; i < mesh->verts.size(); i++)
963                                         generated[i] = mesh->verts[i]*size - loc;
964                         }
965                         else {
966                                 Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
967                                 float3 *generated = attr_generated->data_float3();
968
969                                 for(size_t i = 0; i < mesh->num_curves(); i++) {
970                                         float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
971                                         generated[i] = co*size - loc;
972                                 }
973                         }
974                 }
975         }
976
977         /* create vertex color attributes */
978         if(!motion) {
979                 BL::Mesh::tessface_vertex_colors_iterator l;
980                 int vcol_num = 0;
981
982                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
983                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
984                                 continue;
985
986                         ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
987
988                         if(primitive == CURVE_TRIANGLES) {
989                                 Attribute *attr_vcol = mesh->attributes.add(
990                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
991
992                                 uchar4 *cdata = attr_vcol->data_uchar4();
993
994                                 ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
995                         }
996                         else {
997                                 Attribute *attr_vcol = mesh->curve_attributes.add(
998                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
999
1000                                 float3 *fdata = attr_vcol->data_float3();
1001
1002                                 if(fdata) {
1003                                         size_t i = 0;
1004
1005                                         for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
1006                                                 if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
1007                                                         fdata[i++] = color_srgb_to_scene_linear_v3(CData.curve_vcol[curve]);
1008                                 }
1009                         }
1010                 }
1011         }
1012
1013         /* create UV attributes */
1014         if(!motion) {
1015                 BL::Mesh::tessface_uv_textures_iterator l;
1016                 int uv_num = 0;
1017
1018                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
1019                         bool active_render = l->active_render();
1020                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
1021                         ustring name = ustring(l->name().c_str());
1022
1023                         /* UV map */
1024                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
1025                                 Attribute *attr_uv;
1026
1027                                 ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
1028
1029                                 if(primitive == CURVE_TRIANGLES) {
1030                                         if(active_render)
1031                                                 attr_uv = mesh->attributes.add(std, name);
1032                                         else
1033                                                 attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
1034
1035                                         float3 *uv = attr_uv->data_float3();
1036
1037                                         ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
1038                                 }
1039                                 else {
1040                                         if(active_render)
1041                                                 attr_uv = mesh->curve_attributes.add(std, name);
1042                                         else
1043                                                 attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
1044
1045                                         float3 *uv = attr_uv->data_float3();
1046
1047                                         if(uv) {
1048                                                 size_t i = 0;
1049
1050                                                 for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
1051                                                         if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
1052                                                                 uv[i++] = CData.curve_uv[curve];
1053                                         }
1054                                 }
1055                         }
1056                 }
1057         }
1058
1059         if(!preview)
1060                 set_resolution(&b_ob, &b_scene, &b_scene_layer, false);
1061
1062         mesh->compute_bounds();
1063 }
1064
1065 CCL_NAMESPACE_END