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