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