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