Cycles: remove option to disable transparent shadows globally.
[blender-staging.git] / intern / cycles / blender / blender_curves.cpp
index c37895cd19675596808f3f02c57322612b66f6e1..42b985305ea1f7e530c809473b8514f0087777f3 100644 (file)
 /*
 /*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
  *
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
  */
 
-#include "attribute.h"
-#include "mesh.h"
-#include "object.h"
-#include "scene.h"
-#include "curves.h"
+#include "render/attribute.h"
+#include "render/camera.h"
+#include "render/curves.h"
+#include "render/mesh.h"
+#include "render/object.h"
+#include "render/scene.h"
 
 
-#include "blender_sync.h"
-#include "blender_util.h"
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
 
 
-#include "util_foreach.h"
+#include "util/util_foreach.h"
+#include "util/util_logging.h"
 
 CCL_NAMESPACE_BEGIN
 
 
 CCL_NAMESPACE_BEGIN
 
-/* Utilities */
-
-/* Hair curve functions */
-
-void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]);
-void interp_weights(float t, float data[4], int type);
-float shaperadius(float shape, float root, float tip, float time);
-void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
-void ToggleRender(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, BL::Scene *scene);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int uv_num);
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int vcol_num);
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background);
-void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam);
-void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments);
-void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments);
-void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments);
-void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol);
-
 ParticleCurveData::ParticleCurveData()
 {
 }
 
 ParticleCurveData::~ParticleCurveData()
 {
 ParticleCurveData::ParticleCurveData()
 {
 }
 
 ParticleCurveData::~ParticleCurveData()
 {
-       psys_firstcurve.clear();
-       psys_curvenum.clear();
-       psys_shader.clear();
-       psys_rootradius.clear();
-       psys_tipradius.clear();
-       psys_shape.clear();
-
-       curve_firstkey.clear();
-       curve_keynum.clear();
-       curve_length.clear();
-       curve_uv.clear();
-       curve_vcol.clear();
-
-       curvekey_co.clear();
-       curvekey_time.clear();
 }
 
 }
 
-void interp_weights(float t, float data[4], int type)
+static void interp_weights(float t, float data[4])
 {
 {
-       float t2, t3, fc;
-
-       if(type == CURVE_LINEAR) {
-               data[0] =          0.0f;
-               data[1] = -t     + 1.0f;
-               data[2] =  t;
-               data[3] =          0.0f;
-       }
-       else if(type == CURVE_CARDINAL) {
-               t2 = t * t;
-               t3 = t2 * t;
-               fc = 0.71f;
-
-               data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
-               data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
-               data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
-               data[3] =  fc          * t3  - fc * t2;
-       }
-       else if(type == CURVE_BSPLINE) {
-               t2 = t * t;
-               t3 = t2 * t;
-
-               data[0] = -0.16666666f * t3  + 0.5f * t2   - 0.5f * t    + 0.16666666f;
-               data[1] =  0.5f        * t3  - t2                        + 0.66666666f;
-               data[2] = -0.5f        * t3  + 0.5f * t2   + 0.5f * t    + 0.16666666f;
-               data[3] =  0.16666666f * t3;
-       }
+       /* Cardinal curve interpolation */
+       float t2 = t * t;
+       float t3 = t2 * t;
+       float fc = 0.71f;
+
+       data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
+       data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
+       data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
+       data[3] =  fc          * t3  - fc * t2;
 }
 
 }
 
-void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4])
+static void curveinterp_v3_v3v3v3v3(float3 *p,
+                                    float3 *v1, float3 *v2, float3 *v3, float3 *v4,
+                                    const float w[4])
 {
        p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
        p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
        p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
 }
 
 {
        p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3];
        p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3];
        p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3];
 }
 
-float shaperadius(float shape, float root, float tip, float time)
+static float shaperadius(float shape, float root, float tip, float time)
 {
        float radius = 1.0f - time;
 {
        float radius = 1.0f - time;
+
        if(shape != 0.0f) {
                if(shape < 0.0f)
        if(shape != 0.0f) {
                if(shape < 0.0f)
-                       radius = (float)pow(1.0f - time, 1.f + shape);
+                       radius = powf(radius, 1.0f + shape);
                else
                else
-                       radius = (float)pow(1.0f - time, 1.f / (1.f - shape));
+                       radius = powf(radius, 1.0f / (1.0f - shape));
        }
        return (radius * (root - tip)) + tip;
 }
 
 /* curve functions */
 
        }
        return (radius * (root - tip)) + tip;
 }
 
 /* curve functions */
 
-void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation)
+static void InterpolateKeySegments(int seg,
+                                   int segno,
+                                   int key,
+                                   int curve,
+                                   float3 *keyloc,
+                                   float *time,
+                                   ParticleCurveData *CData)
 {
        float3 ckey_loc1 = CData->curvekey_co[key];
        float3 ckey_loc2 = ckey_loc1;
 {
        float3 ckey_loc1 = CData->curvekey_co[key];
        float3 ckey_loc2 = ckey_loc1;
@@ -135,7 +93,6 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
        if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
                ckey_loc4 = CData->curvekey_co[key + 2];
 
        if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)
                ckey_loc4 = CData->curvekey_co[key + 2];
 
-
        float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
        float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
 
        float time1 = CData->curvekey_time[key]/CData->curve_length[curve];
        float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve];
 
@@ -146,15 +103,18 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
 
        float t[4];
 
 
        float t[4];
 
