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