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