Cycles Hair: refactoring to store curves with the index of the first key and the
[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 "mesh.h"
20 #include "object.h"
21 #include "scene.h"
22 #include "curves.h"
23
24 #include "blender_sync.h"
25 #include "blender_util.h"
26
27 #include "subd_mesh.h"
28 #include "subd_patch.h"
29 #include "subd_split.h"
30
31 #include "util_foreach.h"
32
33 #include "DNA_modifier_types.h"
34 #include "DNA_particle_types.h"
35 #include "DNA_meshdata_types.h"
36
37 CCL_NAMESPACE_BEGIN
38
39 /* Utilities */
40
41 /* Hair curve functions */
42
43 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
44 void interp_weights(float t, float data[4], int type);
45 float shaperadius(float shape, float root, float tip, float time);
46 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
47 bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData);
48 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents);
49 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam);
50 void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments);
51 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments);
52 void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments);
53
54 ParticleCurveData::ParticleCurveData()
55 {
56 }
57
58 ParticleCurveData::~ParticleCurveData()
59 {
60         psys_firstcurve.clear();
61         psys_curvenum.clear();
62         psys_shader.clear();
63         psys_rootradius.clear();
64         psys_tipradius.clear();
65         psys_shape.clear();
66
67         curve_firstkey.clear();
68         curve_keynum.clear();
69         curve_length.clear();
70         curve_uv.clear();
71
72         curvekey_co.clear();
73         curvekey_time.clear();
74 }
75
76 void interp_weights(float t, float data[4], int type)
77 {
78         float t2, t3, fc;
79
80         if(type == CURVE_LINEAR) {
81                 data[0] =          0.0f;
82                 data[1] = -t     + 1.0f;
83                 data[2] =  t;
84                 data[3] =          0.0f;
85         }
86         else if(type == CURVE_CARDINAL) {
87                 t2 = t * t;
88                 t3 = t2 * t;
89                 fc = 0.71f;
90
91                 data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
92                 data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
93                 data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
94                 data[3] =  fc          * t3  - fc * t2;
95         }
96         else if(type == CURVE_BSPLINE) {
97                 t2 = t * t;
98                 t3 = t2 * t;
99
100                 data[0] = -0.16666666f * t3  + 0.5f * t2   - 0.5f * t    + 0.16666666f;
101                 data[1] =  0.5f        * t3  - t2                        + 0.66666666f;
102                 data[2] = -0.5f        * t3  + 0.5f * t2   + 0.5f * t    + 0.16666666f;
103                 data[3] =  0.16666666f * t3;
104         }
105 }
106
107 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
108 {
109         p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
110         p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
111         p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
112 }
113
114 float shaperadius(float shape, float root, float tip, float time)
115 {
116         float radius = 1.0f - time;
117         if(shape != 0.0f) {
118                 if(shape < 0.0f)
119                         radius = (float)pow(1.0f - time, 1.f + shape);
120                 else
121                         radius = (float)pow(1.0f - time, 1.f / (1.f - shape));
122         }
123         return (radius * (root - tip)) + tip;
124 }
125
126 /* curve functions */
127
128 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation)
129 {
130         float3 ckey_loc1 = CData->curvekey_co[key];
131         float3 ckey_loc2 = ckey_loc1;
132         float3 ckey_loc3 = CData->curvekey_co[key+1];
133         float3 ckey_loc4 = ckey_loc3;
134
135         if(key > CData->curve_firstkey[curve])
136                 ckey_loc1 = CData->curvekey_co[key - 1];
137
138         if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
139                 ckey_loc4 = CData->curvekey_co[key + 2];
140
141
142         float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
143         float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
144
145         float dfra = (time2 - time1) / (float)segno;
146
147         if(time)
148                 *time = (dfra * seg) + time1;
149
150         float t[4];
151
152         interp_weights((float)seg / (float)segno, t, interpolation);
153
154         if(keyloc)
155                 curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
156 }
157
158 bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData)
159 {
160
161         int curvenum = 0;
162         int keyno = 0;
163
164         if(!(mesh && b_mesh && b_ob && CData))
165                 return false;
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) && (b_mod->show_viewport()) && (b_mod->show_render())) {
170
171                         BL::ParticleSystemModifier psmd(b_mod->ptr);
172
173                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
174
175                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
176
177                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
178
179                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
180                                 int shader = mesh->used_shaders[mi];
181
182                                 int totcurves = b_psys.particles.length();
183
184                                 if(totcurves == 0)
185                                         continue;
186
187                                 PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
188
189                                 CData->psys_firstcurve.push_back(curvenum);
190                                 CData->psys_curvenum.push_back(totcurves);
191                                 CData->psys_shader.push_back(shader);
192
193                                 float radius = b_psys.settings().particle_size() * 0.5f;
194         
195                                 CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
196                                 CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
197                                 CData->psys_shape.push_back(get_float(cpsys, "shape"));
198                                 CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
199
200                                 BL::ParticleSystem::particles_iterator b_pa;
201                                 for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) {
202                                         CData->curve_firstkey.push_back(keyno);
203
204                                         int keylength = b_pa->hair_keys.length();
205                                         CData->curve_keynum.push_back(keylength);
206
207                                         float curve_length = 0.0f;
208                                         float3 pcKey;
209                                         int step_no = 0;
210                                         BL::Particle::hair_keys_iterator b_cKey;
211                                         for(b_pa->hair_keys.begin(b_cKey); b_cKey != b_pa->hair_keys.end(); ++b_cKey) {
212                                                 float nco[3];
213                                                 b_cKey->co_object( *b_ob, psmd, *b_pa, nco);
214                                                 float3 cKey = make_float3(nco[0],nco[1],nco[2]);
215                                                 if(step_no > 0)
216                                                         curve_length += len(cKey - pcKey);
217                                                 CData->curvekey_co.push_back(cKey);
218                                                 CData->curvekey_time.push_back(curve_length);
219                                                 pcKey = cKey;
220                                                 keyno++;
221                                                 step_no++;
222                                         }
223
224                                         CData->curve_length.push_back(curve_length);
225                                         /*add uvs*/
226                                         BL::Mesh::tessface_uv_textures_iterator l;
227                                         b_mesh->tessface_uv_textures.begin(l);
228
229                                         float3 uv = make_float3(0.0f, 0.0f, 0.0f);
230                                         if(b_mesh->tessface_uv_textures.length())
231                                                 b_pa->uv_on_emitter(psmd,&uv.x);
232                                         CData->curve_uv.push_back(uv);
233
234                                         curvenum++;
235
236                                 }
237                         }
238                 }
239         }
240
241         return true;
242
243 }
244
245 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
246 {
247
248         int curvenum = 0;
249         int keyno = 0;
250
251         if(!(mesh && b_mesh && b_ob && CData))
252                 return false;
253
254         Transform tfm = get_transform(b_ob->matrix_world());
255         Transform itfm = transform_quick_inverse(tfm);
256
257         BL::Object::modifiers_iterator b_mod;
258         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
259                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
260                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
261
262                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
263
264                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
265
266                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
267
268                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
269                                 int shader = mesh->used_shaders[mi];
270                                 int draw_step = b_psys.settings().draw_step();
271                                 int ren_step = (int)pow((float)2.0f,(float)draw_step);
272                                 /*b_psys.settings().render_step(draw_step);*/
273
274                                 int totparts = b_psys.particles.length();
275                                 int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100;
276                                 int totcurves = totchild;
277                                 
278                                 if(use_parents || b_psys.settings().child_type() == 0)
279                                         totcurves += totparts;
280
281                                 if(totcurves == 0)
282                                         continue;
283
284                                 PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
285
286                                 CData->psys_firstcurve.push_back(curvenum);
287                                 CData->psys_curvenum.push_back(totcurves);
288                                 CData->psys_shader.push_back(shader);
289
290                                 float radius = b_psys.settings().particle_size() * 0.5f;
291         
292                                 CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
293                                 CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
294                                 CData->psys_shape.push_back(get_float(cpsys, "shape"));
295                                 CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
296
297                                 int pa_no = 0;
298                                 if(!use_parents && !(b_psys.settings().child_type() == 0))
299                                         pa_no = totparts;
300
301                                 BL::ParticleSystem::particles_iterator b_pa;
302                                 b_psys.particles.begin(b_pa);
303                                 for(; pa_no < totparts+totchild; pa_no++) {
304
305                                         CData->curve_firstkey.push_back(keyno);
306                                         CData->curve_keynum.push_back(ren_step+1);
307                                         
308                                         float curve_length = 0.0f;
309                                         float3 pcKey;
310                                         for(int step_no = 0; step_no <= ren_step; step_no++) {
311                                                 float nco[3];
312                                                 b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco);
313                                                 float3 cKey = make_float3(nco[0],nco[1],nco[2]);
314                                                 cKey = transform_point(&itfm, cKey);
315                                                 if(step_no > 0)
316                                                         curve_length += len(cKey - pcKey);
317                                                 CData->curvekey_co.push_back(cKey);
318                                                 CData->curvekey_time.push_back(curve_length);
319                                                 pcKey = cKey;
320                                                 keyno++;
321                                         }
322                                         CData->curve_length.push_back(curve_length);
323
324                                         /*add uvs*/
325                                         BL::Mesh::tessface_uv_textures_iterator l;
326                                         b_mesh->tessface_uv_textures.begin(l);
327
328                                         float3 uv = make_float3(0.0f, 0.0f, 0.0f);
329                                         if(b_mesh->tessface_uv_textures.length())
330                                                 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x);
331                                         CData->curve_uv.push_back(uv);
332
333                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
334                                                 ++b_pa;
335
336                                         curvenum++;
337
338                                 }
339                         }
340
341                 }
342         }
343
344         return true;
345
346 }
347
348 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam)
349 {
350         int vertexno = mesh->verts.size();
351         int vertexindex = vertexno;
352
353         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
354                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
355
356                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
357
358                                 int subv = 1;
359                                 float3 xbasis;
360
361                                 float3 v1;
362
363                                 if(curvekey == CData->curve_firstkey[curve]) {
364                                         subv = 0;
365                                         v1 = CData->curvekey_co[curvekey+2] - CData->curvekey_co[curvekey];
366                                 }
367                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
368                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 2];
369                                 else 
370                                         v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
371
372
373                                 for (; subv <= segments; subv++) {
374
375                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
376                                         float time = 0.0f;
377
378                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
379                                                 ickey_loc = CData->curvekey_co[curvekey];
380                                         else
381                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
382
383                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
384
385                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
386                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
387
388                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
389                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
390
391                                         xbasis = normalize(cross(v1,RotCam - ickey_loc));
392                                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
393                                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
394                                         mesh->verts.push_back(ickey_loc_shfl);
395                                         mesh->verts.push_back(ickey_loc_shfr);
396                                         if(subv!=0) {
397                                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
398                                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
399                                         }
400                                         vertexindex += 2;
401                                 }
402                         }
403                 }
404         }
405
406         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
407         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
408         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
409         mesh->add_face_normals();
410         mesh->add_vertex_normals();
411         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
412
413         /* texture coords still needed */
414
415 }
416
417 void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments)
418 {
419         int vertexno = mesh->verts.size();
420         int vertexindex = vertexno;
421
422         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
423                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
424
425                         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]]);
426                         if(len_squared(firstxbasis)!= 0.0f)
427                                 firstxbasis = normalize(firstxbasis);
428                         else
429                                 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]]));
430
431                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
432
433                                 float3 xbasis = firstxbasis;
434                                 float3 v1;
435                                 float3 v2;
436
437                                 if(curvekey == CData->curve_firstkey[curve]) {
438                                         v1 = CData->curvekey_co[curvekey+2] - CData->curvekey_co[curvekey+1];
439                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
440                                 }
441                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) {
442                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
443                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2];
444                                 }
445                                 else {
446                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
447                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
448                                 }
449
450                                 xbasis = cross(v1,v2);
451
452                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
453                                         firstxbasis = normalize(xbasis);
454                                         break;
455                                 }
456                         }
457
458                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
459
460                                 int subv = 1;
461                                 float3 v1;
462                                 float3 v2;
463                                 float3 xbasis;
464
465                                 if(curvekey == CData->curve_firstkey[curve]) {
466                                         subv = 0;
467                                         v1 = CData->curvekey_co[curvekey+2] - CData->curvekey_co[curvekey+1];
468                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
469                                 }
470                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) {
471                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
472                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2];
473                                 }
474                                 else {
475                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
476                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
477                                 }
478
479                                 xbasis = cross(v1,v2);
480
481                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
482                                         xbasis = normalize(xbasis);
483                                         firstxbasis = xbasis;
484                                 }
485                                 else
486                                         xbasis = firstxbasis;
487
488                                 for (; subv <= segments; subv++) {
489
490                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
491                                         float time = 0.0f;
492
493                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
494                                                 ickey_loc = CData->curvekey_co[curvekey];
495                                         else
496                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
497
498                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
499
500                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
501                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
502
503                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
504                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
505
506                                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
507                                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
508                                         mesh->verts.push_back(ickey_loc_shfl);
509                                         mesh->verts.push_back(ickey_loc_shfr);
510                                         if(subv!=0) {
511                                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
512                                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
513                                         }
514                                         vertexindex += 2;
515                                 }
516                         }
517                 }
518         }
519
520         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
521         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
522         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
523         mesh->add_face_normals();
524         mesh->add_vertex_normals();
525         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
526         /* texture coords still needed */
527
528 }
529
530 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments)
531 {
532         int vertexno = mesh->verts.size();
533         int vertexindex = vertexno;
534
535         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
536                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
537
538                         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]]);
539                         if(len_squared(firstxbasis)!= 0.0f)
540                                 firstxbasis = normalize(firstxbasis);
541                         else
542                                 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]]));
543
544
545                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
546
547                                 float3 xbasis = firstxbasis;
548                                 float3 v1;
549                                 float3 v2;
550
551                                 if(curvekey == CData->curve_firstkey[curve]) {
552                                         v1 = CData->curvekey_co[curvekey+2] - CData->curvekey_co[curvekey+1];
553                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
554                                 }
555                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) {
556                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
557                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2];
558                                 }
559                                 else {
560                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
561                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
562                                 }
563
564                                 xbasis = cross(v1,v2);
565
566                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
567                                         firstxbasis = normalize(xbasis);
568                                         break;
569                                 }
570                         }
571
572                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
573
574                                 int subv = 1;
575                                 float3 xbasis;
576                                 float3 ybasis;
577                                 float3 v1;
578                                 float3 v2;
579
580                                 if(curvekey == CData->curve_firstkey[curve]) {
581                                         subv = 0;
582                                         v1 = CData->curvekey_co[curvekey+2] - CData->curvekey_co[curvekey+1];
583                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
584                                 }
585                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) {
586                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
587                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[curvekey-2];
588                                 }
589                                 else {
590                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
591                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
592                                 }
593
594                                 xbasis = cross(v1,v2);
595
596                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
597                                         xbasis = normalize(xbasis);
598                                         firstxbasis = xbasis;
599                                 }
600                                 else
601                                         xbasis = firstxbasis;
602
603                                 ybasis = normalize(cross(xbasis,v2));
604
605                                 for (; subv <= segments; subv++) {
606
607                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
608                                         float time = 0.0f;
609
610                                         if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
611                                                 ickey_loc = CData->curvekey_co[curvekey];
612                                         else
613                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
614
615                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
616
617                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
618                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
619
620                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == segments))
621                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
622
623                                         float angle = 2 * M_PI_F / (float)resolution;
624                                         for(int section = 0 ; section < resolution; section++) {
625                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
626                                                 mesh->verts.push_back(ickey_loc_shf);
627                                         }
628
629                                         if(subv!=0) {
630                                                 for(int section = 0 ; section < resolution - 1; section++) {
631                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth);
632                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth);
633                                                 }
634                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth);
635                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth);
636                                         }
637                                         vertexindex += resolution;
638                                 }
639                         }
640                 }
641         }
642
643         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
644         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
645         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
646         mesh->add_face_normals();
647         mesh->add_vertex_normals();
648         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
649
650         /* texture coords still needed */
651 }
652
653 void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments)
654 {
655         int num_keys = 0;
656         int num_curves = 0;
657
658         if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
659                 return;
660
661         Attribute *attr_uv = mesh->curve_attributes.add(ATTR_STD_UV);
662         Attribute *attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
663
664         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
665
666                 if(CData->psys_curvenum[sys] == 0)
667                         continue;
668
669                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
670
671                         if(CData->curve_keynum[curve] <= 1)
672                                 continue;
673
674                         size_t num_curve_keys = 0;
675
676                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
677
678                                 int subv = 1;
679                                 if(curvekey == CData->curve_firstkey[curve])
680                                         subv = 0;
681
682                                 for (; subv <= segments; subv++) {
683
684                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
685                                         float time = 0.0f;
686
687                                         if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
688                                                 ickey_loc = CData->curvekey_co[curvekey];
689                                         else
690                                                 InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
691
692                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
693
694                                         if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
695                                                 radius =0.0f;
696
697                                         mesh->add_curve_key(ickey_loc, radius);
698                                         attr_intercept->add(time);
699
700                                         num_curve_keys++;
701                                 }
702                         }
703
704                         mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
705                         attr_uv->add(CData->curve_uv[curve]);
706
707                         num_keys += num_curve_keys;
708                         num_curves++;
709                 }
710         }
711
712         /* check allocation*/
713         if((mesh->curve_keys.size() !=  num_keys) || (mesh->curves.size() !=  num_curves)) {
714                 /* allocation failed -> clear data */
715                 mesh->curve_keys.clear();
716                 mesh->curves.clear();
717                 mesh->curve_attributes.clear();
718         }
719 }
720
721 /* Hair Curve Sync */
722
723 void BlenderSync::sync_curve_settings()
724 {
725         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
726         
727         int preset = get_enum(csscene, "preset");
728
729         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
730         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
731
732         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
733
734         if(preset == CURVE_CUSTOM) {
735                 /*custom properties*/
736                 curve_system_manager->primitive = get_enum(csscene, "primitive");
737                 curve_system_manager->line_method = get_enum(csscene, "line_method");
738                 curve_system_manager->interpolation = get_enum(csscene, "interpolation");
739                 curve_system_manager->triangle_method = get_enum(csscene, "triangle_method");
740                 curve_system_manager->resolution = get_int(csscene, "resolution");
741                 curve_system_manager->segments = get_int(csscene, "segments");
742                 curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth");
743
744                 curve_system_manager->normalmix = get_float(csscene, "normalmix");
745                 curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio");
746
747                 curve_system_manager->use_cache = get_boolean(csscene, "use_cache");
748                 curve_system_manager->use_parents = get_boolean(csscene, "use_parents");
749                 curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing");
750                 curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing");
751                 curve_system_manager->use_joined = get_boolean(csscene, "use_joined");
752                 curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal");
753                 curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry");
754                 curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction");
755         }
756         else {
757                 curve_system_manager->primitive = CURVE_LINE_SEGMENTS;
758                 curve_system_manager->interpolation = CURVE_CARDINAL;
759                 curve_system_manager->normalmix = 1.0f;
760                 curve_system_manager->encasing_ratio = 1.01f;
761                 curve_system_manager->use_cache = true;
762                 curve_system_manager->use_parents = false;
763                 curve_system_manager->segments = 1;
764                 curve_system_manager->use_joined = false;
765
766                 switch(preset) {
767                         case CURVE_TANGENT_SHADING:
768                                 /*tangent shading*/
769                                 curve_system_manager->line_method = CURVE_UNCORRECTED;
770                                 curve_system_manager->use_encasing = true;
771                                 curve_system_manager->use_backfacing = false;
772                                 curve_system_manager->use_tangent_normal = true;
773                                 curve_system_manager->use_tangent_normal_geometry = true;
774                                 curve_system_manager->use_tangent_normal_correction = false;
775                                 break;
776                         case CURVE_TRUE_NORMAL:
777                                 /*True Normal*/
778                                 curve_system_manager->line_method = CURVE_CORRECTED;
779                                 curve_system_manager->use_encasing = true;
780                                 curve_system_manager->use_backfacing = false;
781                                 curve_system_manager->use_tangent_normal = false;
782                                 curve_system_manager->use_tangent_normal_geometry = false;
783                                 curve_system_manager->use_tangent_normal_correction = false;
784                                 break;
785                         case CURVE_ACCURATE_PRESET:
786                                 /*Accurate*/
787                                 curve_system_manager->line_method = CURVE_ACCURATE;
788                                 curve_system_manager->use_encasing = false;
789                                 curve_system_manager->use_backfacing = true;
790                                 curve_system_manager->use_tangent_normal = false;
791                                 curve_system_manager->use_tangent_normal_geometry = false;
792                                 curve_system_manager->use_tangent_normal_correction = false;
793                                 break;
794                 }
795                 
796         }
797
798         if(curve_system_manager->modified_mesh(prev_curve_system_manager))
799         {
800                 BL::BlendData::objects_iterator b_ob;
801
802                 for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
803                         if(object_is_mesh(*b_ob)) {
804                                 BL::Object::particle_systems_iterator b_psys;
805                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
806                                         if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) {
807                                                 BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
808                                                 mesh_map.set_recalc(key);
809                                                 object_map.set_recalc(*b_ob);
810                                         }
811                                 }
812                         }
813                 }
814         }
815
816         if(curve_system_manager->modified(prev_curve_system_manager))
817                 curve_system_manager->tag_update(scene);
818
819 }
820
821 void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated)
822 {
823         /* Clear stored curve data */
824         mesh->curve_keys.clear();
825         mesh->curves.clear();
826         mesh->curve_attributes.clear();
827
828         /* obtain general settings */
829         bool use_curves = scene->curve_system_manager->use_curves;
830
831         if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) {
832                 mesh->compute_bounds();
833                 return;
834         }
835
836         int primitive = scene->curve_system_manager->primitive;
837         int interpolation = scene->curve_system_manager->interpolation;
838         int triangle_method = scene->curve_system_manager->triangle_method;
839         int resolution = scene->curve_system_manager->resolution;
840         int segments = scene->curve_system_manager->segments;
841         bool use_smooth = scene->curve_system_manager->use_smooth;
842         bool use_cache = scene->curve_system_manager->use_cache;
843         bool use_parents = scene->curve_system_manager->use_parents;
844         bool export_tgs = scene->curve_system_manager->use_joined;
845
846         /* extract particle hair data - should be combined with connecting to mesh later*/
847
848         ParticleCurveData CData;
849
850         if(use_cache)
851                 ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents);
852         else
853                 ObtainParticleData(mesh, &b_mesh, &b_ob, &CData);
854
855         /* attach strands to mesh */
856         BL::Object b_CamOb = b_scene.camera();
857         float3 RotCam = make_float3(0.0f, 0.0f, 0.0f);
858         if(b_CamOb) {
859                 Transform ctfm = get_transform(b_CamOb.matrix_world());
860                 Transform tfm = get_transform(b_ob.matrix_world());
861                 Transform itfm = transform_quick_inverse(tfm);
862                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
863         }
864
865         if(primitive == CURVE_TRIANGLES){
866                 if(triangle_method == CURVE_CAMERA)
867                         ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
868                 else if(triangle_method == CURVE_RIBBONS)
869                         ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
870                 else
871                         ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments);
872         }
873         else {
874                 ExportCurveSegments(mesh, &CData, interpolation, segments);
875                 int ckey_num = mesh->curve_keys.size();
876
877                 /*export tangents or curve data? - not functional yet*/
878                 if(export_tgs && ckey_num > 1) {
879                         Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT);
880                         float3 *data_tangent = attr_tangent->data_float3();
881                         
882                         for(int ck = 0; ck < ckey_num; ck++) {
883                                 float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) -
884                                         normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co));
885                                 
886                                 data_tangent[ck] = tg;
887                         }
888                 }
889         }
890
891         mesh->compute_bounds();
892 }
893
894
895 CCL_NAMESPACE_END
896