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