-       interp_weights((float)seg / (float)segno, t, interpolation);
+       interp_weights((float)seg / (float)segno, t);
 
        if(keyloc)
                curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
 }
 
 
        if(keyloc)
                curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
 }
 
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background)
+static bool ObtainCacheParticleData(Mesh *mesh,
+                                    BL::Mesh *b_mesh,
+                                    BL::Object *b_ob,
+                                    ParticleCurveData *CData,
+                                    bool background)
 {
 {
-
        int curvenum = 0;
        int keyno = 0;
 
        int curvenum = 0;
        int keyno = 0;
 
@@ -166,290 +126,292 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
-               if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
+               if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
-
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
-
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
-                       if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
-
-                               int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
-                               int shader = mesh->used_shaders[mi];
-                               int draw_step = background ? b_psys.settings().render_step() : b_psys.settings().draw_step();
-                               int ren_step = (int)pow((float)2.0f,(float)draw_step);
+                       if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+                               int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
+                               int draw_step = background ? b_part.render_step() : b_part.draw_step();
                                int totparts = b_psys.particles.length();
                                int totparts = b_psys.particles.length();
-                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
+                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
                                int totcurves = totchild;
                                int totcurves = totchild;
-                               
-                               if(use_parents || b_psys.settings().child_type() == 0)
+
+                               if(b_part.child_type() == 0 || totchild == 0)
                                        totcurves += totparts;
 
                                if(totcurves == 0)
                                        continue;
 
                                        totcurves += totparts;
 
                                if(totcurves == 0)
                                        continue;
 
+                               int ren_step = (1 << draw_step) + 1;
+                               if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
+                                       ren_step += b_part.kink_extra_steps();
+
                                PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
 
                                PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
 
-                               CData->psys_firstcurve.push_back(curvenum);
-                               CData->psys_curvenum.push_back(totcurves);
-                               CData->psys_shader.push_back(shader);
+                               CData->psys_firstcurve.push_back_slow(curvenum);
+                               CData->psys_curvenum.push_back_slow(totcurves);
+                               CData->psys_shader.push_back_slow(shader);
+
+                               float radius = get_float(cpsys, "radius_scale") * 0.5f;
 
 
-                               float radius = b_psys.settings().particle_size() * 0.5f;
-       
-                               CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
-                               CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
-                               CData->psys_shape.push_back(get_float(cpsys, "shape"));
-                               CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+                               CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width"));
+                               CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width"));
+                               CData->psys_shape.push_back_slow(get_float(cpsys, "shape"));
+                               CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip"));
 
                                int pa_no = 0;
 
                                int pa_no = 0;
-                               if(!use_parents && !(b_psys.settings().child_type() == 0))
+                               if(!(b_part.child_type() == 0) && totchild != 0)
                                        pa_no = totparts;
 
                                        pa_no = totparts;
 
+                               int num_add = (totparts+totchild - pa_no);
+                               CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
+                               CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
+                               CData->curve_length.reserve(CData->curve_length.size() + num_add);
+                               CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
+                               CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
+
                                for(; pa_no < totparts+totchild; pa_no++) {
                                for(; pa_no < totparts+totchild; pa_no++) {
+                                       int keynum = 0;
+                                       CData->curve_firstkey.push_back_slow(keyno);
 
 
-                                       CData->curve_firstkey.push_back(keyno);
-                                       CData->curve_keynum.push_back(ren_step+1);
-                                       
                                        float curve_length = 0.0f;
                                        float3 pcKey;
                                        float curve_length = 0.0f;
                                        float3 pcKey;
-                                       for(int step_no = 0; step_no <= ren_step; step_no++) {
+                                       for(int step_no = 0; step_no < ren_step; step_no++) {
                                                float nco[3];
                                                float nco[3];
-                                               b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco);
-                                               float3 cKey = make_float3(nco[0],nco[1],nco[2]);
+                                               b_psys.co_hair(*b_ob, pa_no, step_no, nco);
+                                               float3 cKey = make_float3(nco[0], nco[1], nco[2]);
                                                cKey = transform_point(&itfm, cKey);
                                                cKey = transform_point(&itfm, cKey);
-                                               if(step_no > 0)
-                                                       curve_length += len(cKey - pcKey);
-                                               CData->curvekey_co.push_back(cKey);
-                                               CData->curvekey_time.push_back(curve_length);
+                                               if(step_no > 0) {
+                                                       float step_length = len(cKey - pcKey);
+                                                       if(step_length == 0.0f)
+                                                               continue;
+                                                       curve_length += step_length;
+                                               }
+                                               CData->curvekey_co.push_back_slow(cKey);
+                                               CData->curvekey_time.push_back_slow(curve_length);
                                                pcKey = cKey;
                                                pcKey = cKey;
-                                               keyno++;
+                                               keynum++;
                                        }
                                        }
-                                       CData->curve_length.push_back(curve_length);
+                                       keyno += keynum;
 
 
+                                       CData->curve_keynum.push_back_slow(keynum);
+                                       CData->curve_length.push_back_slow(curve_length);
                                        curvenum++;
                                        curvenum++;
-
                                }
                        }
                                }
                        }
-
                }
        }
 
        return true;
                }
        }
 
        return true;
-
 }
 
 }
 
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int uv_num)
+static bool ObtainCacheParticleUV(Mesh *mesh,
+                                  BL::Mesh *b_mesh,
+                                  BL::Object *b_ob,
+                                  ParticleCurveData *CData,
+                                  bool background,
+                                  int uv_num)
 {
 {
-#if 0
-       int keyno = 0;
-#endif
-
        if(!(mesh && b_mesh && b_ob && CData))
                return false;
 
        if(!(mesh && b_mesh && b_ob && CData))
                return false;
 
-#if 0
-       Transform tfm = get_transform(b_ob->matrix_world());
-       Transform itfm = transform_quick_inverse(tfm);
-#endif
-
        CData->curve_uv.clear();
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
        CData->curve_uv.clear();
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
-               if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
+               if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
-
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
-
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
-                       if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
-#if 0
-                               int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
-                               int shader = mesh->used_shaders[mi];
-#endif
-
+                       if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
                                int totparts = b_psys.particles.length();
                                int totparts = b_psys.particles.length();
-                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
+                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
                                int totcurves = totchild;
                                int totcurves = totchild;
-                               
-                               if (use_parents || b_psys.settings().child_type() == 0)
+
+                               if(b_part.child_type() == 0 || totchild == 0)
                                        totcurves += totparts;
 
                                        totcurves += totparts;
 
-                               if (totcurves == 0)
+                               if(totcurves == 0)
                                        continue;
 
                                int pa_no = 0;
                                        continue;
 
                                int pa_no = 0;
-                               if(!use_parents && !(b_psys.settings().child_type() == 0))
+                               if(!(b_part.child_type() == 0) && totchild != 0)
                                        pa_no = totparts;
 
                                        pa_no = totparts;
 
+                               int num_add = (totparts+totchild - pa_no);
+                               CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
+
                                BL::ParticleSystem::particles_iterator b_pa;
                                b_psys.particles.begin(b_pa);
                                for(; pa_no < totparts+totchild; pa_no++) {
                                BL::ParticleSystem::particles_iterator b_pa;
                                b_psys.particles.begin(b_pa);
                                for(; pa_no < totparts+totchild; pa_no++) {
-
-                                       /*add uvs*/
+                                       /* Add UVs */
                                        BL::Mesh::tessface_uv_textures_iterator l;
                                        b_mesh->tessface_uv_textures.begin(l);
 
                                        float3 uv = make_float3(0.0f, 0.0f, 0.0f);
                                        if(b_mesh->tessface_uv_textures.length())
                                                b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
                                        BL::Mesh::tessface_uv_textures_iterator l;
                                        b_mesh->tessface_uv_textures.begin(l);
 
                                        float3 uv = make_float3(0.0f, 0.0f, 0.0f);
                                        if(b_mesh->tessface_uv_textures.length())
                                                b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
-                                       CData->curve_uv.push_back(uv);
+                                       CData->curve_uv.push_back_slow(uv);
 
                                        if(pa_no < totparts && b_pa != b_psys.particles.end())
                                                ++b_pa;
 
                                        if(pa_no < totparts && b_pa != b_psys.particles.end())
                                                ++b_pa;
-
                                }
                        }
                                }
                        }
