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