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