-
                }
        }
 
        return true;
                }
        }
 
        return true;
-
 }
 
 }
 
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, bool background, int vcol_num)
+static bool ObtainCacheParticleVcol(Mesh *mesh,
+                                    BL::Mesh *b_mesh,
+                                    BL::Object *b_ob,
+                                    ParticleCurveData *CData,
+                                    bool background,
+                                    int vcol_num)
 {
 {
-#if 0
-       int keyno = 0;
-#endif
        if(!(mesh && b_mesh && b_ob && CData))
                return false;
 
        if(!(mesh && b_mesh && b_ob && CData))
                return false;
 
-#if 0
-       Transform tfm = get_transform(b_ob->matrix_world());
-       Transform itfm = transform_quick_inverse(tfm);
-#endif
-
        CData->curve_vcol.clear();
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
        CData->curve_vcol.clear();
 
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
-               if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
+               if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
-
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
-
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
                        BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 
-                       if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
-#if 0
-                               int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
-                               int shader = mesh->used_shaders[mi];
-#endif
+                       if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
                                int totparts = b_psys.particles.length();
                                int totparts = b_psys.particles.length();
-                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_psys.settings().draw_percentage() / 100.0f);
+                               int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
                                int totcurves = totchild;
                                int totcurves = totchild;
-                               
-                               if (use_parents || b_psys.settings().child_type() == 0)
+
+                               if(b_part.child_type() == 0 || totchild == 0)
                                        totcurves += totparts;
 
                                        totcurves += totparts;
 
-                               if (totcurves == 0)
+                               if(totcurves == 0)
                                        continue;
 
                                int pa_no = 0;
                                        continue;
 
                                int pa_no = 0;
-                               if(!use_parents && !(b_psys.settings().child_type() == 0))
+                               if(!(b_part.child_type() == 0) && totchild != 0)
                                        pa_no = totparts;
 
                                        pa_no = totparts;
 
+                               int num_add = (totparts+totchild - pa_no);
+                               CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
+
                                BL::ParticleSystem::particles_iterator b_pa;
                                b_psys.particles.begin(b_pa);
                                for(; pa_no < totparts+totchild; pa_no++) {
                                BL::ParticleSystem::particles_iterator b_pa;
                                b_psys.particles.begin(b_pa);
                                for(; pa_no < totparts+totchild; pa_no++) {
-
-                                       /*add uvs*/
+                                       /* Add vertex colors */
                                        BL::Mesh::tessface_vertex_colors_iterator l;
                                        b_mesh->tessface_vertex_colors.begin(l);
 
                                        float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
                                        if(b_mesh->tessface_vertex_colors.length())
                                                b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
                                        BL::Mesh::tessface_vertex_colors_iterator l;
                                        b_mesh->tessface_vertex_colors.begin(l);
 
                                        float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
                                        if(b_mesh->tessface_vertex_colors.length())
                                                b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
-                                       CData->curve_vcol.push_back(vcol);
+                                       CData->curve_vcol.push_back_slow(vcol);
 
                                        if(pa_no < totparts && b_pa != b_psys.particles.end())
                                                ++b_pa;
 
                                        if(pa_no < totparts && b_pa != b_psys.particles.end())
                                                ++b_pa;
-
                                }
                        }
                                }
                        }
-
                }
        }
 
        return true;
                }
        }
 
        return true;
-
 }
 
 }
 
-void ToggleRender(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, BL::Scene *scene)
+static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
 {
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
 {
        BL::Object::modifiers_iterator b_mod;
        for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
-               if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
+               if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
                        BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
                        BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
-                       b_psys.ToggleRender(*scene, *b_ob);
+                       b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
                }
        }
 }
 
                }
        }
 }
 
-void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam)
+static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
+                                      float3 RotCam, bool is_ortho)
 {
        int vertexno = mesh->verts.size();
        int vertexindex = vertexno;
 {
        int vertexno = mesh->verts.size();
        int vertexindex = vertexno;
+       int numverts = 0, numtris = 0;
 
 
-       for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
-               for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+       /* compute and reserve size of arrays */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+                       numverts += 2 + (CData->curve_keynum[curve] - 1)*2;
+                       numtris += (CData->curve_keynum[curve] - 1)*2;
+               }
+       }
 
 
-                               int subv = 1;
-                               float3 xbasis;
+       mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
 
 
-                               float3 v1;
+       /* actually export */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-                               if(curvekey == CData->curve_firstkey[curve]) {
-                                       subv = 0;
-                                       v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey];
-                               }
-                               else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
-                                       v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])];
-                               else 
+                       float3 xbasis;
+                       float3 v1;
+                       float time = 0.0f;
+                       float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]];
+                       float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f);
+                       v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]];
+                       if(is_ortho)
+                               xbasis = normalize(cross(RotCam, v1));
+                       else
+                               xbasis = normalize(cross(RotCam - ickey_loc, v1));
+                       float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
+                       float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
+                       mesh->add_vertex(ickey_loc_shfl);
+                       mesh->add_vertex(ickey_loc_shfr);
+                       vertexindex += 2;
+
+                       for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
+                               ickey_loc = CData->curvekey_co[curvekey];
+
+                               if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
+                                       v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])];
+                               else
                                        v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
 
                                        v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1];
 
+                               time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
+                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
 
