diff options
Diffstat (limited to 'intern/cycles/blender/blender_curves.cpp')
-rw-r--r-- | intern/cycles/blender/blender_curves.cpp | 1130 |
1 files changed, 1130 insertions, 0 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp new file mode 100644 index 00000000000..4fad7d45162 --- /dev/null +++ b/intern/cycles/blender/blender_curves.cpp @@ -0,0 +1,1130 @@ +/* + * Copyright 2011, 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. + * + * 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. + * + * 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. + */ + +#include "attribute.h" +#include "mesh.h" +#include "object.h" +#include "scene.h" +#include "curves.h" + +#include "blender_sync.h" +#include "blender_util.h" + +#include "util_foreach.h" + +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); +bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData); +bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents); +bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num); +bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents); +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() +{ + 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) +{ + 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; + } +} + +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]; +} + +float shaperadius(float shape, float root, float tip, float time) +{ + float radius = 1.0f - time; + if(shape != 0.0f) { + if(shape < 0.0f) + radius = (float)pow(1.0f - time, 1.f + shape); + else + radius = (float)pow(1.0f - time, 1.f / (1.f - shape)); + } + 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) +{ + float3 ckey_loc1 = CData->curvekey_co[key]; + float3 ckey_loc2 = ckey_loc1; + float3 ckey_loc3 = CData->curvekey_co[key+1]; + float3 ckey_loc4 = ckey_loc3; + + if(key > CData->curve_firstkey[curve]) + ckey_loc1 = CData->curvekey_co[key - 1]; + + 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 dfra = (time2 - time1) / (float)segno; + + if(time) + *time = (dfra * seg) + time1; + + float t[4]; + + interp_weights((float)seg / (float)segno, t, interpolation); + + if(keyloc) + curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); +} + +bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData) +{ + + int curvenum = 0; + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + 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())) { + + BL::ParticleSystemModifier psmd(b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().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 totcurves = b_psys.particles.length(); + + if(totcurves == 0) + continue; + + 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); + + 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")); + + BL::ParticleSystem::particles_iterator b_pa; + for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) { + CData->curve_firstkey.push_back(keyno); + + int keylength = b_pa->hair_keys.length(); + CData->curve_keynum.push_back(keylength); + + float curve_length = 0.0f; + float3 pcKey; + int step_no = 0; + BL::Particle::hair_keys_iterator b_cKey; + for(b_pa->hair_keys.begin(b_cKey); b_cKey != b_pa->hair_keys.end(); ++b_cKey) { + float nco[3]; + b_cKey->co_object( *b_ob, psmd, *b_pa, nco); + float3 cKey = make_float3(nco[0],nco[1],nco[2]); + if(step_no > 0) + curve_length += len(cKey - pcKey); + CData->curvekey_co.push_back(cKey); + CData->curvekey_time.push_back(curve_length); + pcKey = cKey; + keyno++; + step_no++; + } + + CData->curve_length.push_back(curve_length); + /*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_pa->uv_on_emitter(psmd,&uv.x); + CData->curve_uv.push_back(uv); + + curvenum++; + + } + } + } + } + + return true; + +} + +bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents) +{ + + int curvenum = 0; + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().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 = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if(use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if(totcurves == 0) + continue; + + 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); + + 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")); + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + for(; pa_no < totparts+totchild; pa_no++) { + + CData->curve_firstkey.push_back(keyno); + CData->curve_keynum.push_back(ren_step+1); + + float curve_length = 0.0f; + float3 pcKey; + for(int step_no = 0; step_no <= ren_step; step_no++) { + 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]); + 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); + pcKey = cKey; + keyno++; + } + CData->curve_length.push_back(curve_length); + + curvenum++; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().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 = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*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.x); + CData->curve_uv.push_back(uv); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().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 = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*add uvs*/ + 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); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam) +{ + 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++) { + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 xbasis; + + float3 v1; + + 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 + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; + + + 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); + + 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; + } + } + } + } + + 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 */ +} + +void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, 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++) { + + 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); + + 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; + } + } + } + } + + 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 */ + +} + +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++) { + + 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 xbasis; + float3 ybasis; + float3 v1; + float3 v2; + + 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; + + ybasis = normalize(cross(xbasis,v2)); + + 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); + + float angle = 2 * M_PI_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); + mesh->verts.push_back(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); + } + 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); + } + vertexindex += 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 */ +} + +static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments) +{ + int num_keys = 0; + int num_curves = 0; + + if(!(mesh->curves.empty() && mesh->curve_keys.empty())) + return; + + Attribute *attr_uv = NULL, *attr_intercept = NULL; + + if(mesh->need_attribute(scene, ATTR_STD_UV)) + attr_uv = mesh->curve_attributes.add(ATTR_STD_UV); + 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++) { + + 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) + 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++) { + + int subv = 1; + if(curvekey == CData->curve_firstkey[curve]) + subv = 0; + + 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] - 2)) + radius =0.0f; + + mesh->add_curve_key(ickey_loc, radius); + if(attr_intercept) + attr_intercept->add(time); + + num_curve_keys++; + } + } + + mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]); + if(attr_uv) + attr_uv->add(CData->curve_uv[curve]); + + num_keys += num_curve_keys; + num_curves++; + } + } + + /* 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(); + } +} + +void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol) +{ + 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; + + 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 curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + + if (curvekey == CData->curve_firstkey[curve]) + subv = 0; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + + 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++; + } + } + + prevtime = time; + } + } + } + } + +} +/* 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"); + + 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->normalmix = get_float(csscene, "normalmix"); + curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio"); + + curve_system_manager->use_cache = get_boolean(csscene, "use_cache"); + 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"); + } + 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_cache = true; + 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; + } + + } + + 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) { + if(object_is_mesh(*b_ob)) { + BL::Object::particle_systems_iterator b_psys; + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { + if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) { + BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data(); + mesh_map.set_recalc(key); + object_map.set_recalc(*b_ob); + } + } + } + } + } + + 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) +{ + /* Clear stored curve data */ + mesh->curve_keys.clear(); + mesh->curves.clear(); + mesh->curve_attributes.clear(); + + /* obtain general settings */ + bool use_curves = scene->curve_system_manager->use_curves; + + if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) { + mesh->compute_bounds(); + 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_cache = scene->curve_system_manager->use_cache; + bool use_parents = scene->curve_system_manager->use_parents; + bool export_tgs = scene->curve_system_manager->use_joined; + + /* extract particle hair data - should be combined with connecting to mesh later*/ + + ParticleCurveData CData; + + if(use_cache) { + ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents); + ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents); + } + else + ObtainParticleData(mesh, &b_mesh, &b_ob, &CData); + + /* 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)); + } + + if(primitive == CURVE_TRIANGLES){ + int vert_num = mesh->triangles.size() * 3; + if(triangle_method == CURVE_CAMERA) { + ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else if(triangle_method == CURVE_RIBBONS) { + ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else { + ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, resolution); + } + + } + 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; + } + } + + /* 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); + + 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; + } + } + + /* create vertex color attributes */ + 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; + + /*error occurs with more than one vertex colour attribute so avoided*/ + if(vcol_num!=0) + break; + + 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, 0); + + float3 *vcol = attr_vcol->data_float3(); + + if(vcol) { + for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++) + vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]); + } + + } + + } + + mesh->compute_bounds(); +} + + +CCL_NAMESPACE_END + |