diff options
Diffstat (limited to 'scene/resources/mesh.cpp')
-rw-r--r-- | scene/resources/mesh.cpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 3aeccdc551..f4bb3088c3 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -743,6 +743,225 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { } +Ref<Mesh> Mesh::create_outline(float p_margin) const { + + + Array arrays; + int index_accum=0; + for(int i=0;i<get_surface_count();i++) { + + if (surface_get_primitive_type(i)!=PRIMITIVE_TRIANGLES) + continue; + + Array a = surface_get_arrays(i); + int vcount=0; + + if (i==0) { + arrays=a; + DVector<Vector3> v=a[ARRAY_VERTEX]; + index_accum+=v.size(); + } else { + + for(int j=0;j<arrays.size();j++) { + + if (arrays[j].get_type()==Variant::NIL || a[j].get_type()==Variant::NIL) { + //mismatch, do not use + arrays[j]=Variant(); + continue; + } + + switch(j) { + + case ARRAY_VERTEX: + case ARRAY_NORMAL: { + + DVector<Vector3> dst = arrays[j]; + DVector<Vector3> src = a[j]; + if (j==ARRAY_VERTEX) + vcount=src.size(); + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + } break; + case ARRAY_TANGENT: + case ARRAY_BONES: + case ARRAY_WEIGHTS: { + + DVector<real_t> dst = arrays[j]; + DVector<real_t> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_COLOR: { + DVector<Color> dst = arrays[j]; + DVector<Color> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_TEX_UV: + case ARRAY_TEX_UV2: { + DVector<Vector2> dst = arrays[j]; + DVector<Vector2> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_INDEX: { + DVector<int> dst = arrays[j]; + DVector<int> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + { + int ss = src.size(); + DVector<int>::Write w = src.write(); + for(int k=0;k<ss;k++) { + w[k]+=index_accum; + } + + } + dst.append_array(src); + arrays[j]=dst; + index_accum+=vcount; + + } break; + + } + } + } + } + + { + int tc=0; + DVector<int>::Write ir; + DVector<int> indices =arrays[ARRAY_INDEX]; + bool has_indices=false; + DVector<Vector3> vertices =arrays[ARRAY_VERTEX]; + int vc = vertices.size(); + ERR_FAIL_COND_V(!vc,Ref<Mesh>()); + DVector<Vector3>::Write r=vertices.write(); + + + if (indices.size()) { + vc=indices.size(); + ir=indices.write(); + has_indices=true; + } + + Map<Vector3,Vector3> normal_accum; + + //fill normals with triangle normals + for(int i=0;i<vc;i+=3) { + + + Vector3 t[3]; + + if (has_indices) { + t[0]=r[ir[i+0]]; + t[1]=r[ir[i+1]]; + t[2]=r[ir[i+2]]; + } else { + t[0]=r[i+0]; + t[1]=r[i+1]; + t[2]=r[i+2]; + } + + Vector3 n = Plane(t[0],t[1],t[2]).normal; + + for(int j=0;j<3;j++) { + + Map<Vector3,Vector3>::Element *E=normal_accum.find(t[j]); + if (!E) { + normal_accum[t[j]]=n; + } else { + float d = n.dot(E->get()); + if (d<1.0) + E->get()+=n*(1.0-d); + //E->get()+=n; + } + } + } + + //normalize + + for (Map<Vector3,Vector3>::Element *E=normal_accum.front();E;E=E->next()) { + E->get().normalize(); + } + + + //displace normals + int vc2 = vertices.size(); + + for(int i=0;i<vc2;i++) { + + + Vector3 t=r[i]; + + Map<Vector3,Vector3>::Element *E=normal_accum.find(t); + ERR_CONTINUE(!E); + + t+=E->get()*p_margin; + r[i]=t; + } + + r = DVector<Vector3>::Write(); + arrays[ARRAY_VERTEX]=vertices; + + if (!has_indices) { + + DVector<int> new_indices; + new_indices.resize(vertices.size()); + DVector<int>::Write iw = new_indices.write(); + + for(int j=0;j<vc2;j+=3) { + + iw[j]=j; + iw[j+1]=j+2; + iw[j+2]=j+1; + } + + iw=DVector<int>::Write(); + arrays[ARRAY_INDEX]=new_indices; + + } else { + + for(int j=0;j<vc;j+=3) { + + SWAP(ir[j+1],ir[j+2]); + } + ir=DVector<int>::Write(); + arrays[ARRAY_INDEX]=indices; + + } + } + + + + + Ref<Mesh> newmesh = memnew( Mesh ); + newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays); + return newmesh; +} + + void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_morph_target","name"),&Mesh::add_morph_target); |