-                               for (; subv <= segments; subv++) {
+                               if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)
+                                       radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
 
 
-                                       float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
-                                       float time = 0.0f;
-
-                                       if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
-                                               ickey_loc = CData->curvekey_co[curvekey];
-                                       else
-                                               InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
-
-                                       float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
-
-                                       if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
-                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
+                               if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+                                       radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
 
 
-                                       if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
-                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
-
-                                       xbasis = normalize(cross(v1,RotCam - ickey_loc));
-                                       float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
-                                       float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
-                                       mesh->verts.push_back(ickey_loc_shfl);
-                                       mesh->verts.push_back(ickey_loc_shfr);
-                                       if(subv!=0) {
-                                               mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
-                                               mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
-                                       }
-                                       vertexindex += 2;
-                               }
+                               if(is_ortho)
+                                       xbasis = normalize(cross(RotCam, v1));
+                               else
+                                       xbasis = normalize(cross(RotCam - ickey_loc, v1));
+                               float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
+                               float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
+                               mesh->add_vertex(ickey_loc_shfl);
+                               mesh->add_vertex(ickey_loc_shfr);
+                               mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
+                               mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
+                               vertexindex += 2;
                        }
                }
        }
 
                        }
                }
        }
 
-       mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
+       mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles());
        mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
        mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
        mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
        mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
@@ -459,136 +421,40 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpo
        /* texture coords still needed */
 }
 
        /* texture coords still needed */
 }
 
-void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments)
+static void ExportCurveTriangleGeometry(Mesh *mesh,
+                                        ParticleCurveData *CData,
+                                        int resolution)
 {
        int vertexno = mesh->verts.size();
        int vertexindex = vertexno;
 {
        int vertexno = mesh->verts.size();
        int vertexindex = vertexno;
+       int numverts = 0, numtris = 0;
 
 
-       for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
-               for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
-
-                       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]]);
-                       if(len_squared(firstxbasis)!= 0.0f)
-                               firstxbasis = normalize(firstxbasis);
-                       else
-                               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]]));
-
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
-
-                               float3 xbasis = firstxbasis;
-                               float3 v1;
-                               float3 v2;
-
-                               if(curvekey == CData->curve_firstkey[curve]) {
-                                       v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
-                                       v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
-                               }
-                               else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
-                                       v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
-                                       v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
-                               }
-                               else {
-                                       v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
-                                       v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
-                               }
-
-                               xbasis = cross(v1,v2);
-
-                               if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
-                                       firstxbasis = normalize(xbasis);
-                                       break;
-                               }
-                       }
-
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
-
-                               int subv = 1;
-                               float3 v1;
-                               float3 v2;
-                               float3 xbasis;
-
-                               if(curvekey == CData->curve_firstkey[curve]) {
-                                       subv = 0;
-                                       v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1];
-                                       v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
-                               }
-                               else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) {
-                                       v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
-                                       v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])];
-                               }
-                               else {
-                                       v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey];
-                                       v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
-                               }
-
-                               xbasis = cross(v1,v2);
-
-                               if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
-                                       xbasis = normalize(xbasis);
-                                       firstxbasis = xbasis;
-                               }
-                               else
-                                       xbasis = firstxbasis;
-
-                               for (; subv <= segments; subv++) {
-
-                                       float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
-                                       float time = 0.0f;
-
-                                       if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
-                                               ickey_loc = CData->curvekey_co[curvekey];
-                                       else
-                                               InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
-
-                                       float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
-
-                                       if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
-                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
-
-                                       if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
-                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
+       /* compute and reserve size of arrays */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-                                       float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
-                                       float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
-                                       mesh->verts.push_back(ickey_loc_shfl);
-                                       mesh->verts.push_back(ickey_loc_shfr);
-                                       if(subv!=0) {
-                                               mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth);
-                                               mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth);
-                                       }
-                                       vertexindex += 2;
-                               }
-                       }
+                       numverts += (CData->curve_keynum[curve] - 1)*resolution + resolution;
+                       numtris += (CData->curve_keynum[curve] - 1)*2*resolution;
                }
        }
 
                }
        }
 
-       mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
-       mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
-       mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
-       mesh->add_face_normals();
-       mesh->add_vertex_normals();
-       mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
-       /* texture coords still needed */
-
-}
+       mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
 
 
-void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments)
-{
-       int vertexno = mesh->verts.size();
-       int vertexindex = vertexno;
-
-       for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
-               for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+       /* actually export */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
                        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]]);
 
                        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]]);
-                       if(len_squared(firstxbasis)!= 0.0f)
+                       if(!is_zero(firstxbasis))
                                firstxbasis = normalize(firstxbasis);
                        else
                                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]]));
 
                                firstxbasis = normalize(firstxbasis);
                        else
                                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]]));
 
-
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
-
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
                                float3 xbasis = firstxbasis;
                                float3 v1;
                                float3 v2;
                                float3 xbasis = firstxbasis;
                                float3 v1;
                                float3 v2;
@@ -606,7 +472,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
                                        v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
                                }
 
                                        v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
                                }
 
-                               xbasis = cross(v1,v2);
+                               xbasis = cross(v1, v2);
 
                                if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
                                        firstxbasis = normalize(xbasis);
 
                                if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
                                        firstxbasis = normalize(xbasis);
@@ -614,8 +480,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
                                }
                        }
 
                                }
                        }
 
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
-
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
                                int subv = 1;
                                float3 xbasis;
                                float3 ybasis;
                                int subv = 1;
                                float3 xbasis;
                                float3 ybasis;
@@ -636,7 +501,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
                                        v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
                                }
 
                                        v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1];
                                }
 
-                               xbasis = cross(v1,v2);
+                               xbasis = cross(v1, v2);
 
                                if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
                                        xbasis = normalize(xbasis);
 
                                if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) {
                                        xbasis = normalize(xbasis);
@@ -645,39 +510,35 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
                                else
                                        xbasis = firstxbasis;
 
                                else
                                        xbasis = firstxbasis;
 
-                               ybasis = normalize(cross(xbasis,v2));
-
-                               for (; subv <= segments; subv++) {
+                               ybasis = normalize(cross(xbasis, v2));
 
 
+                               for(; subv <= 1; subv++) {
                                        float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
                                        float time = 0.0f;
 
                                        float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
                                        float time = 0.0f;
 
-                                       if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
-                                               ickey_loc = CData->curvekey_co[curvekey];
-                                       else
-                                               InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+                                       InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData);
 
                                        float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
 
                                        float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
-                                       if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
-                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
-
-                                       if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments))
+                                       if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1))
                                                radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
 
                                                radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f);
 
