Make strict compiler flags happy
[blender-staging.git] / intern / cycles / blender / blender_curves.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17 #include "attribute.h"
18 #include "mesh.h"
19 #include "object.h"
20 #include "scene.h"
21 #include "curves.h"
22
23 #include "blender_sync.h"
24 #include "blender_util.h"
25
26 #include "util_foreach.h"
27
28 CCL_NAMESPACE_BEGIN
29
30 /* Utilities */
31
32 /* Hair curve functions */
33
34 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
35 void interp_weights(float t, float data[4], int type);
36 float shaperadius(float shape, float root, float tip, float time);
37 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
38 bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
39 bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
40 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
41 void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
42 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotCam);
43 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
44 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
45 void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *fdata);
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         curve_vcol.clear();
65
66         curvekey_co.clear();
67         curvekey_time.clear();
68 }
69
70 void interp_weights(float t, float data[4], int type)
71 {
72         float t2, t3, fc;
73         
74         switch (type) {
75                 case CURVE_LINEAR:
76                         data[0] =          0.0f;
77                         data[1] = -t     + 1.0f;
78                         data[2] =  t;
79                         data[3] =          0.0f;
80                         break;
81                 case CURVE_CARDINAL:
82                         t2 = t * t;
83                         t3 = t2 * t;
84                         fc = 0.71f;
85
86                         data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
87                         data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
88                         data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
89                         data[3] =  fc          * t3  - fc * t2;
90                         break;
91                 case CURVE_BSPLINE:
92                         t2 = t * t;
93                         t3 = t2 * t;
94
95                         data[0] = -0.16666666f * t3  + 0.5f * t2   - 0.5f * t    + 0.16666666f;
96                         data[1] =  0.5f        * t3  - t2                        + 0.66666666f;
97                         data[2] = -0.5f        * t3  + 0.5f * t2   + 0.5f * t    + 0.16666666f;
98                         data[3] =  0.16666666f * t3;
99                         break;
100                 default:
101                         break;
102         }
103 }
104
105 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
106 {
107         p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
108         p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
109         p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
110 }
111
112 float shaperadius(float shape, float root, float tip, float time)
113 {
114         float radius = 1.0f - time;
115         
116         if(shape != 0.0f) {
117                 if(shape < 0.0f)
118                         radius = powf(radius, 1.0f + shape);
119                 else
120                         radius = powf(radius, 1.0f / (1.0f - shape));
121         }
122         return (radius * (root - tip)) + tip;
123 }
124
125 /* curve functions */
126
127 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation)
128 {
129         float3 ckey_loc1 = CData->curvekey_co[key];
130         float3 ckey_loc2 = ckey_loc1;
131         float3 ckey_loc3 = CData->curvekey_co[key+1];
132         float3 ckey_loc4 = ckey_loc3;
133
134         if(key > CData->curve_firstkey[curve])
135                 ckey_loc1 = CData->curvekey_co[key - 1];
136
137         if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
138                 ckey_loc4 = CData->curvekey_co[key + 2];
139
140
141         float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
142         float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
143
144         float dfra = (time2 - time1) / (float)segno;
145
146         if(time)
147                 *time = (dfra * seg) + time1;
148
149         float t[4];
150
151         interp_weights((float)seg / (float)segno, t, interpolation);
152
153         if(keyloc)
154                 curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
155 }
156
157 bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
158 {
159
160         int curvenum = 0;
161         int keyno = 0;
162
163         if(!(mesh && b_mesh && b_ob && CData))
164                 return false;
165
166         Transform tfm = get_transform(b_ob->matrix_world());
167         Transform itfm = transform_quick_inverse(tfm);
168
169         BL::Object::modifiers_iterator b_mod;
170         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
171                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
172                         BL::ParticleSystemModifier psmd((const PointerRNA)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                                 int draw_step = background ? b_psys.settings().render_step() : b_psys.settings().draw_step();
183                                 int ren_step = (int)powf(2.0f, (float)draw_step);
184                                 int totparts = b_psys.particles.length();
185                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
186                                 int totcurves = totchild;
187                                 
188                                 if(b_psys.settings().child_type() == 0)
189                                         totcurves += totparts;
190
191                                 if(totcurves == 0)
192                                         continue;
193
194                                 PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
195
196                                 CData->psys_firstcurve.push_back(curvenum);
197                                 CData->psys_curvenum.push_back(totcurves);
198                                 CData->psys_shader.push_back(shader);
199
200                                 float radius = get_float(cpsys, "radius_scale") * 0.5f;
201         
202                                 CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
203                                 CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
204                                 CData->psys_shape.push_back(get_float(cpsys, "shape"));
205                                 CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
206
207                                 int pa_no = 0;
208                                 if(!(b_psys.settings().child_type() == 0))
209                                         pa_no = totparts;
210
211                                 for(; pa_no < totparts+totchild; pa_no++) {
212
213                                         CData->curve_firstkey.push_back(keyno);
214                                         CData->curve_keynum.push_back(ren_step+1);
215                                         
216                                         float curve_length = 0.0f;
217                                         float3 pcKey;
218                                         for(int step_no = 0; step_no <= ren_step; step_no++) {
219                                                 float nco[3];
220                                                 b_psys.co_hair(*b_ob, pa_no, step_no, nco);
221                                                 float3 cKey = make_float3(nco[0], nco[1], nco[2]);
222                                                 cKey = transform_point(&itfm, cKey);
223                                                 if(step_no > 0)
224                                                         curve_length += len(cKey - pcKey);
225                                                 CData->curvekey_co.push_back(cKey);
226                                                 CData->curvekey_time.push_back(curve_length);
227                                                 pcKey = cKey;
228                                                 keyno++;
229                                         }
230                                         CData->curve_length.push_back(curve_length);
231
232                                         curvenum++;
233
234                                 }
235                         }
236
237                 }
238         }
239
240         return true;
241
242 }
243
244 bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
245 {
246 #if 0
247         int keyno = 0;
248 #endif
249
250         if(!(mesh && b_mesh && b_ob && CData))
251                 return false;
252
253 #if 0
254         Transform tfm = get_transform(b_ob->matrix_world());
255         Transform itfm = transform_quick_inverse(tfm);
256 #endif
257
258         CData->curve_uv.clear();
259
260         BL::Object::modifiers_iterator b_mod;
261         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
262                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
263                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
264
265                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
266
267                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
268
269                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
270 #if 0
271                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
272                                 int shader = mesh->used_shaders[mi];
273 #endif
274
275                                 int totparts = b_psys.particles.length();
276                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
277                                 int totcurves = totchild;
278                                 
279                                 if (b_psys.settings().child_type() == 0)
280                                         totcurves += totparts;
281
282                                 if (totcurves == 0)
283                                         continue;
284
285                                 int pa_no = 0;
286                                 if(!(b_psys.settings().child_type() == 0))
287                                         pa_no = totparts;
288
289                                 BL::ParticleSystem::particles_iterator b_pa;
290                                 b_psys.particles.begin(b_pa);
291                                 for(; pa_no < totparts+totchild; pa_no++) {
292
293                                         /*add uvs*/
294                                         BL::Mesh::tessface_uv_textures_iterator l;
295                                         b_mesh->tessface_uv_textures.begin(l);
296
297                                         float3 uv = make_float3(0.0f, 0.0f, 0.0f);
298                                         if(b_mesh->tessface_uv_textures.length())
299                                                 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
300                                         CData->curve_uv.push_back(uv);
301
302                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
303                                                 ++b_pa;
304
305                                 }
306                         }
307
308                 }
309         }
310
311         return true;
312
313 }
314
315 bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
316 {
317 #if 0
318         int keyno = 0;
319 #endif
320         if(!(mesh && b_mesh && b_ob && CData))
321                 return false;
322
323 #if 0
324         Transform tfm = get_transform(b_ob->matrix_world());
325         Transform itfm = transform_quick_inverse(tfm);
326 #endif
327
328         CData->curve_vcol.clear();
329
330         BL::Object::modifiers_iterator b_mod;
331         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
332                 if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
333                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
334
335                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
336
337                         BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
338
339                         if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
340 #if 0
341                                 int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
342                                 int shader = mesh->used_shaders[mi];
343 #endif
344                                 int totparts = b_psys.particles.length();
345                                 int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
346                                 int totcurves = totchild;
347                                 
348                                 if (b_psys.settings().child_type() == 0)
349                                         totcurves += totparts;
350
351                                 if (totcurves == 0)
352                                         continue;
353
354                                 int pa_no = 0;
355                                 if(!(b_psys.settings().child_type() == 0))
356                                         pa_no = totparts;
357
358                                 BL::ParticleSystem::particles_iterator b_pa;
359                                 b_psys.particles.begin(b_pa);
360                                 for(; pa_no < totparts+totchild; pa_no++) {
361
362                                         /*add uvs*/
363                                         BL::Mesh::tessface_vertex_colors_iterator l;
364                                         b_mesh->tessface_vertex_colors.begin(l);
365
366                                         float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
367                                         if(b_mesh->tessface_vertex_colors.length())
368                                                 b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
369                                         CData->curve_vcol.push_back(vcol);
370
371                                         if(pa_no < totparts && b_pa != b_psys.particles.end())
372                                                 ++b_pa;
373
374                                 }
375                         }
376
377                 }
378         }
379
380         return true;
381
382 }
383
384 static void set_resolution(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, BL::Scene *scene, bool render)
385 {
386         BL::Object::modifiers_iterator b_mod;
387         for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
388                 if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
389                         BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
390                         BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
391                         b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
392                 }
393         }
394 }
395
396 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotCam)
397 {
398         int vertexno = mesh->verts.size();
399         int vertexindex = vertexno;
400
401         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
402                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
403
404                         float3 xbasis;
405                         float3 v1;
406                         float time = 0.0f;
407                         float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]];
408                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f);
409                         v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]];
410                         xbasis = normalize(cross(RotCam - ickey_loc,v1));
411                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
412                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
413                         mesh->verts.push_back(ickey_loc_shfl);
414                         mesh->verts.push_back(ickey_loc_shfr);
415                         vertexindex += 2;
416
417                         for( int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
418                                 ickey_loc = CData->curvekey_co[curvekey];
419
420                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
421                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])];
422                                 else 
423                                         v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
424
425                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
426                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
427
428                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
429                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
430
431                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
432                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
433
434                                 xbasis = normalize(cross(RotCam - ickey_loc,v1));
435                                 float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
436                                 float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
437                                 mesh->verts.push_back(ickey_loc_shfl);
438                                 mesh->verts.push_back(ickey_loc_shfr);
439                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
440                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
441                                 vertexindex += 2;
442                         }
443                 }
444         }
445
446         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
447         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
448         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
449         mesh->add_face_normals();
450         mesh->add_vertex_normals();
451         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
452
453         /* texture coords still needed */
454 }
455
456 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution)
457 {
458         int vertexno = mesh->verts.size();
459         int vertexindex = vertexno;
460
461         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
462                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
463
464                         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]]);
465                         if(len_squared(firstxbasis)!= 0.0f)
466                                 firstxbasis = normalize(firstxbasis);
467                         else
468                                 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]]));
469
470
471                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
472
473                                 float3 xbasis = firstxbasis;
474                                 float3 v1;
475                                 float3 v2;
476
477                                 if(curvekey == CData->curve_firstkey[curve]) {
478                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
479                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
480                                 }
481                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
482                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
483                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
484                                 }
485                                 else {
486                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
487                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
488                                 }
489
490                                 xbasis = cross(v1,v2);
491
492                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
493                                         firstxbasis = normalize(xbasis);
494                                         break;
495                                 }
496                         }
497
498                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
499
500                                 int subv = 1;
501                                 float3 xbasis;
502                                 float3 ybasis;
503                                 float3 v1;
504                                 float3 v2;
505
506                                 if(curvekey == CData->curve_firstkey[curve]) {
507                                         subv = 0;
508                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
509                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
510                                 }
511                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
512                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
513                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
514                                 }
515                                 else {
516                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
517                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
518                                 }
519
520                                 xbasis = cross(v1,v2);
521
522                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
523                                         xbasis = normalize(xbasis);
524                                         firstxbasis = xbasis;
525                                 }
526                                 else
527                                         xbasis = firstxbasis;
528
529                                 ybasis = normalize(cross(xbasis,v2));
530
531                                 for (; subv <= 1; subv++) {
532
533                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
534                                         float time = 0.0f;
535
536                                         InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData , 1);
537
538                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
539
540                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1))
541                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
542
543                                         if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
544                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
545
546                                         float angle = M_2PI_F / (float)resolution;
547                                         for(int section = 0 ; section < resolution; section++) {
548                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
549                                                 mesh->verts.push_back(ickey_loc_shf);
550                                         }
551
552                                         if(subv!=0) {
553                                                 for(int section = 0 ; section < resolution - 1; section++) {
554                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true);
555                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true);
556                                                 }
557                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true);
558                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true);
559                                         }
560                                         vertexindex += resolution;
561                                 }
562                         }
563                 }
564         }
565
566         mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
567         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
568         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
569         mesh->add_face_normals();
570         mesh->add_vertex_normals();
571         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
572
573         /* texture coords still needed */
574 }
575
576 void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
577 {
578         int num_keys = 0;
579         int num_curves = 0;
580
581         if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
582                 return;
583
584         Attribute *attr_intercept = NULL;
585         
586         if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
587                 attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
588
589         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
590
591                 if(CData->psys_curvenum[sys] == 0)
592                         continue;
593
594                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
595
596                         if(CData->curve_keynum[curve] <= 1)
597                                 continue;
598
599                         size_t num_curve_keys = 0;
600
601                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
602                                 float3 ickey_loc = CData->curvekey_co[curvekey];
603                                 float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
604                                 float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
605
606                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
607                                         radius =0.0f;
608
609                                 mesh->add_curve_key(ickey_loc, radius);
610                                 if(attr_intercept)
611                                         attr_intercept->add(time);
612
613                                 num_curve_keys++;
614                         }
615
616                         mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
617                         num_keys += num_curve_keys;
618                         num_curves++;
619                 }
620         }
621
622         /* check allocation*/
623         if((mesh->curve_keys.size() !=  num_keys) || (mesh->curves.size() !=  num_curves)) {
624                 /* allocation failed -> clear data */
625                 mesh->curve_keys.clear();
626                 mesh->curves.clear();
627                 mesh->curve_attributes.clear();
628         }
629 }
630
631 static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int motion)
632 {
633         /* export motion vectors for curve keys */
634         AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
635         Attribute *attr_motion = mesh->curve_attributes.add(std);
636         float3 *data_motion = attr_motion->data_float3();
637         float3 *current_motion = data_motion;
638         size_t size = mesh->curve_keys.size();
639         size_t i = 0;
640         bool have_motion = false;
641
642         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
643                 if(CData->psys_curvenum[sys] == 0)
644                         continue;
645
646                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
647                         if(CData->curve_keynum[curve] <= 1)
648                                 continue;
649
650                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
651                                 if(i < mesh->curve_keys.size()) {
652                                         *current_motion = CData->curvekey_co[curvekey];
653
654                                         /* unlike mesh coordinates, these tend to be slightly different
655                                          * between frames due to particle transforms into/out of object
656                                          * space, so we use an epsilon to detect actual changes */
657                                         if(len_squared(*current_motion - mesh->curve_keys[i].co) > 1e-5f*1e-5f)
658                                                 have_motion = true;
659
660                                         current_motion++;
661                                 }
662
663                                 i++;
664                         }
665                 }
666         }
667
668         if(i != size || !have_motion)
669                 mesh->curve_attributes.remove(std);
670 }
671
672 void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
673 {
674         if(uvdata == NULL)
675                 return;
676
677         float time = 0.0f;
678         float prevtime = 0.0f;
679
680         int vertexindex = vert_offset;
681
682         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
683                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
684
685                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
686
687                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
688
689                                 for(int section = 0 ; section < resol; section++) {
690                                         uvdata[vertexindex] = CData->curve_uv[curve];
691                                         uvdata[vertexindex].z = prevtime;
692                                         vertexindex++;
693                                         uvdata[vertexindex] = CData->curve_uv[curve];
694                                         uvdata[vertexindex].z = time;
695                                         vertexindex++;
696                                         uvdata[vertexindex] = CData->curve_uv[curve];
697                                         uvdata[vertexindex].z = prevtime;
698                                         vertexindex++;
699                                         uvdata[vertexindex] = CData->curve_uv[curve];
700                                         uvdata[vertexindex].z = time;
701                                         vertexindex++;
702                                         uvdata[vertexindex] = CData->curve_uv[curve];
703                                         uvdata[vertexindex].z = prevtime;
704                                         vertexindex++;
705                                         uvdata[vertexindex] = CData->curve_uv[curve];
706                                         uvdata[vertexindex].z = time;
707                                         vertexindex++;
708                                 }
709
710                                 prevtime = time;                        
711                                 
712                         }
713                 }
714         }
715
716 }
717
718 void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *fdata)
719 {
720         if(fdata == NULL)
721                 return;
722
723         int vertexindex = vert_offset;
724
725         for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
726                 for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
727
728                         for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
729
730                                 for(int section = 0 ; section < resol; section++) {
731                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
732                                         vertexindex++;
733                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
734                                         vertexindex++;
735                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
736                                         vertexindex++;
737                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
738                                         vertexindex++;
739                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
740                                         vertexindex++;
741                                         fdata[vertexindex] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
742                                         vertexindex++;
743                                 }
744                         }
745                 }
746         }
747
748 }
749
750 /* Hair Curve Sync */
751
752 void BlenderSync::sync_curve_settings()
753 {
754         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
755
756         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
757         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
758
759         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
760         curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
761         curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
762
763         curve_system_manager->primitive = get_enum(csscene, "primitive");
764         curve_system_manager->curve_shape = get_enum(csscene, "shape");
765         curve_system_manager->resolution = get_int(csscene, "resolution");
766         curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
767         curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
768
769         curve_system_manager->encasing_ratio = 1.01f;
770
771         if(curve_system_manager->primitive == CURVE_TRIANGLES && curve_system_manager->curve_shape == CURVE_RIBBON) {
772                 /*camera facing planes*/
773                 curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
774                 curve_system_manager->resolution = 1;
775         }
776         if(curve_system_manager->primitive == CURVE_TRIANGLES && curve_system_manager->curve_shape == CURVE_THICK) {
777                 /*camera facing planes*/
778                 curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
779         }
780         if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS && curve_system_manager->curve_shape == CURVE_RIBBON) {
781                 /*tangent shading*/
782                 curve_system_manager->line_method = CURVE_UNCORRECTED;
783                 curve_system_manager->use_encasing = true;
784                 curve_system_manager->use_backfacing = false;
785                 curve_system_manager->use_tangent_normal = true;
786                 curve_system_manager->use_tangent_normal_geometry = true;
787         }
788         if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS && curve_system_manager->curve_shape == CURVE_THICK) {
789                 curve_system_manager->line_method = CURVE_ACCURATE;
790                 curve_system_manager->use_encasing = false;
791                 curve_system_manager->use_tangent_normal = false;
792                 curve_system_manager->use_tangent_normal_geometry = false;
793         }
794         if(curve_system_manager->primitive == CURVE_SEGMENTS && curve_system_manager->curve_shape == CURVE_RIBBON) {
795                 curve_system_manager->primitive = CURVE_RIBBONS;
796                 curve_system_manager->use_backfacing = false;
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, int motion)
823 {
824         if(!motion) {
825                 /* Clear stored curve data */
826                 mesh->curve_keys.clear();
827                 mesh->curves.clear();
828                 mesh->curve_attributes.clear();
829         }
830
831         /* obtain general settings */
832         bool use_curves = scene->curve_system_manager->use_curves;
833
834         if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) {
835                 if(!motion)
836                         mesh->compute_bounds();
837                 return;
838         }
839
840         int primitive = scene->curve_system_manager->primitive;
841         int triangle_method = scene->curve_system_manager->triangle_method;
842         int resolution = scene->curve_system_manager->resolution;
843         size_t vert_num = mesh->verts.size();
844         size_t tri_num = mesh->triangles.size();
845         int used_res = 1;
846
847         /* extract particle hair data - should be combined with connecting to mesh later*/
848
849         ParticleCurveData CData;
850
851         if(!preview)
852                 set_resolution(mesh, &b_mesh, &b_ob, &b_scene, true);
853
854         ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
855
856         /* obtain camera parameters */
857         BL::Object b_CamOb = b_scene.camera();
858         float3 RotCam = make_float3(0.0f, 0.0f, 0.0f);
859         if(b_CamOb) {
860                 Transform ctfm = get_transform(b_CamOb.matrix_world());
861                 Transform tfm = get_transform(b_ob.matrix_world());
862                 Transform itfm = transform_quick_inverse(tfm);
863                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
864         }
865
866         /* add hair geometry to mesh */
867         if(primitive == CURVE_TRIANGLES) {
868                 if(triangle_method == CURVE_CAMERA_TRIANGLES)
869                         ExportCurveTrianglePlanes(mesh, &CData, RotCam);
870                 else {
871                         ExportCurveTriangleGeometry(mesh, &CData, resolution);
872                         used_res = resolution;
873                 }
874         }
875         else {
876                 if(motion)
877                         ExportCurveSegmentsMotion(scene, mesh, &CData, motion);
878                 else
879                         ExportCurveSegments(scene, mesh, &CData);
880         }
881
882         /* generated coordinates from first key. we should ideally get this from
883          * blender to handle deforming objects */
884         if(!motion) {
885                 if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
886                         float3 loc, size;
887                         mesh_texture_space(b_mesh, loc, size);
888
889                         if(primitive == CURVE_TRIANGLES) {
890                                 Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
891                                 float3 *generated = attr_generated->data_float3();
892
893                                 for(size_t i = vert_num; i < mesh->verts.size(); i++)
894                                         generated[i] = mesh->verts[i]*size - loc;
895                         }
896                         else {
897                                 Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
898                                 float3 *generated = attr_generated->data_float3();
899                                 size_t i = 0;
900
901                                 foreach(Mesh::Curve& curve, mesh->curves) {
902                                         float3 co = mesh->curve_keys[curve.first_key].co;
903                                         generated[i++] = co*size - loc;
904                                 }
905                         }
906                 }
907         }
908
909         /* create vertex color attributes */
910         if(!motion) {
911                 BL::Mesh::tessface_vertex_colors_iterator l;
912                 int vcol_num = 0;
913
914                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
915                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
916                                 continue;
917
918                         ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
919
920                         if(primitive == CURVE_TRIANGLES) {
921
922                                 Attribute *attr_vcol = mesh->attributes.add(
923                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
924
925                                 float3 *fdata = attr_vcol->data_float3();
926
927                                 ExportCurveTriangleVcol(mesh, &CData, tri_num * 3, used_res, fdata);
928                         }
929                         else {
930                                 Attribute *attr_vcol = mesh->curve_attributes.add(
931                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
932
933                                 float3 *fdata = attr_vcol->data_float3();
934
935                                 if(fdata) {
936                                         for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
937                                                 fdata[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
938                                 }
939                         }
940                 }
941         }
942
943         /* create UV attributes */
944         if(!motion) {
945                 BL::Mesh::tessface_uv_textures_iterator l;
946                 int uv_num = 0;
947
948                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
949                         bool active_render = l->active_render();
950                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
951                         ustring name = ustring(l->name().c_str());
952
953                         /* UV map */
954                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
955                                 Attribute *attr_uv;
956
957                                 ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
958
959                                 if(primitive == CURVE_TRIANGLES) {
960                                         if(active_render)
961                                                 attr_uv = mesh->attributes.add(std, name);
962                                         else
963                                                 attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
964
965                                         float3 *uv = attr_uv->data_float3();
966
967                                         ExportCurveTriangleUV(mesh, &CData, tri_num * 3, used_res, uv);
968                                 }
969                                 else {
970                                         if(active_render)
971                                                 attr_uv = mesh->curve_attributes.add(std, name);
972                                         else
973                                                 attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
974
975                                         float3 *uv = attr_uv->data_float3();
976
977                                         if(uv) {
978                                                 for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
979                                                         uv[curve] = CData.curve_uv[curve];
980                                         }
981                                 }
982                         }
983                 }
984         }
985
986         if(!preview)
987                 set_resolution(mesh, &b_mesh, &b_ob, &b_scene, false);
988
989         mesh->compute_bounds();
990 }
991
992 CCL_NAMESPACE_END
993