Cycles / Math:
[blender-staging.git] / intern / cycles / blender / blender_curves.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "attribute.h"
20 #include "mesh.h"
21 #include "object.h"
22 #include "scene.h"
23 #include "curves.h"
24
25 #include "blender_sync.h"
26 #include "blender_util.h"
27
28 #include "util_foreach.h"
29
30 CCL_NAMESPACE_BEGIN
31
32 /* Utilities */
33
34 /* Hair curve functions */
35
36 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
37 void interp_weights(float t, float data[4], int type);
38 float shaperadius(float shape, float root, float tip, float time);
39 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
40 bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int uv_num);
41 bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int vcol_num);
42 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background);
43 void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments);
44 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam);
45 void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments);
46 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments);
47 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments, int vert_offset, int resol, float3 *uvdata);
48 void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments, int vert_offset, int resol, float3 *fdata);
49
50 ParticleCurveData::ParticleCurveData()
51 {
52 }
53
54 ParticleCurveData::~ParticleCurveData()
55 {
56         psys_firstcurve.clear();
57         psys_curvenum.clear();
58         psys_shader.clear();
59         psys_rootradius.clear();
60         psys_tipradius.clear();
61         psys_shape.clear();
62
63         curve_firstkey.clear();
64         curve_keynum.clear();
65         curve_length.clear();
66         curve_uv.clear();
67         curve_vcol.clear();
68
69         curvekey_co.clear();
70         curvekey_time.clear();
71 }
72
73 void interp_weights(float t, float data[4], int type)
74 {
75         float t2, t3, fc;
76         
77         switch (type) {
78                 case CURVE_LINEAR:
79                         data[0] =          0.0f;
80                         data[1] = -t     + 1.0f;
81                         data[2] =  t;
82                         data[3] =          0.0f;
83                         break;
84                 case CURVE_CARDINAL:
85                         t2 = t * t;
86                         t3 = t2 * t;
87                         fc = 0.71f;
88
89                         data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
90                         data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
91                         data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
92                         data[3] =  fc          * t3  - fc * t2;
93                         break;
94                 case CURVE_BSPLINE:
95                         t2 = t * t;
96                         t3 = t2 * t;
97
98                         data[0] = -0.16666666f * t3  + 0.5f * t2   - 0.5f * t    + 0.16666666f;
99                         data[1] =  0.5f        * t3  - t2                        + 0.66666666f;
100                         data[2] = -0.5f        * t3  + 0.5f * t2   + 0.5f * t    + 0.16666666f;
101                         data[3] =  0.16666666f * t3;
102                         break;
103                 default:
104                         break;
105         }
106 }
107
108 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
109 {
110         p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
111         p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
112         p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
113 }
114
115 float shaperadius(float shape, float root, float tip, float time)
116 {
117         float radius = 1.0f - time;
118         if(shape != 0.0f) {
119                 if(shape < 0.0f)
120                         radius = (float)pow(1.0f - time, 1.f + shape);
121                 else
122                         radius = (float)pow(1.0f - time, 1.f / (1.f - shape));
123         }
124         return (radius * (root - tip)) + tip;
125 }
126
127 /* curve functions */
128
129 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation)
130 {
131         float3 ckey_loc1 = CData->curvekey_co[key];
132         float3 ckey_loc2 = ckey_loc1;
133         float3 ckey_loc3 = CData->curvekey_co[key+1];
134         float3 ckey_loc4 = ckey_loc3;
135
136         if(key > CData->curve_firstkey[curve])
137                 ckey_loc1 = CData->curvekey_co[key - 1];
138
139         if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
140                 ckey_loc4 = CData->curvekey_co[key + 2];
141
142
143         float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
144         float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
145
146         float dfra = (time2 - time1) / (float)segno;
147
148         if(time)
149                 *time = (dfra * seg) + time1;
150
151         float t[4];
152
153         interp_weights((float)seg / (float)segno, t, interpolation);
154
155         if(keyloc)
156                 curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
157 }
158
159 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background)
160 {
161
162         int curvenum = 0;
163         int keyno = 0;
164
165         if(!(mesh && b_mesh && b_ob && CData))
166                 return false;
167
168         Transform tfm = get_transform(b_ob->matrix_world());
169         Transform itfm = transform_quick_inverse(tfm);
170
171         BL::Object::modifiers_iterator b_mod;
172         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
173                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
174                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
175
176                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
177
178                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
179
180                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
181
182                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
183                                 int shader = mesh->used_shaders[mi];
184                                 int draw_step = background ? b_psys.settings().render_step() : b_psys.settings().draw_step();
185                                 int ren_step = (int)pow((float)2.0f,(float)draw_step);
186                                 int totparts = b_psys.particles.length();
187                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
188                                 int totcurves = totchild;
189                                 
190                                 if(use_parents || b_psys.settings().child_type() == 0)
191                                         totcurves += totparts;
192
193                                 if(totcurves == 0)
194                                         continue;
195
196                                 PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
197
198                                 CData->psys_firstcurve.push_back(curvenum);
199                                 CData->psys_curvenum.push_back(totcurves);
200                                 CData->psys_shader.push_back(shader);
201
202                                 float radius = get_float(cpsys, "radius_scale") * 0.5f;
203         
204                                 CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
205                                 CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
206                                 CData->psys_shape.push_back(get_float(cpsys, "shape"));
207                                 CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
208
209                                 int pa_no = 0;
210                                 if(!use_parents && !(b_psys.settings().child_type() == 0))
211                                         pa_no = totparts;
212
213                                 for(; pa_no < totparts+totchild; pa_no++) {
214
215                                         CData->curve_firstkey.push_back(keyno);
216                                         CData->curve_keynum.push_back(ren_step+1);
217                                         
218                                         float curve_length = 0.0f;
219                                         float3 pcKey;
220                                         for(int step_no = 0; step_no <= ren_step; step_no++) {
221                                                 float nco[3];
222                                                 b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco);
223                                                 float3 cKey = make_float3(nco[0],nco[1],nco[2]);
224                                                 cKey = transform_point(&itfm, cKey);
225                                                 if(step_no > 0)
226                                                         curve_length += len(cKey - pcKey);
227                                                 CData->curvekey_co.push_back(cKey);
228                                                 CData->curvekey_time.push_back(curve_length);
229                                                 pcKey = cKey;
230                                                 keyno++;
231                                         }
232                                         CData->curve_length.push_back(curve_length);
233
234                                         curvenum++;
235
236                                 }
237                         }
238
239                 }
240         }
241
242         return true;
243
244 }
245
246 bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int uv_num)
247 {
248 #if 0
249         int keyno = 0;
250 #endif
251
252         if(!(mesh && b_mesh && b_ob && CData))
253                 return false;
254
255 #if 0
256         Transform tfm = get_transform(b_ob->matrix_world());
257         Transform itfm = transform_quick_inverse(tfm);
258 #endif
259
260         CData->curve_uv.clear();
261
262         BL::Object::modifiers_iterator b_mod;
263         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
264                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
265                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
266
267                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
268
269                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
270
271                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
272 #if 0
273                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
274                                 int shader = mesh->used_shaders[mi];
275 #endif
276
277                                 int totparts = b_psys.particles.length();
278                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
279                                 int totcurves = totchild;
280                                 
281                                 if (use_parents || b_psys.settings().child_type() == 0)
282                                         totcurves += totparts;
283
284                                 if (totcurves == 0)
285                                         continue;
286
287                                 int pa_no = 0;
288                                 if(!use_parents && !(b_psys.settings().child_type() == 0))
289                                         pa_no = totparts;
290
291                                 BL::ParticleSystem::particles_iterator b_pa;
292                                 b_psys.particles.begin(b_pa);
293                                 for(; pa_no < totparts+totchild; pa_no++) {
294
295                                         /*add uvs*/
296                                         BL::Mesh::tessface_uv_textures_iterator l;
297                                         b_mesh->tessface_uv_textures.begin(l);
298
299                                         float3 uv = make_float3(0.0f, 0.0f, 0.0f);
300                                         if(b_mesh->tessface_uv_textures.length())
301                                                 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
302                                         CData->curve_uv.push_back(uv);
303
304                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
305                                                 ++b_pa;
306
307                                 }
308                         }
309
310                 }
311         }
312
313         return true;
314
315 }
316
317 bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int vcol_num)
318 {
319 #if 0
320         int keyno = 0;
321 #endif
322         if(!(mesh && b_mesh && b_ob && CData))
323                 return false;
324
325 #if 0
326         Transform tfm = get_transform(b_ob->matrix_world());
327         Transform itfm = transform_quick_inverse(tfm);
328 #endif
329
330         CData->curve_vcol.clear();
331
332         BL::Object::modifiers_iterator b_mod;
333         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
334                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
335                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
336
337                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
338
339                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
340
341                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
342 #if 0
343                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
344                                 int shader = mesh->used_shaders[mi];
345 #endif
346                                 int totparts = b_psys.particles.length();
347                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
348                                 int totcurves = totchild;
349                                 
350                                 if (use_parents || b_psys.settings().child_type() == 0)
351                                         totcurves += totparts;
352
353                                 if (totcurves == 0)
354                                         continue;
355
356                                 int pa_no = 0;
357                                 if(!use_parents && !(b_psys.settings().child_type() == 0))
358                                         pa_no = totparts;
359
360                                 BL::ParticleSystem::particles_iterator b_pa;
361                                 b_psys.particles.begin(b_pa);
362                                 for(; pa_no < totparts+totchild; pa_no++) {
363
364                                         /*add uvs*/
365                                         BL::Mesh::tessface_vertex_colors_iterator l;
366                                         b_mesh->tessface_vertex_colors.begin(l);
367
368                                         float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
369                                         if(b_mesh->tessface_vertex_colors.length())
370                                                 b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
371                                         CData->curve_vcol.push_back(vcol);
372
373                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
374                                                 ++b_pa;
375
376                                 }
377                         }
378
379                 }
380         }
381
382         return true;
383
384 }
385
386 static void set_resolution(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, BL::Scene *scene, bool render)
387 {
388         BL::Object::modifiers_iterator b_mod;
389         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
390                 if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
391                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
392                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
393                         b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
394                 }
395         }
396 }
397
398 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam)
399 {
400         int vertexno = mesh->verts.size();
401         int vertexindex = vertexno;
402
403         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
404                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
405
406                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
407
408                                 int subv = 1;
409                                 float3 xbasis;
410
411                                 float3 v1;
412
413                                 if(curvekey == CData->curve_firstkey[curve]) {
414                                         subv = 0;
415                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey];
416                                 }
417                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
418                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])];
419                                 else 
420                                         v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
421
422
423                                 for (; subv <= segments; subv++) {
424
425                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
426                                         float time = 0.0f;
427
428                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
429                                                 ickey_loc = CData->curvekey_co[curvekey];
430                                         else
431                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
432
433                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
434
435                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
436                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
437
438                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
439                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
440
441                                         xbasis = normalize(cross(RotCam - ickey_loc,v1));
442                                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
443                                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
444                                         mesh->verts.push_back(ickey_loc_shfl);
445                                         mesh->verts.push_back(ickey_loc_shfr);
446                                         if(subv!=0) {
447                                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
448                                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
449                                         }
450                                         vertexindex += 2;
451                                 }
452                         }
453                 }
454         }
455
456         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
457         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
458         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
459         mesh->add_face_normals();
460         mesh->add_vertex_normals();
461         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
462
463         /* texture coords still needed */
464 }
465
466 void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments)
467 {
468         int vertexno = mesh->verts.size();
469         int vertexindex = vertexno;
470
471         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
472                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
473
474                         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]]);
475                         if(len_squared(firstxbasis)!= 0.0f)
476                                 firstxbasis = normalize(firstxbasis);
477                         else
478                                 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]]));
479
480                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
481
482                                 float3 xbasis = firstxbasis;
483                                 float3 v1;
484                                 float3 v2;
485
486                                 if(curvekey == CData->curve_firstkey[curve]) {
487                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
488                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
489                                 }
490                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
491                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
492                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
493                                 }
494                                 else {
495                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
496                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
497                                 }
498
499                                 xbasis = cross(v1,v2);
500
501                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
502                                         firstxbasis = normalize(xbasis);
503                                         break;
504                                 }
505                         }
506
507                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
508
509                                 int subv = 1;
510                                 float3 v1;
511                                 float3 v2;
512                                 float3 xbasis;
513
514                                 if(curvekey == CData->curve_firstkey[curve]) {
515                                         subv = 0;
516                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
517                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
518                                 }
519                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
520                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
521                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
522                                 }
523                                 else {
524                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
525                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
526                                 }
527
528                                 xbasis = cross(v1,v2);
529
530                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
531                                         xbasis = normalize(xbasis);
532                                         firstxbasis = xbasis;
533                                 }
534                                 else
535                                         xbasis = firstxbasis;
536
537                                 for (; subv <= segments; subv++) {
538
539                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
540                                         float time = 0.0f;
541
542                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
543                                                 ickey_loc = CData->curvekey_co[curvekey];
544                                         else
545                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
546
547                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
548
549                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
550                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
551
552                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
553                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
554
555                                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
556                                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
557                                         mesh->verts.push_back(ickey_loc_shfl);
558                                         mesh->verts.push_back(ickey_loc_shfr);
559                                         if(subv!=0) {
560                                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
561                                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
562                                         }
563                                         vertexindex += 2;
564                                 }
565                         }
566                 }
567         }
568
569         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
570         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
571         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
572         mesh->add_face_normals();
573         mesh->add_vertex_normals();
574         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
575         /* texture coords still needed */
576
577 }
578
579 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments)
580 {
581         int vertexno = mesh->verts.size();
582         int vertexindex = vertexno;
583
584         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
585                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
586
587                         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]]);
588                         if(len_squared(firstxbasis)!= 0.0f)
589                                 firstxbasis = normalize(firstxbasis);
590                         else
591                                 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]]));
592
593
594                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
595
596                                 float3 xbasis = firstxbasis;
597                                 float3 v1;
598                                 float3 v2;
599
600                                 if(curvekey == CData->curve_firstkey[curve]) {
601                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
602                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
603                                 }
604                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
605                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
606                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
607                                 }
608                                 else {
609                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
610                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
611                                 }
612
613                                 xbasis = cross(v1,v2);
614
615                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
616                                         firstxbasis = normalize(xbasis);
617                                         break;
618                                 }
619                         }
620
621                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
622
623                                 int subv = 1;
624                                 float3 xbasis;
625                                 float3 ybasis;
626                                 float3 v1;
627                                 float3 v2;
628
629                                 if(curvekey == CData->curve_firstkey[curve]) {
630                                         subv = 0;
631                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
632                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
633                                 }
634                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
635                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
636                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
637                                 }
638                                 else {
639                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
640                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
641                                 }
642
643                                 xbasis = cross(v1,v2);
644
645                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
646                                         xbasis = normalize(xbasis);
647                                         firstxbasis = xbasis;
648                                 }
649                                 else
650                                         xbasis = firstxbasis;
651
652                                 ybasis = normalize(cross(xbasis,v2));
653
654                                 for (; subv <= segments; subv++) {
655
656                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
657                                         float time = 0.0f;
658
659                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
660                                                 ickey_loc = CData->curvekey_co[curvekey];
661                                         else
662                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
663
664                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
665
666                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
667                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
668
669                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
670                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
671
672                                         float angle = M_2PI_F / (float)resolution;
673                                         for(int section = 0 ; section < resolution; section++) {
674                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
675                                                 mesh->verts.push_back(ickey_loc_shf);
676                                         }
677
678                                         if(subv!=0) {
679                                                 for(int section = 0 ; section < resolution - 1; section++) {
680                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth);
681                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth);
682                                                 }
683                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth);
684                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth);
685                                         }
686                                         vertexindex += resolution;
687                                 }
688                         }
689                 }
690         }
691
692         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
693         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
694         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
695         mesh->add_face_normals();
696         mesh->add_vertex_normals();
697         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
698
699         /* texture coords still needed */
700 }
701
702 static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments)
703 {
704         int num_keys = 0;
705         int num_curves = 0;
706
707         if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
708                 return;
709
710         Attribute *attr_intercept = NULL;
711         
712         if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
713                 attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
714
715         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
716
717                 if(CData->psys_curvenum[sys] == 0)
718                         continue;
719
720                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
721
722                         if(CData->curve_keynum[curve] <= 1)
723                                 continue;
724
725                         size_t num_curve_keys = 0;
726
727                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
728
729                                 int subv = 1;
730                                 if(curvekey == CData->curve_firstkey[curve])
731                                         subv = 0;
732
733                                 for (; subv <= segments; subv++) {
734
735                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
736                                         float time = 0.0f;
737
738                                         if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
739                                                 ickey_loc = CData->curvekey_co[curvekey];
740                                         else
741                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
742
743                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
744
745                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
746                                                 radius =0.0f;
747
748                                         mesh->add_curve_key(ickey_loc, radius);
749                                         if(attr_intercept)
750                                                 attr_intercept->add(time);
751
752                                         num_curve_keys++;
753                                 }
754                         }
755
756                         mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
757                         num_keys += num_curve_keys;
758                         num_curves++;
759                 }
760         }
761
762         /* check allocation*/
763         if((mesh->curve_keys.size() !=  num_keys) || (mesh->curves.size() !=  num_curves)) {
764                 /* allocation failed -> clear data */
765                 mesh->curve_keys.clear();
766                 mesh->curves.clear();
767                 mesh->curve_attributes.clear();
768         }
769 }
770
771 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments, int vert_offset, int resol, float3 *uvdata)
772 {
773         if(uvdata == NULL)
774                 return;
775
776         float time = 0.0f;
777         float prevtime = 0.0f;
778
779         int vertexindex = vert_offset;
780
781         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
782                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
783
784                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
785
786                                 int subv = 1;
787
788                                 if (curvekey == CData->curve_firstkey[curve])
789                                         subv = 0;
790                                 
791                                 for (; subv <= segments; subv++) {
792
793                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
794
795                                         InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
796
797                                         if(subv!=0) {
798                                                 for(int section = 0 ; section < resol; section++) {
799                                                         uvdata[vertexindex] = CData->curve_uv[curve];
800                                                         uvdata[vertexindex].z = prevtime;
801                                                         vertexindex++;
802                                                         uvdata[vertexindex] = CData->curve_uv[curve];
803                                                         uvdata[vertexindex].z = time;
804                                                         vertexindex++;
805                                                         uvdata[vertexindex] = CData->curve_uv[curve];
806                                                         uvdata[vertexindex].z = prevtime;
807                                                         vertexindex++;
808                                                         uvdata[vertexindex] = CData->curve_uv[curve];
809                                                         uvdata[vertexindex].z = time;
810                                                         vertexindex++;
811                                                         uvdata[vertexindex] = CData->curve_uv[curve];
812                                                         uvdata[vertexindex].z = prevtime;
813                                                         vertexindex++;
814                                                         uvdata[vertexindex] = CData->curve_uv[curve];
815                                                         uvdata[vertexindex].z = time;
816                                                         vertexindex++;
817                                                 }
818                                         }
819
820                                         prevtime = time;
821                                 }
822                         }
823                 }
824         }
825
826 }
827
828 void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments, int vert_offset, int resol, float3 *fdata)
829 {
830         if(fdata == NULL)
831                 return;
832
833         float time = 0.0f;
834 //      float prevtime = 0.0f; // UNUSED
835
836         int vertexindex = vert_offset;
837
838         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
839                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
840
841                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
842
843                                 int subv = 1;
844
845                                 if (curvekey == CData->curve_firstkey[curve])
846                                         subv = 0;
847                                 
848                                 for (; subv <= segments; subv++) {
849
850                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
851
852                                         InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
853
854                                         if(subv!=0) {
855                                                 for(int section = 0 ; section < resol; section++) {
856                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
857                                                         vertexindex++;
858                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
859                                                         vertexindex++;
860                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
861                                                         vertexindex++;
862                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
863                                                         vertexindex++;
864                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
865                                                         vertexindex++;
866                                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
867                                                         vertexindex++;
868                                                 }
869                                         }
870
871                                         // prevtime = time;  // UNUSED
872                                 }
873                         }
874                 }
875         }
876
877 }
878
879 /* Hair Curve Sync */
880
881 void BlenderSync::sync_curve_settings()
882 {
883         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
884         
885         int preset = get_enum(csscene, "preset");
886
887         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
888         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
889
890         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
891         curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
892         curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
893
894         if(preset == CURVE_CUSTOM) {
895                 /*custom properties*/
896                 curve_system_manager->primitive = get_enum(csscene, "primitive");
897                 curve_system_manager->line_method = get_enum(csscene, "line_method");
898                 curve_system_manager->interpolation = get_enum(csscene, "interpolation");
899                 curve_system_manager->triangle_method = get_enum(csscene, "triangle_method");
900                 curve_system_manager->resolution = get_int(csscene, "resolution");
901                 curve_system_manager->segments = get_int(csscene, "segments");
902                 curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth");
903                 curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
904
905                 curve_system_manager->normalmix = get_float(csscene, "normalmix");
906                 curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio");
907
908                 curve_system_manager->use_parents = get_boolean(csscene, "use_parents");
909                 curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing");
910                 curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing");
911                 curve_system_manager->use_joined = get_boolean(csscene, "use_joined");
912                 curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal");
913                 curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry");
914                 curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction");
915         }
916         else {
917                 curve_system_manager->primitive = CURVE_LINE_SEGMENTS;
918                 curve_system_manager->interpolation = CURVE_CARDINAL;
919                 curve_system_manager->normalmix = 1.0f;
920                 curve_system_manager->encasing_ratio = 1.01f;
921                 curve_system_manager->use_parents = false;
922                 curve_system_manager->segments = 1;
923                 curve_system_manager->use_joined = false;
924
925                 switch(preset) {
926                         case CURVE_FAST_PLANES:
927                                 /*camera facing planes*/
928                                 curve_system_manager->primitive = CURVE_TRIANGLES;
929                                 curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
930                                 curve_system_manager->use_smooth = true;
931                                 curve_system_manager->resolution = 1;
932                                 break;
933                         case CURVE_TANGENT_SHADING:
934                                 /*tangent shading*/
935                                 curve_system_manager->line_method = CURVE_UNCORRECTED;
936                                 curve_system_manager->use_encasing = true;
937                                 curve_system_manager->use_backfacing = false;
938                                 curve_system_manager->use_tangent_normal = true;
939                                 curve_system_manager->use_tangent_normal_geometry = true;
940                                 curve_system_manager->use_tangent_normal_correction = false;
941                                 break;
942                         case CURVE_TRUE_NORMAL:
943                                 /*True Normal*/
944                                 curve_system_manager->line_method = CURVE_CORRECTED;
945                                 curve_system_manager->use_encasing = true;
946                                 curve_system_manager->use_backfacing = false;
947                                 curve_system_manager->use_tangent_normal = false;
948                                 curve_system_manager->use_tangent_normal_geometry = false;
949                                 curve_system_manager->use_tangent_normal_correction = false;
950                                 break;
951                         case CURVE_ACCURATE_PRESET:
952                                 /*Accurate*/
953                                 curve_system_manager->line_method = CURVE_ACCURATE;
954                                 curve_system_manager->use_encasing = false;
955                                 curve_system_manager->use_backfacing = true;
956                                 curve_system_manager->use_tangent_normal = false;
957                                 curve_system_manager->use_tangent_normal_geometry = false;
958                                 curve_system_manager->use_tangent_normal_correction = false;
959                                 break;
960                         case CURVE_SMOOTH_CURVES:
961                                 /*Cardinal curves preset*/
962                                 curve_system_manager->primitive = CURVE_SEGMENTS;
963                                 curve_system_manager->use_backfacing = true;
964                                 curve_system_manager->subdivisions = 4;
965                                 break;
966                         case CURVE_SMOOTH_RIBBONS:
967                                 /*Cardinal ribbons preset*/
968                                 curve_system_manager->primitive = CURVE_RIBBONS;
969                                 curve_system_manager->use_backfacing = false;
970                                 curve_system_manager->subdivisions = 4;
971                                 break;
972                 }
973                 
974         }
975
976         if(curve_system_manager->modified_mesh(prev_curve_system_manager))
977         {
978                 BL::BlendData::objects_iterator b_ob;
979
980                 for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
981                         if(object_is_mesh(*b_ob)) {
982                                 BL::Object::particle_systems_iterator b_psys;
983                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
984                                         if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) {
985                                                 BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
986                                                 mesh_map.set_recalc(key);
987                                                 object_map.set_recalc(*b_ob);
988                                         }
989                                 }
990                         }
991                 }
992         }
993
994         if(curve_system_manager->modified(prev_curve_system_manager))
995                 curve_system_manager->tag_update(scene);
996
997 }
998
999 void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated)
1000 {
1001         /* Clear stored curve data */
1002         mesh->curve_keys.clear();
1003         mesh->curves.clear();
1004         mesh->curve_attributes.clear();
1005
1006         /* obtain general settings */
1007         bool use_curves = scene->curve_system_manager->use_curves;
1008
1009         if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) {
1010                 mesh->compute_bounds();
1011                 return;
1012         }
1013
1014         int primitive = scene->curve_system_manager->primitive;
1015         int interpolation = scene->curve_system_manager->interpolation;
1016         int triangle_method = scene->curve_system_manager->triangle_method;
1017         int resolution = scene->curve_system_manager->resolution;
1018         int segments = scene->curve_system_manager->segments;
1019         bool use_smooth = scene->curve_system_manager->use_smooth;
1020         bool use_parents = scene->curve_system_manager->use_parents;
1021         bool export_tgs = scene->curve_system_manager->use_joined;
1022         size_t vert_num = mesh->verts.size();
1023         size_t tri_num = mesh->triangles.size();
1024         int used_res = 1;
1025
1026         /* extract particle hair data - should be combined with connecting to mesh later*/
1027
1028         ParticleCurveData CData;
1029
1030         if(!preview)
1031                 set_resolution(mesh, &b_mesh, &b_ob, &b_scene, true);
1032
1033         ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview);
1034
1035         /* obtain camera parameters */
1036         BL::Object b_CamOb = b_scene.camera();
1037         float3 RotCam = make_float3(0.0f, 0.0f, 0.0f);
1038         if(b_CamOb) {
1039                 Transform ctfm = get_transform(b_CamOb.matrix_world());
1040                 Transform tfm = get_transform(b_ob.matrix_world());
1041                 Transform itfm = transform_quick_inverse(tfm);
1042                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
1043         }
1044
1045         /* add hair geometry to mesh */
1046         if(primitive == CURVE_TRIANGLES){
1047                 if(triangle_method == CURVE_CAMERA_TRIANGLES)
1048                         ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
1049                 else if(triangle_method == CURVE_RIBBON_TRIANGLES)
1050                         ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
1051                 else {
1052                         ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments);
1053                         used_res = resolution;
1054                 }
1055         }
1056         else {
1057                 ExportCurveSegments(scene, mesh, &CData, interpolation, segments);
1058                 int ckey_num = mesh->curve_keys.size();
1059
1060                 /*export tangents or curve data? - not functional yet*/
1061                 if(export_tgs && ckey_num > 1) {
1062                         Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT);
1063                         float3 *data_tangent = attr_tangent->data_float3();
1064                         
1065                         for(int ck = 0; ck < ckey_num; ck++) {
1066                                 float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) -
1067                                         normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co));
1068                                 
1069                                 data_tangent[ck] = tg;
1070                         }
1071                 }
1072         }
1073
1074
1075         /* generated coordinates from first key. we should ideally get this from
1076          * blender to handle deforming objects */
1077         {
1078                 if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
1079                         float3 loc, size;
1080                         mesh_texture_space(b_mesh, loc, size);
1081
1082                         if(primitive == CURVE_TRIANGLES) {
1083                                 Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
1084                                 float3 *generated = attr_generated->data_float3();
1085
1086                                 for(size_t i = vert_num; i < mesh->verts.size(); i++)
1087                                         generated[i] = mesh->verts[i]*size - loc;
1088                         }
1089                         else {
1090                                 Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
1091                                 float3 *generated = attr_generated->data_float3();
1092                                 size_t i = 0;
1093
1094                                 foreach(Mesh::Curve& curve, mesh->curves) {
1095                                         float3 co = mesh->curve_keys[curve.first_key].co;
1096                                         generated[i++] = co*size - loc;
1097                                 }
1098                         }
1099                 }
1100         }
1101
1102         /* create vertex color attributes */
1103         {
1104                 BL::Mesh::tessface_vertex_colors_iterator l;
1105                 int vcol_num = 0;
1106
1107                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
1108                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
1109                                 continue;
1110
1111                         ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview, vcol_num);
1112
1113                         if(primitive == CURVE_TRIANGLES) {
1114
1115                                 Attribute *attr_vcol = mesh->attributes.add(
1116                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
1117
1118                                 float3 *fdata = attr_vcol->data_float3();
1119
1120                                 ExportCurveTriangleVcol(mesh, &CData, interpolation, segments, tri_num * 3, used_res, fdata);
1121                         }
1122                         else {
1123                                 Attribute *attr_vcol = mesh->curve_attributes.add(
1124                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
1125
1126                                 float3 *fdata = attr_vcol->data_float3();
1127
1128                                 if(fdata) {
1129                                         for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
1130                                                 fdata[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
1131                                 }
1132                         }
1133                 }
1134         }
1135
1136         /* create UV attributes */
1137         {
1138                 BL::Mesh::tessface_uv_textures_iterator l;
1139                 int uv_num = 0;
1140
1141                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
1142                         bool active_render = l->active_render();
1143                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
1144                         ustring name = ustring(l->name().c_str());
1145
1146                         /* UV map */
1147                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
1148                                 Attribute *attr_uv;
1149
1150                                 ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview, uv_num);
1151
1152                                 if(primitive == CURVE_TRIANGLES) {
1153                                         if(active_render)
1154                                                 attr_uv = mesh->attributes.add(std, name);
1155                                         else
1156                                                 attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
1157
1158                                         float3 *uv = attr_uv->data_float3();
1159
1160                                         ExportCurveTriangleUV(mesh, &CData, interpolation, segments, tri_num * 3, used_res, uv);
1161                                 }
1162                                 else {
1163                                         if(active_render)
1164                                                 attr_uv = mesh->curve_attributes.add(std, name);
1165                                         else
1166                                                 attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
1167
1168                                         float3 *uv = attr_uv->data_float3();
1169
1170                                         if(uv) {
1171                                                 for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
1172                                                         uv[curve] = CData.curve_uv[curve];
1173                                         }
1174                                 }
1175                         }
1176                 }
1177         }
1178
1179         if(!preview)
1180                 set_resolution(mesh, &b_mesh, &b_ob, &b_scene, false);
1181
1182         mesh->compute_bounds();
1183 }
1184
1185
1186 CCL_NAMESPACE_END
1187