-                                       float angle = 2 * M_PI_F / (float)resolution;
-                                       for(int section = 0 ; section < resolution; section++) {
+                                       if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
+                                               radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f);
+
+                                       float angle = M_2PI_F / (float)resolution;
+                                       for(int section = 0; section < resolution; section++) {
                                                float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
                                                float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
-                                               mesh->verts.push_back(ickey_loc_shf);
+                                               mesh->add_vertex(ickey_loc_shf);
                                        }
 
                                        }
 
-                                       if(subv!=0) {
-                                               for(int section = 0 ; section < resolution - 1; section++) {
-                                                       mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth);
-                                                       mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth);
+                                       if(subv != 0) {
+                                               for(int section = 0; section < resolution - 1; section++) {
+                                                       mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true);
+                                                       mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true);
                                                }
                                                }
-                                               mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth);
-                                               mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth);
+                                               mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true);
+                                               mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true);
                                        }
                                        vertexindex += resolution;
                                }
                                        }
                                        vertexindex += resolution;
                                }
@@ -685,7 +546,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
                }
        }
 
                }
        }
 
-       mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
+       mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles());
        mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
        mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
        mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
        mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
        mesh->add_face_normals();
@@ -695,212 +556,306 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int inter
        /* texture coords still needed */
 }
 
        /* texture coords still needed */
 }
 
-static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments)
+static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
 {
        int num_keys = 0;
        int num_curves = 0;
 
 {
        int num_keys = 0;
        int num_curves = 0;
 
-       if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
+       if(mesh->num_curves())
                return;
 
        Attribute *attr_intercept = NULL;
                return;
 
        Attribute *attr_intercept = NULL;
-       
+
        if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
                attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
 
        if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
                attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
 
-       for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
+       /* compute and reserve size of arrays */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-               if(CData->psys_curvenum[sys] == 0)
-                       continue;
+                       num_keys += CData->curve_keynum[curve];
+                       num_curves++;
+               }
+       }
+
+       if(num_curves > 0) {
+               VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
+       }
 
 
-               for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+       mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
 
 
-                       if(CData->curve_keynum[curve] <= 1)
+       num_keys = 0;
+       num_curves = 0;
+
+       /* actually export */
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
                                continue;
 
                        size_t num_curve_keys = 0;
 
                                continue;
 
                        size_t num_curve_keys = 0;
 
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
+                               float3 ickey_loc = CData->curvekey_co[curvekey];
+                               float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
+                               float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
 
-                               int subv = 1;
-                               if(curvekey == CData->curve_firstkey[curve])
-                                       subv = 0;
+                               if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+                                       radius = 0.0f;
 
 
-                               for (; subv <= segments; subv++) {
+                               mesh->add_curve_key(ickey_loc, radius);
+                               if(attr_intercept)
+                                       attr_intercept->add(time);
 
 
-                                       float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
-                                       float time = 0.0f;
+                               num_curve_keys++;
+                       }
 
 
-                                       if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0))
-                                               ickey_loc = CData->curvekey_co[curvekey];
-                                       else
-                                               InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
+                       mesh->add_curve(num_keys, CData->psys_shader[sys]);
+                       num_keys += num_curve_keys;
+                       num_curves++;
+               }
+       }
 
 
+       /* check allocation */
+       if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
+               VLOG(1) << "Allocation failed, clearing data";
+               mesh->clear();
+       }
+}
+
+static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
+{
+       VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
+               << ", time index " << time_index;
+
+       /* find attribute */
+       Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+       bool new_attribute = false;
+
+       /* add new attribute if it doesn't exist already */
+       if(!attr_mP) {
+               VLOG(1) << "Creating new motion vertex position attribute";
+               attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+               new_attribute = true;
+       }
+
+       /* export motion vectors for curve keys */
+       size_t numkeys = mesh->curve_keys.size();
+       float4 *mP = attr_mP->data_float4() + time_index*numkeys;
+       bool have_motion = false;
+       int i = 0;
+
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               if(CData->psys_curvenum[sys] == 0)
+                       continue;
+
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
+
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
+                               if(i < mesh->curve_keys.size()) {
+                                       float3 ickey_loc = CData->curvekey_co[curvekey];
+                                       float time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
                                        float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
                                        float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time);
 
-                                       if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2))
-                                               radius =0.0f;
+                                       if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
+                                               radius = 0.0f;
 
 
-                                       mesh->add_curve_key(ickey_loc, radius);
-                                       if(attr_intercept)
-                                               attr_intercept->add(time);
+                                       /* curve motion keys store both position and radius in float4 */
+                                       mP[i] = float3_to_float4(ickey_loc);
+                                       mP[i].w = radius;
 
 
-                                       num_curve_keys++;
+                                       /* unlike mesh coordinates, these tend to be slightly different
+                                        * between frames due to particle transforms into/out of object
+                                        * space, so we use an epsilon to detect actual changes */
+                                       float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
+                                       curve_key.w = mesh->curve_radius[i];
+                                       if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
+                                               have_motion = true;
                                }
                                }
-                       }
 
 
-                       mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
-                       num_keys += num_curve_keys;
-                       num_curves++;
+                               i++;
+                       }
                }
        }
 
                }
        }
 
-       /* check allocation*/
-       if((mesh->curve_keys.size() !=  num_keys) || (mesh->curves.size() !=  num_curves)) {
-               /* allocation failed -> clear data */
-               mesh->curve_keys.clear();
-               mesh->curves.clear();
-               mesh->curve_attributes.clear();
+       /* in case of new attribute, we verify if there really was any motion */
+       if(new_attribute) {
+               if(i != numkeys || !have_motion) {
+                       /* No motion or hair "topology" changed, remove attributes again. */
+                       if(i != numkeys) {
+                               VLOG(1) << "Hair topology changed, removing attribute.";
+                       }
+                       else {
+                               VLOG(1) << "No motion, removing attribute.";
+                       }
+                       mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+               }
+               else if(time_index > 0) {
+                       VLOG(1) << "Filling in new motion vertex position for time_index "
+                               << time_index;
+                       /* motion, fill up previous steps that we might have skipped because
+                        * they had no motion, but we need them anyway now */
+                       for(int step = 0; step < time_index; step++) {
+                               float4 *mP = attr_mP->data_float4() + step*numkeys;
+
+                               for(int key = 0; key < numkeys; key++) {
+                                       mP[key] = float3_to_float4(mesh->curve_keys[key]);
+                                       mP[key].w = mesh->curve_radius[key];
+                               }
+                       }
+               }
        }
 }
 
        }
 }
 
