Merge branch 'master' into blender2.8
[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 "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 void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
41 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
42                                float3 RotCam, bool is_ortho);
43 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
44 void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
45 void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
46
47 ParticleCurveData::ParticleCurveData()
48 {
49 }
50
51 ParticleCurveData::~ParticleCurveData()
52 {
53 }
54
55 void interp_weights(float t, float data[4])
56 {
57         /* Cardinal curve interpolation */
58         float t2 = t * t;
59         float t3 = t2 * t;
60         float fc = 0.71f;
61
62         data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
63         data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
64         data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
65         data[3] =  fc          * t3  - fc * t2;
66 }
67
68 void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
69 {
70         p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
71         p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
72         p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
73 }
74
75 float shaperadius(float shape, float root, float tip, float time)
76 {
77         float radius = 1.0f - time;
78         
79         if(shape != 0.0f) {
80                 if(shape < 0.0f)
81                         radius = powf(radius, 1.0f + shape);
82                 else
83                         radius = powf(radius, 1.0f / (1.0f - shape));
84         }
85         return (radius * (root - tip)) + tip;
86 }
87
88 /* curve functions */
89
90 void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData)
91 {
92         float3 ckey_loc1 = CData->curvekey_co[key];
93         float3 ckey_loc2 = ckey_loc1;
94         float3 ckey_loc3 = CData->curvekey_co[key+1];
95         float3 ckey_loc4 = ckey_loc3;
96
97         if(key > CData->curve_firstkey[curve])
98                 ckey_loc1 = CData->curvekey_co[key - 1];
99
100         if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
101                 ckey_loc4 = CData->curvekey_co[key + 2];
102
103         float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
104         float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
105
106         float dfra = (time2 - time1) / (float)segno;
107
108         if(time)
109                 *time = (dfra * seg) + time1;
110
111         float t[4];
112
113         interp_weights((float)seg / (float)segno, t);
114
115         if(keyloc)
116                 curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
117 }
118
119 void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
120                                float3 RotCam, bool is_ortho)
121 {
122         int vertexno = mesh->verts.size();
123         int vertexindex = vertexno;
124         int numverts = 0, numtris = 0;
125
126         /* compute and reserve size of arrays */
127         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
128                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
129                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
130                                 continue;
131
132                         numverts += 2 + (CData->curve_keynum[curve] - 1)*2;
133                         numtris += (CData->curve_keynum[curve] - 1)*2;
134                 }
135         }
136
137         mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
138
139         /* actually export */
140         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
141                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
142                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
143                                 continue;
144
145                         float3 xbasis;
146                         float3 v1;
147                         float time = 0.0f;
148                         float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]];
149                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f);
150                         v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]];
151                         if(is_ortho)
152                                 xbasis = normalize(cross(RotCam, v1));
153                         else
154                                 xbasis = normalize(cross(RotCam - ickey_loc, v1));
155                         float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
156                         float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
157                         mesh->add_vertex(ickey_loc_shfl);
158                         mesh->add_vertex(ickey_loc_shfr);
159                         vertexindex += 2;
160
161                         for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
162                                 ickey_loc = CData->curvekey_co[curvekey];
163
164                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
165                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])];
166                                 else 
167                                         v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
168
169                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
170                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
171
172                                 if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
173                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
174
175                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
176                                         radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
177
178                                 if(is_ortho)
179                                         xbasis = normalize(cross(RotCam, v1));
180                                 else
181                                         xbasis = normalize(cross(RotCam - ickey_loc, v1));
182                                 float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
183                                 float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
184                                 mesh->add_vertex(ickey_loc_shfl);
185                                 mesh->add_vertex(ickey_loc_shfr);
186                                 mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
187                                 mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
188                                 vertexindex += 2;
189                         }
190                 }
191         }
192
193         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
194         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
195         mesh->add_face_normals();
196         mesh->add_vertex_normals();
197         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
198
199         /* texture coords still needed */
200 }
201
202 void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution)
203 {
204         int vertexno = mesh->verts.size();
205         int vertexindex = vertexno;
206         int numverts = 0, numtris = 0;
207
208         /* compute and reserve size of arrays */
209         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
210                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
211                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
212                                 continue;
213
214                         numverts += (CData->curve_keynum[curve] - 2)*2*resolution + resolution;
215                         numtris += (CData->curve_keynum[curve] - 2)*resolution;
216                 }
217         }
218
219         mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
220
221         /* actually export */
222         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
223                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
224                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
225                                 continue;
226
227                         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]]);
228                         if(!is_zero(firstxbasis))
229                                 firstxbasis = normalize(firstxbasis);
230                         else
231                                 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]]));
232
233                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
234                                 float3 xbasis = firstxbasis;
235                                 float3 v1;
236                                 float3 v2;
237
238                                 if(curvekey == CData->curve_firstkey[curve]) {
239                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
240                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
241                                 }
242                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
243                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
244                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
245                                 }
246                                 else {
247                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
248                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
249                                 }
250
251                                 xbasis = cross(v1, v2);
252
253                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
254                                         firstxbasis = normalize(xbasis);
255                                         break;
256                                 }
257                         }
258
259                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
260                                 int subv = 1;
261                                 float3 xbasis;
262                                 float3 ybasis;
263                                 float3 v1;
264                                 float3 v2;
265
266                                 if(curvekey == CData->curve_firstkey[curve]) {
267                                         subv = 0;
268                                         v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
269                                         v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
270                                 }
271                                 else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
272                                         v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
273                                         v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
274                                 }
275                                 else {
276                                         v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
277                                         v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
278                                 }
279
280                                 xbasis = cross(v1, v2);
281
282                                 if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
283                                         xbasis = normalize(xbasis);
284                                         firstxbasis = xbasis;
285                                 }
286                                 else
287                                         xbasis = firstxbasis;
288
289                                 ybasis = normalize(cross(xbasis, v2));
290
291                                 for(; subv <= 1; subv++) {
292                                         float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
293                                         float time = 0.0f;
294
295                                         InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData);
296
297                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
298
299                                         if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1))
300                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
301
302                                         if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
303                                                 radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
304
305                                         float angle = M_2PI_F / (float)resolution;
306                                         for(int section = 0; section < resolution; section++) {
307                                                 float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
308                                                 mesh->add_vertex(ickey_loc_shf);
309                                         }
310
311                                         if(subv != 0) {
312                                                 for(int section = 0; section < resolution - 1; section++) {
313                                                         mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true);
314                                                         mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true);
315                                                 }
316                                                 mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true);
317                                                 mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true);
318                                         }
319                                         vertexindex += resolution;
320                                 }
321                         }
322                 }
323         }
324
325         mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
326         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
327         mesh->add_face_normals();
328         mesh->add_vertex_normals();
329         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
330
331         /* texture coords still needed */
332 }
333
334 void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
335 {
336         int num_keys = 0;
337         int num_curves = 0;
338
339         if(mesh->num_curves())
340                 return;
341
342         Attribute *attr_intercept = NULL;
343         
344         if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
345                 attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
346
347         /* compute and reserve size of arrays */
348         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
349                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
350                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
351                                 continue;
352
353                         num_keys += CData->curve_keynum[curve];
354                         num_curves++;
355                 }
356         }
357
358         if(num_curves > 0) {
359                 VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
360         }
361
362         mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
363
364         num_keys = 0;
365         num_curves = 0;
366
367         /* actually export */
368         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
369                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
370                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
371                                 continue;
372
373                         size_t num_curve_keys = 0;
374
375                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
376                                 float3 ickey_loc = CData->curvekey_co[curvekey];
377                                 float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
378                                 float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
379
380                                 if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
381                                         radius = 0.0f;
382
383                                 mesh->add_curve_key(ickey_loc, radius);
384                                 if(attr_intercept)
385                                         attr_intercept->add(time);
386
387                                 num_curve_keys++;
388                         }
389
390                         mesh->add_curve(num_keys, CData->psys_shader[sys]);
391                         num_keys += num_curve_keys;
392                         num_curves++;
393                 }
394         }
395
396         /* check allocation */
397         if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
398                 VLOG(1) << "Allocation failed, clearing data";
399                 mesh->clear();
400         }
401 }
402
403 static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
404 {
405         VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
406                 << ", time index " << time_index;
407
408         /* find attribute */
409         Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
410         bool new_attribute = false;
411
412         /* add new attribute if it doesn't exist already */
413         if(!attr_mP) {
414                 VLOG(1) << "Creating new motion vertex position attribute";
415                 attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
416                 new_attribute = true;
417         }
418
419         /* export motion vectors for curve keys */
420         size_t numkeys = mesh->curve_keys.size();
421         float4 *mP = attr_mP->data_float4() + time_index*numkeys;
422         bool have_motion = false;
423         int i = 0;
424
425         for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
426                 if(CData->psys_curvenum[sys] == 0)
427                         continue;
428
429                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
430                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
431                                 continue;
432
433                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
434                                 if(i < mesh->curve_keys.size()) {
435                                         float3 ickey_loc = CData->curvekey_co[curvekey];
436                                         float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
437                                         float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
438
439                                         if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
440                                                 radius = 0.0f;
441
442                                         /* curve motion keys store both position and radius in float4 */
443                                         mP[i] = float3_to_float4(ickey_loc);
444                                         mP[i].w = radius;
445
446                                         /* unlike mesh coordinates, these tend to be slightly different
447                                          * between frames due to particle transforms into/out of object
448                                          * space, so we use an epsilon to detect actual changes */
449                                         float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
450                                         curve_key.w = mesh->curve_radius[i];
451                                         if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
452                                                 have_motion = true;
453                                 }
454
455                                 i++;
456                         }
457                 }
458         }
459
460         /* in case of new attribute, we verify if there really was any motion */
461         if(new_attribute) {
462                 if(i != numkeys || !have_motion) {
463                         /* no motion, remove attributes again */
464                         VLOG(1) << "No motion, removing attribute";
465                         mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
466                 }
467                 else if(time_index > 0) {
468                         VLOG(1) << "Filling in new motion vertex position for time_index "
469                                 << time_index;
470                         /* motion, fill up previous steps that we might have skipped because
471                          * they had no motion, but we need them anyway now */
472                         for(int step = 0; step < time_index; step++) {
473                                 float4 *mP = attr_mP->data_float4() + step*numkeys;
474
475                                 for(int key = 0; key < numkeys; key++) {
476                                         mP[key] = float3_to_float4(mesh->curve_keys[key]);
477                                         mP[key].w = mesh->curve_radius[key];
478                                 }
479                         }
480                 }
481         }
482 }
483
484 void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
485 {
486         if(uvdata == NULL)
487                 return;
488
489         float time = 0.0f;
490         float prevtime = 0.0f;
491
492         int vertexindex = vert_offset;
493
494         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
495                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
496                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
497                                 continue;
498
499                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
500                                 time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
501
502                                 for(int section = 0; section < resol; section++) {
503                                         uvdata[vertexindex] = CData->curve_uv[curve];
504                                         uvdata[vertexindex].z = prevtime;
505                                         vertexindex++;
506                                         uvdata[vertexindex] = CData->curve_uv[curve];
507                                         uvdata[vertexindex].z = time;
508                                         vertexindex++;
509                                         uvdata[vertexindex] = CData->curve_uv[curve];
510                                         uvdata[vertexindex].z = prevtime;
511                                         vertexindex++;
512                                         uvdata[vertexindex] = CData->curve_uv[curve];
513                                         uvdata[vertexindex].z = time;
514                                         vertexindex++;
515                                         uvdata[vertexindex] = CData->curve_uv[curve];
516                                         uvdata[vertexindex].z = prevtime;
517                                         vertexindex++;
518                                         uvdata[vertexindex] = CData->curve_uv[curve];
519                                         uvdata[vertexindex].z = time;
520                                         vertexindex++;
521                                 }
522
523                                 prevtime = time;
524                         }
525                 }
526         }
527 }
528
529 void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
530 {
531         if(cdata == NULL)
532                 return;
533
534         int vertexindex = vert_offset;
535
536         for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
537                 for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
538                         if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
539                                 continue;
540
541                         for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
542                                 for(int section = 0; section < resol; section++) {
543                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
544                                         vertexindex++;
545                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
546                                         vertexindex++;
547                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
548                                         vertexindex++;
549                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
550                                         vertexindex++;
551                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
552                                         vertexindex++;
553                                         cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear(CData->curve_vcol[curve]));
554                                         vertexindex++;
555                                 }
556                         }
557                 }
558         }
559 }
560
561 /* Hair Curve Sync */
562
563 void BlenderSync::sync_curve_settings()
564 {
565         PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
566
567         CurveSystemManager *curve_system_manager = scene->curve_system_manager;
568         CurveSystemManager prev_curve_system_manager = *curve_system_manager;
569
570         curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
571         curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
572         curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
573
574         curve_system_manager->primitive =
575                 (CurvePrimitiveType)get_enum(csscene,
576                                              "primitive",
577                                              CURVE_NUM_PRIMITIVE_TYPES,
578                                              CURVE_LINE_SEGMENTS);
579         curve_system_manager->curve_shape =
580                 (CurveShapeType)get_enum(csscene,
581                                          "shape",
582                                          CURVE_NUM_SHAPE_TYPES,
583                                          CURVE_THICK);
584         curve_system_manager->resolution = get_int(csscene, "resolution");
585         curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
586         curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
587
588         /* Triangles */
589         if(curve_system_manager->primitive == CURVE_TRIANGLES) {
590                 /* camera facing planes */
591                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
592                         curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
593                         curve_system_manager->resolution = 1;
594                 }
595                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
596                         curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
597                 }
598         }
599         /* Line Segments */
600         else if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS) {
601                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
602                         /* tangent shading */
603                         curve_system_manager->line_method = CURVE_UNCORRECTED;
604                         curve_system_manager->use_encasing = true;
605                         curve_system_manager->use_backfacing = false;
606                         curve_system_manager->use_tangent_normal_geometry = true;
607                 }
608                 else if(curve_system_manager->curve_shape == CURVE_THICK) {
609                         curve_system_manager->line_method = CURVE_ACCURATE;
610                         curve_system_manager->use_encasing = false;
611                         curve_system_manager->use_tangent_normal_geometry = false;
612                 }
613         }
614         /* Curve Segments */
615         else if(curve_system_manager->primitive == CURVE_SEGMENTS) {
616                 if(curve_system_manager->curve_shape == CURVE_RIBBON) {
617                         curve_system_manager->primitive = CURVE_RIBBONS;
618                         curve_system_manager->use_backfacing = false;
619                 }
620         }
621
622         if(curve_system_manager->modified_mesh(prev_curve_system_manager)) {
623         }
624
625         if(curve_system_manager->modified(prev_curve_system_manager))
626                 curve_system_manager->tag_update(scene);
627 }
628
629 void BlenderSync::sync_curves(Mesh *mesh,
630                               BL::Mesh& b_mesh,
631                               BL::Object& b_ob,
632                               bool motion,
633                               int time_index)
634 {
635         if(!motion) {
636                 /* Clear stored curve data */
637                 mesh->curve_keys.clear();
638                 mesh->curve_radius.clear();
639                 mesh->curve_first_key.clear();
640                 mesh->curve_shader.clear();
641                 mesh->curve_attributes.clear();
642         }
643
644         /* obtain general settings */
645         bool use_curves = scene->curve_system_manager->use_curves;
646
647         if(!use_curves) {
648                 if(!motion)
649                         mesh->compute_bounds();
650                 return;
651         }
652
653         int primitive = scene->curve_system_manager->primitive;
654         int triangle_method = scene->curve_system_manager->triangle_method;
655         int resolution = scene->curve_system_manager->resolution;
656         size_t vert_num = mesh->verts.size();
657         size_t tri_num = mesh->num_triangles();
658         int used_res = 1;
659
660         /* extract particle hair data - should be combined with connecting to mesh later*/
661
662         ParticleCurveData CData;
663
664         /* add hair geometry to mesh */
665         if(primitive == CURVE_TRIANGLES) {
666                 if(triangle_method == CURVE_CAMERA_TRIANGLES) {
667                         /* obtain camera parameters */
668                         float3 RotCam;
669                         Camera *camera = scene->camera;
670                         Transform &ctfm = camera->matrix;
671                         if(camera->type == CAMERA_ORTHOGRAPHIC) {
672                                 RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
673                         }
674                         else {
675                                 Transform tfm = get_transform(b_ob.matrix_world());
676                                 Transform itfm = transform_quick_inverse(tfm);
677                                 RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
678                                                                             ctfm.y.w,
679                                                                             ctfm.z.w));
680                         }
681                         bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
682                         ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
683                 }
684                 else {
685                         ExportCurveTriangleGeometry(mesh, &CData, resolution);
686                         used_res = resolution;
687                 }
688         }
689         else {
690                 if(motion)
691                         ExportCurveSegmentsMotion(mesh, &CData, time_index);
692                 else
693                         ExportCurveSegments(scene, mesh, &CData);
694         }
695
696         /* generated coordinates from first key. we should ideally get this from
697          * blender to handle deforming objects */
698         if(!motion) {
699                 if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
700                         float3 loc, size;
701                         mesh_texture_space(b_mesh, loc, size);
702
703                         if(primitive == CURVE_TRIANGLES) {
704                                 Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
705                                 float3 *generated = attr_generated->data_float3();
706
707                                 for(size_t i = vert_num; i < mesh->verts.size(); i++)
708                                         generated[i] = mesh->verts[i]*size - loc;
709                         }
710                         else {
711                                 Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
712                                 float3 *generated = attr_generated->data_float3();
713
714                                 for(size_t i = 0; i < mesh->num_curves(); i++) {
715                                         float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
716                                         generated[i] = co*size - loc;
717                                 }
718                         }
719                 }
720         }
721
722         /* create vertex color attributes */
723         if(!motion) {
724                 BL::Mesh::tessface_vertex_colors_iterator l;
725                 int vcol_num = 0;
726
727                 for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
728                         if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
729                                 continue;
730
731                         if(primitive == CURVE_TRIANGLES) {
732                                 Attribute *attr_vcol = mesh->attributes.add(
733                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
734
735                                 uchar4 *cdata = attr_vcol->data_uchar4();
736
737                                 ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
738                         }
739                         else {
740                                 Attribute *attr_vcol = mesh->curve_attributes.add(
741                                         ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
742
743                                 float3 *fdata = attr_vcol->data_float3();
744
745                                 if(fdata) {
746                                         size_t i = 0;
747
748                                         for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
749                                                 if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
750                                                         fdata[i++] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
751                                 }
752                         }
753                 }
754         }
755
756         /* create UV attributes */
757         if(!motion) {
758                 BL::Mesh::tessface_uv_textures_iterator l;
759                 int uv_num = 0;
760
761                 for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
762                         bool active_render = l->active_render();
763                         AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
764                         ustring name = ustring(l->name().c_str());
765
766                         /* UV map */
767                         if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
768                                 Attribute *attr_uv;
769
770                                 if(primitive == CURVE_TRIANGLES) {
771                                         if(active_render)
772                                                 attr_uv = mesh->attributes.add(std, name);
773                                         else
774                                                 attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
775
776                                         float3 *uv = attr_uv->data_float3();
777
778                                         ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
779                                 }
780                                 else {
781                                         if(active_render)
782                                                 attr_uv = mesh->curve_attributes.add(std, name);
783                                         else
784                                                 attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
785
786                                         float3 *uv = attr_uv->data_float3();
787
788                                         if(uv) {
789                                                 size_t i = 0;
790
791                                                 for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
792                                                         if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
793                                                                 uv[i++] = CData.curve_uv[curve];
794                                         }
795                                 }
796                         }
797                 }
798         }
799
800         mesh->compute_bounds();
801 }
802
803 CCL_NAMESPACE_END
804