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