-void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol)
+static void ExportCurveTriangleUV(ParticleCurveData *CData,
+                                  int vert_offset,
+                                  int resol,
+                                  float3 *uvdata)
 {
 {
+       if(uvdata == NULL)
+               return;
+
        float time = 0.0f;
        float prevtime = 0.0f;
 
        float time = 0.0f;
        float prevtime = 0.0f;
 
-       Attribute *attr = mesh->attributes.find(ATTR_STD_UV);
-       if (attr == NULL)
-               return;
-               
-       float3 *uvdata = attr->data_float3();
-
        int vertexindex = vert_offset;
 
        int vertexindex = vert_offset;
 
-       for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
-               for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) {
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-                       for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+                               time = CData->curvekey_time[curvekey]/CData->curve_length[curve];
+
+                               for(int section = 0; section < resol; section++) {
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = prevtime;
+                                       vertexindex++;
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = time;
+                                       vertexindex++;
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = prevtime;
+                                       vertexindex++;
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = time;
+                                       vertexindex++;
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = prevtime;
+                                       vertexindex++;
+                                       uvdata[vertexindex] = CData->curve_uv[curve];
+                                       uvdata[vertexindex].z = time;
+                                       vertexindex++;
+                               }
 
 
-                               int subv = 1;
+                               prevtime = time;
+                       }
+               }
+       }
+}
 
 
-                               if (curvekey == CData->curve_firstkey[curve])
-                                       subv = 0;
-                               
-                               for (; subv <= segments; subv++) {
+static void ExportCurveTriangleVcol(ParticleCurveData *CData,
+                                    int vert_offset,
+                                    int resol,
+                                    uchar4 *cdata)
+{
+       if(cdata == NULL)
+               return;
 
 
-                                       float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
+       int vertexindex = vert_offset;
 
 
-                                       InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation);
-
-                                       if(subv!=0) {
-                                               for(int section = 0 ; section < resol; section++) {
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = prevtime;
-                                                       vertexindex++;
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = time;
-                                                       vertexindex++;
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = prevtime;
-                                                       vertexindex++;
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = time;
-                                                       vertexindex++;
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = prevtime;
-                                                       vertexindex++;
-                                                       uvdata[vertexindex] = CData->curve_uv[curve];
-                                                       uvdata[vertexindex].z = time;
-                                                       vertexindex++;
-                                               }
-                                       }
+       for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) {
+               for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) {
+                       if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f)
+                               continue;
 
 
-                                       prevtime = time;
+                       for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) {
+                               for(int section = 0; section < resol; section++) {
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
+                                       cdata[vertexindex] = color_float_to_byte(color_srgb_to_scene_linear_v3(CData->curve_vcol[curve]));
+                                       vertexindex++;
                                }
                        }
                }
        }
                                }
                        }
                }
        }
-
 }
 }
+
 /* Hair Curve Sync */
 
 void BlenderSync::sync_curve_settings()
 {
        PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
 /* Hair Curve Sync */
 
 void BlenderSync::sync_curve_settings()
 {
        PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");
-       
-       int preset = get_enum(csscene, "preset");
 
        CurveSystemManager *curve_system_manager = scene->curve_system_manager;
        CurveSystemManager prev_curve_system_manager = *curve_system_manager;
 
        curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
 
        CurveSystemManager *curve_system_manager = scene->curve_system_manager;
        CurveSystemManager prev_curve_system_manager = *curve_system_manager;
 
        curve_system_manager->use_curves = get_boolean(csscene, "use_curves");
-
-       if(preset == CURVE_CUSTOM) {
-               /*custom properties*/
-               curve_system_manager->primitive = get_enum(csscene, "primitive");
-               curve_system_manager->line_method = get_enum(csscene, "line_method");
-               curve_system_manager->interpolation = get_enum(csscene, "interpolation");
-               curve_system_manager->triangle_method = get_enum(csscene, "triangle_method");
-               curve_system_manager->resolution = get_int(csscene, "resolution");
-               curve_system_manager->segments = get_int(csscene, "segments");
-               curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth");
-               curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
-
-               curve_system_manager->normalmix = get_float(csscene, "normalmix");
-               curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio");
-
-               curve_system_manager->use_parents = get_boolean(csscene, "use_parents");
-               curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing");
-               curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing");
-               curve_system_manager->use_joined = get_boolean(csscene, "use_joined");
-               curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal");
-               curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry");
-               curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction");
+       curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
+       curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
+
+       curve_system_manager->primitive =
+               (CurvePrimitiveType)get_enum(csscene,
+                                            "primitive",
+                                            CURVE_NUM_PRIMITIVE_TYPES,
+                                            CURVE_LINE_SEGMENTS);
+       curve_system_manager->curve_shape =
+               (CurveShapeType)get_enum(csscene,
+                                        "shape",
+                                        CURVE_NUM_SHAPE_TYPES,
+                                        CURVE_THICK);
+       curve_system_manager->resolution = get_int(csscene, "resolution");
+       curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
+       curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
+
+       /* Triangles */
+       if(curve_system_manager->primitive == CURVE_TRIANGLES) {
+               /* camera facing planes */
+               if(curve_system_manager->curve_shape == CURVE_RIBBON) {
+                       curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
+                       curve_system_manager->resolution = 1;
+               }
+               else if(curve_system_manager->curve_shape == CURVE_THICK) {
+                       curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
+               }
        }
        }
-       else {
-               curve_system_manager->primitive = CURVE_LINE_SEGMENTS;
-               curve_system_manager->interpolation = CURVE_CARDINAL;
-               curve_system_manager->normalmix = 1.0f;
-               curve_system_manager->encasing_ratio = 1.01f;
-               curve_system_manager->use_parents = false;
-               curve_system_manager->segments = 1;
-               curve_system_manager->use_joined = false;
-
-               switch(preset) {
-                       case CURVE_TANGENT_SHADING:
-                               /*tangent shading*/
-                               curve_system_manager->line_method = CURVE_UNCORRECTED;
-                               curve_system_manager->use_encasing = true;
-                               curve_system_manager->use_backfacing = false;
-                               curve_system_manager->use_tangent_normal = true;
-                               curve_system_manager->use_tangent_normal_geometry = true;
-                               curve_system_manager->use_tangent_normal_correction = false;
-                               break;
-                       case CURVE_TRUE_NORMAL:
-                               /*True Normal*/
-                               curve_system_manager->line_method = CURVE_CORRECTED;
-                               curve_system_manager->use_encasing = true;
-                               curve_system_manager->use_backfacing = false;
-                               curve_system_manager->use_tangent_normal = false;
-                               curve_system_manager->use_tangent_normal_geometry = false;
-                               curve_system_manager->use_tangent_normal_correction = false;
-                               break;
-                       case CURVE_ACCURATE_PRESET:
-                               /*Accurate*/
-                               curve_system_manager->line_method = CURVE_ACCURATE;
-                               curve_system_manager->use_encasing = false;
-                               curve_system_manager->use_backfacing = true;
-                               curve_system_manager->use_tangent_normal = false;
-                               curve_system_manager->use_tangent_normal_geometry = false;
-                               curve_system_manager->use_tangent_normal_correction = false;
-                               break;
+       /* Line Segments */
+       else if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS) {
+               if(curve_system_manager->curve_shape == CURVE_RIBBON) {
+                       /* tangent shading */
+                       curve_system_manager->line_method = CURVE_UNCORRECTED;
+                       curve_system_manager->use_encasing = true;
+                       curve_system_manager->use_backfacing = false;
+                       curve_system_manager->use_tangent_normal_geometry = true;
+               }
+               else if(curve_system_manager->curve_shape == CURVE_THICK) {
+                       curve_system_manager->line_method = CURVE_ACCURATE;
+                       curve_system_manager->use_encasing = false;
+                       curve_system_manager->use_tangent_normal_geometry = false;
+               }
+       }
+       /* Curve Segments */
+       else if(curve_system_manager->primitive == CURVE_SEGMENTS) {
+               if(curve_system_manager->curve_shape == CURVE_RIBBON) {
+                       curve_system_manager->primitive = CURVE_RIBBONS;
+                       curve_system_manager->use_backfacing = false;
                }
                }
-               
        }
 
        }
 
-       if(curve_system_manager->modified_mesh(prev_curve_system_manager))
-       {
+       if(curve_system_manager->modified_mesh(prev_curve_system_manager)) {
                BL::BlendData::objects_iterator b_ob;
 
                for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
                BL::BlendData::objects_iterator b_ob;
 
                for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
@@ -919,166 +874,192 @@ void BlenderSync::sync_curve_settings()
 
        if(curve_system_manager->modified(prev_curve_system_manager))
                curve_system_manager->tag_update(scene);
 
        if(curve_system_manager->modified(prev_curve_system_manager))
                curve_system_manager->tag_update(scene);
-
 }
 
 }
 
-void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated)
+void BlenderSync::sync_curves(Mesh *mesh,
+                              BL::Mesh& b_mesh,
+                              BL::Object& b_ob,
+                              bool motion,
+                              int time_index)
 {
 {
-       /* Clear stored curve data */
-       mesh->curve_keys.clear();
-       mesh->curves.clear();
-       mesh->curve_attributes.clear();
+       if(!motion) {
+               /* Clear stored curve data */
+               mesh->curve_keys.clear();
+               mesh->curve_radius.clear();
+               mesh->curve_first_key.clear();
+               mesh->curve_shader.clear();
+               mesh->curve_attributes.clear();
+       }
 
        /* obtain general settings */
 
        /* obtain general settings */
-       bool use_curves = scene->curve_system_manager->use_curves;
+       const bool use_curves = scene->curve_system_manager->use_curves;
 
 
-       if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) {
-               mesh->compute_bounds();
+       if(!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) {
+               if(!motion)
+                       mesh->compute_bounds();
                return;
        }
 
                return;
        }
 
-       int primitive = scene->curve_system_manager->primitive;
-       int interpolation = scene->curve_system_manager->interpolation;
-       int triangle_method = scene->curve_system_manager->triangle_method;
-       int resolution = scene->curve_system_manager->resolution;
-       int segments = scene->curve_system_manager->segments;
-       bool use_smooth = scene->curve_system_manager->use_smooth;
-       bool use_parents = scene->curve_system_manager->use_parents;
-       bool export_tgs = scene->curve_system_manager->use_joined;
+       const int primitive = scene->curve_system_manager->primitive;
+       const int triangle_method = scene->curve_system_manager->triangle_method;
+       const int resolution = scene->curve_system_manager->resolution;
+       const size_t vert_num = mesh->verts.size();
+       const size_t tri_num = mesh->num_triangles();
+       int used_res = 1;
 
        /* extract particle hair data - should be combined with connecting to mesh later*/
 
        ParticleCurveData CData;
 
        if(!preview)
 
        /* extract particle hair data - should be combined with connecting to mesh later*/
 
        ParticleCurveData CData;
 
        if(!preview)
-               ToggleRender(mesh, &b_mesh, &b_ob, &b_scene);
-
-       ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview);
-
-       /* attach strands to mesh */
-       BL::Object b_CamOb = b_scene.camera();
-       float3 RotCam = make_float3(0.0f, 0.0f, 0.0f);
-       if(b_CamOb) {
-               Transform ctfm = get_transform(b_CamOb.matrix_world());
-               Transform tfm = get_transform(b_ob.matrix_world());
-               Transform itfm = transform_quick_inverse(tfm);
-               RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
-       }
+               set_resolution(&b_ob, &b_scene, true);
 
 
-       if(primitive == CURVE_TRIANGLES){
-               int vert_num = mesh->triangles.size() * 3;
-               ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview, 0);
+       ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
+
+       /* add hair geometry to mesh */
+       if(primitive == CURVE_TRIANGLES) {
                if(triangle_method == CURVE_CAMERA_TRIANGLES) {
                if(triangle_method == CURVE_CAMERA_TRIANGLES) {
-                       ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
-                       ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
-               }
-               else if(triangle_method == CURVE_RIBBON_TRIANGLES) {
-                       ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
-                       ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
+                       /* obtain camera parameters */
+                       float3 RotCam;
+                       Camera *camera = scene->camera;
+                       Transform &ctfm = camera->matrix;
+                       if(camera->type == CAMERA_ORTHOGRAPHIC) {
+                               RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
+                       }
+                       else {
+                               Transform tfm = get_transform(b_ob.matrix_world());
+                               Transform itfm = transform_quick_inverse(tfm);
+                               RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
+                                                                           ctfm.y.w,
+                                                                           ctfm.z.w));
+                       }
+                       bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
+                       ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
                }
                else {
                }
                else {
-                       ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments);
-                       ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, resolution);
+                       ExportCurveTriangleGeometry(mesh, &CData, resolution);
+                       used_res = resolution;
                }
                }
-
        }
        else {
        }
        else {
-               ExportCurveSegments(scene, mesh, &CData, interpolation, segments);
-               int ckey_num = mesh->curve_keys.size();
-
-               /*export tangents or curve data? - not functional yet*/
-               if(export_tgs && ckey_num > 1) {
-                       Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT);
-                       float3 *data_tangent = attr_tangent->data_float3();
-                       
-                       for(int ck = 0; ck < ckey_num; ck++) {
-                               float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) -
-                                       normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co));
-                               
-                               data_tangent[ck] = tg;
-                       }
-               }
+               if(motion)
+                       ExportCurveSegmentsMotion(mesh, &CData, time_index);
+               else
+                       ExportCurveSegments(scene, mesh, &CData);
+       }
+
+       /* generated coordinates from first key. we should ideally get this from
+        * blender to handle deforming objects */
+       if(!motion) {
+               if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
+                       float3 loc, size;
+                       mesh_texture_space(b_mesh, loc, size);
 
 
-               /* generated coordinates from first key. we should ideally get this from
-                * blender to handle deforming objects */
-               {
-                       if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
-                               float3 loc, size;
-                               mesh_texture_space(b_mesh, loc, size);
+                       if(primitive == CURVE_TRIANGLES) {
+                               Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED);
+                               float3 *generated = attr_generated->data_float3();
 
 
+                               for(size_t i = vert_num; i < mesh->verts.size(); i++)
+                                       generated[i] = mesh->verts[i]*size - loc;
+                       }
+                       else {
                                Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
                                float3 *generated = attr_generated->data_float3();
                                Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
                                float3 *generated = attr_generated->data_float3();
-                               size_t i = 0;
 
 
-                               foreach(Mesh::Curve& curve, mesh->curves) {
-                                       float3 co = mesh->curve_keys[curve.first_key].co;
-                                       generated[i++] = co*size - loc;
+                               for(size_t i = 0; i < mesh->num_curves(); i++) {
+                                       float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
+                                       generated[i] = co*size - loc;
                                }
                        }
                }
                                }
                        }
                }
+       }
 
 
-               /* create vertex color attributes */
-               {
-                       BL::Mesh::tessface_vertex_colors_iterator l;
-                       int vcol_num = 0;
+       /* create vertex color attributes */
+       if(!motion) {
+               BL::Mesh::tessface_vertex_colors_iterator l;
+               int vcol_num = 0;
 
 
-                       for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
-                               if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
-                                       continue;
+               for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
+                       if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
+                               continue;
+
+                       ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
+
+                       if(primitive == CURVE_TRIANGLES) {
+                               Attribute *attr_vcol = mesh->attributes.add(
+                                       ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
 
 
+                               uchar4 *cdata = attr_vcol->data_uchar4();
+
+                               ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
+                       }
+                       else {
                                Attribute *attr_vcol = mesh->curve_attributes.add(
                                        ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
 
                                Attribute *attr_vcol = mesh->curve_attributes.add(
                                        ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
 
-                               ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview, vcol_num);
+                               float3 *fdata = attr_vcol->data_float3();
 
 
-                               float3 *vcol = attr_vcol->data_float3();
+                               if(fdata) {
+                                       size_t i = 0;
 
 
-                               if(vcol) {
-                                       for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
-                                               vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
+                                       for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
+                                               if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
+                                                       fdata[i++] = color_srgb_to_scene_linear_v3(CData.curve_vcol[curve]);
                                }
                        }
                }
                                }
                        }
                }
+       }
+
+       /* create UV attributes */
+       if(!motion) {
+               BL::Mesh::tessface_uv_textures_iterator l;
+               int uv_num = 0;
 
 
-               /* create uv map attributes */
-               {
-                       BL::Mesh::tessface_uv_textures_iterator l;
-                       int uv_num = 0;
+               for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
+                       bool active_render = l->active_render();
+                       AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+                       ustring name = ustring(l->name().c_str());
 
 
-                       for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
-                               bool active_render = l->active_render();
-                               AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
-                               ustring name = ustring(l->name().c_str());
+                       /* UV map */
+                       if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
+                               Attribute *attr_uv;
 
 
-                               /* UV map */
-                               if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
-                                       Attribute *attr;
+                               ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
 
 
+                               if(primitive == CURVE_TRIANGLES) {
                                        if(active_render)
                                        if(active_render)
-                                               attr = mesh->curve_attributes.add(std, name);
+                                               attr_uv = mesh->attributes.add(std, name);
                                        else
                                        else
-                                               attr = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
+                                               attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
 
 
-                                       ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, !preview, uv_num);
+                                       float3 *uv = attr_uv->data_float3();
 
 
-                                       float3 *uv = attr->data_float3();
+                                       ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
+                               }
+                               else {
+                                       if(active_render)
+                                               attr_uv = mesh->curve_attributes.add(std, name);
+                                       else
+                                               attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
+
+                                       float3 *uv = attr_uv->data_float3();
 
                                        if(uv) {
 
                                        if(uv) {
-                                               for(size_t curve = 0; curve < CData.curve_uv.size() ;curve++)
-                                                       uv[curve] = CData.curve_uv[curve];
+                                               size_t i = 0;
+
+                                               for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
+                                                       if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
+                                                               uv[i++] = CData.curve_uv[curve];
                                        }
                                        }
-                               }                       
+                               }
                        }
                }
                        }
                }
-
        }
 
        if(!preview)
        }
 
        if(!preview)
-               ToggleRender(mesh, &b_mesh, &b_ob, &b_scene);
+               set_resolution(&b_ob, &b_scene, false);
 
        mesh->compute_bounds();
 }
 
 
        mesh->compute_bounds();
 }
 
-
 CCL_NAMESPACE_END
 CCL_NAMESPACE_END
-