summaryrefslogtreecommitdiffstats
path: root/scene/resources/surface_tool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/surface_tool.cpp')
-rw-r--r--scene/resources/surface_tool.cpp441
1 files changed, 298 insertions, 143 deletions
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index d0c159e9f0..2856101674 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -32,57 +32,56 @@
#define EQ_VERTEX_DIST 0.00001
+bool SurfaceTool::Vertex::operator==(const Vertex& p_b) const {
-bool SurfaceTool::compare(const Vertex& p_a,const Vertex& p_b) const {
- if (p_a.vertex.distance_to(p_b.vertex)>EQ_VERTEX_DIST)
+ if (vertex!=p_b.vertex)
return false;
- if (format&Mesh::ARRAY_FORMAT_TEX_UV) {
+ if (uv!=p_b.uv)
+ return false;
- if (p_a.uv.distance_to(p_b.uv)>EQ_VERTEX_DIST)
- return false;
- }
+ if (uv2!=p_b.uv2)
+ return false;
- if (format&Mesh::ARRAY_FORMAT_TEX_UV2) {
+ if (normal!=p_b.normal)
+ return false;
- if (p_a.uv2.distance_to(p_b.uv2)>EQ_VERTEX_DIST)
- return false;
- }
+ if (binormal!=p_b.binormal)
+ return false;
- if (format&Mesh::ARRAY_FORMAT_NORMAL) {
- if (p_a.normal.distance_to(p_b.normal)>EQ_VERTEX_DIST)
- return false;
- }
+ if (color!=p_b.color)
+ return false;
- if (format&Mesh::ARRAY_FORMAT_TANGENT) {
- if (p_a.binormal.distance_to(p_b.binormal)>EQ_VERTEX_DIST)
- return false;
- if (p_a.tangent.distance_to(p_b.tangent)>EQ_VERTEX_DIST)
+ if (bones.size()!=p_b.bones.size())
+ return false;
+
+ for(int i=0;i<bones.size();i++) {
+ if (bones[i]!=p_b.bones[i])
return false;
}
- if (format&Mesh::ARRAY_FORMAT_COLOR) {
- if (p_a.color!=p_b.color)
+ for(int i=0;i<weights.size();i++) {
+ if (weights[i]!=p_b.weights[i])
return false;
}
- if (format&Mesh::ARRAY_FORMAT_BONES) {
- for(int i=0;i<4;i++) {
- if (Math::abs(p_a.bones[i]-p_b.bones[i])>CMP_EPSILON)
- return false;
- }
- }
+ return true;
+}
- if (format&Mesh::ARRAY_FORMAT_WEIGHTS) {
- for(int i=0;i<4;i++) {
- if (Math::abs(p_a.weights[i]-p_b.weights[i])>CMP_EPSILON)
- return false;
- }
- }
+uint32_t SurfaceTool::VertexHasher::hash(const Vertex &p_vtx) {
- return true;
+ uint32_t h = hash_djb2_buffer((const uint8_t*)&p_vtx.vertex,sizeof(real_t)*3);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.normal,sizeof(real_t)*3,h);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.binormal,sizeof(real_t)*3,h);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.tangent,sizeof(real_t)*3,h);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.uv,sizeof(real_t)*2,h);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.uv2,sizeof(real_t)*2,h);
+ h = hash_djb2_buffer((const uint8_t*)&p_vtx.color,sizeof(real_t)*4,h);
+ h = hash_djb2_buffer((const uint8_t*)p_vtx.bones.ptr(),p_vtx.bones.size()*sizeof(int),h);
+ h = hash_djb2_buffer((const uint8_t*)p_vtx.weights.ptr(),p_vtx.weights.size()*sizeof(float),h);
+ return h;
}
void SurfaceTool::begin(Mesh::PrimitiveType p_primitive) {
@@ -186,6 +185,17 @@ void SurfaceTool::add_weights( const Vector<float>& p_weights) {
}
+void SurfaceTool::add_smooth_group(bool p_smooth) {
+
+ ERR_FAIL_COND(!begun);
+ if (index_array.size()) {
+ smooth_groups[index_array.size()]=p_smooth;
+ } else {
+
+ smooth_groups[vertex_array.size()]=p_smooth;
+ }
+}
+
void SurfaceTool::add_index( int p_index) {
@@ -377,79 +387,53 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
void SurfaceTool::index() {
-#if 0
- printf("indexing..\n");
- ERR_FAIL_COND( format & Surface::ARRAY_FORMAT_INDEX ); // already indexed
-
- index_array.clear();
- DVector< Vertex > indexed_vertex_array;
+ if (index_array.size())
+ return; //already indexed
- int vertex_array_len = vertex_array.size();
- vertex_array.read_lock();
- const Vertex*vertex_array_ptr = vertex_array.read();
- for (int i=0;i<vertex_array_len;i++) {
+ HashMap<Vertex,int,VertexHasher> indices;
+ List<Vertex> new_vertices;
- int index_pos=-1;
+ for(List< Vertex >::Element *E=vertex_array.front();E;E=E->next()) {
- int indexed_vertex_array_len=indexed_vertex_array.size();
-
- if (indexed_vertex_array_len) {
-
- indexed_vertex_array.read_lock();
- const Vertex* indexed_vertex_array_ptr=indexed_vertex_array.read();
-
- for (int j=0;j<indexed_vertex_array_len;j++) {
-
- if (vertex_array_ptr[i].same_as(indexed_vertex_array_ptr[j])) {
-
- index_pos=j;
- break;
- }
- }
-
- indexed_vertex_array.read_unlock();
- }
-
- if (index_pos==-1) {
-
- index_pos=indexed_vertex_array.size();
- indexed_vertex_array.push_back(vertex_array_ptr[i]);
+ int *idxptr=indices.getptr(E->get());
+ int idx;
+ if (!idxptr) {
+ idx=indices.size();
+ new_vertices.push_back(E->get());
+ indices[E->get()]=idx;
} else {
-
- indexed_vertex_array.write_lock();
- indexed_vertex_array.write()[index_pos].normal+=vertex_array_ptr[i].normal;
- indexed_vertex_array.write()[index_pos].binormal+=vertex_array_ptr[i].binormal;
- indexed_vertex_array.write()[index_pos].tangent+=vertex_array_ptr[i].tangent;
- indexed_vertex_array.write_unlock();
+ idx=*idxptr;
}
- index_array.push_back(index_pos);
- }
-
- int idxvertsize=indexed_vertex_array.size();
- indexed_vertex_array.write_lock();
- Vertex* idxvert=indexed_vertex_array.write();
- for (int i=0;i<idxvertsize;i++) {
+ index_array.push_back(idx);
- idxvert[i].normal.normalize();
- idxvert[i].tangent.normalize();
- idxvert[i].binormal.normalize();
}
- indexed_vertex_array.write_unlock();
- vertex_array.read_unlock();
-
- format|=Surface::ARRAY_FORMAT_INDEX;
- vertex_array=indexed_vertex_array;
+ vertex_array.clear();
+ vertex_array=new_vertices;
- printf("indexing.. end\n");
-#endif
+ format|=Mesh::ARRAY_FORMAT_INDEX;
}
void SurfaceTool::deindex() {
+ if (index_array.size()==0)
+ return; //nothing to deindex
+ Vector< Vertex > varr;
+ varr.resize(vertex_array.size());
+ int idx=0;
+ for (List< Vertex >::Element *E=vertex_array.front();E;E=E->next()) {
+ varr[idx++]=E->get();
+ }
+ vertex_array.clear();
+ for (List<int>::Element *E=index_array.front();E;E=E->next()) {
+
+ ERR_FAIL_INDEX(E->get(),varr.size());
+ vertex_array.push_back(varr[E->get()]);
+ }
+ format&=~Mesh::ARRAY_FORMAT_INDEX;
}
@@ -631,80 +615,250 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T
void SurfaceTool::generate_tangents() {
ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
+ ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
-#if 0
- int len=vertex_array.size();
- vertex_array.write_lock();
- Vertex *vertexptr=vertex_array.write();
-
- for (int i=0;i<len/3;i++) {
+ if (index_array.size()) {
+ Vector<List<Vertex>::Element*> vtx;
+ vtx.resize(vertex_array.size());
+ int idx=0;
+ for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
+ vtx[idx++]=E;
+ E->get().binormal=Vector3();
+ E->get().tangent=Vector3();
+ }
- Vector3 v1 = vertexptr[i*3+0].vertex;
- Vector3 v2 = vertexptr[i*3+1].vertex;
- Vector3 v3 = vertexptr[i*3+2].vertex;
+ for (List<int>::Element *E=index_array.front();E;) {
+
+ int i[3];
+ i[0]=E->get();
+ E=E->next();
+ ERR_FAIL_COND(!E);
+ i[1]=E->get();
+ E=E->next();
+ ERR_FAIL_COND(!E);
+ i[2]=E->get();
+ E=E->next();
+ ERR_FAIL_COND(!E);
+
+
+ Vector3 v1 = vtx[ i[0] ]->get().vertex;
+ Vector3 v2 = vtx[ i[1] ]->get().vertex;
+ Vector3 v3 = vtx[ i[2] ]->get().vertex;
+
+ Vector2 w1 = vtx[ i[0] ]->get().uv;
+ Vector2 w2 = vtx[ i[1] ]->get().uv;
+ Vector2 w3 = vtx[ i[2] ]->get().uv;
+
+
+ float x1 = v2.x - v1.x;
+ float x2 = v3.x - v1.x;
+ float y1 = v2.y - v1.y;
+ float y2 = v3.y - v1.y;
+ float z1 = v2.z - v1.z;
+ float z2 = v3.z - v1.z;
+
+ float s1 = w2.x - w1.x;
+ float s2 = w3.x - w1.x;
+ float t1 = w2.y - w1.y;
+ float t2 = w3.y - w1.y;
+
+ float r = (s1 * t2 - s2 * t1);
+
+ Vector3 binormal,tangent;
+
+ if (r==0) {
+ binormal=Vector3(0,0,0);
+ tangent=Vector3(0,0,0);
+ } else {
+ tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
+ (t2 * z1 - t1 * z2) * r);
+ binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
+ (s1 * z2 - s2 * z1) * r);
+ }
- Vector3 w1 = vertexptr[i*3+0].uv[0];
- Vector3 w2 = vertexptr[i*3+1].uv[0];
- Vector3 w3 = vertexptr[i*3+2].uv[0];
+ tangent.normalize();
+ binormal.normalize();
+ Vector3 normal=Plane( v1, v2, v3 ).normal;
+ Vector3 tangentp = tangent - normal * normal.dot( tangent );
+ Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
- float x1 = v2.x - v1.x;
- float x2 = v3.x - v1.x;
- float y1 = v2.y - v1.y;
- float y2 = v3.y - v1.y;
- float z1 = v2.z - v1.z;
- float z2 = v3.z - v1.z;
+ tangentp.normalize();
+ binormalp.normalize();
- float s1 = w2.x - w1.x;
- float s2 = w3.x - w1.x;
- float t1 = w2.y - w1.y;
- float t2 = w3.y - w1.y;
- float r = (s1 * t2 - s2 * t1);
+ for (int j=0;j<3;j++) {
+ vtx[ i[j] ]->get().binormal+=binormalp;
+ vtx[ i[j] ]->get().tangent+=tangentp;
- Vector3 binormal,tangent;
+ }
+ }
- if (r==0) {
- binormal=Vector3(0,0,0);
- tangent=Vector3(0,0,0);
- } else {
- tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r);
- binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r);
+ for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
+ E->get().binormal.normalize();
+ E->get().tangent.normalize();
}
- tangent.normalize();
- binormal.normalize();
- Vector3 normal=Plane( v1, v2, v3 ).normal;
- Vector3 tangentp = tangent - normal * normal.dot( tangent );
- Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
+ } else {
+
- tangentp.normalize();
- binormalp.normalize();
+ for (List<Vertex>::Element *E=vertex_array.front();E;) {
+ List< Vertex >::Element *v[3];
+ v[0]=E;
+ v[1]=v[0]->next();
+ ERR_FAIL_COND(!v[1]);
+ v[2]=v[1]->next();
+ ERR_FAIL_COND(!v[2]);
+ E=v[2]->next();
- for (int j=0;j<3;j++) {
- vertexptr[i*3+j].normal=normal;
- vertexptr[i*3+j].binormal=binormalp;
- vertexptr[i*3+j].tangent=tangentp;
+ Vector3 v1 = v[0]->get().vertex;
+ Vector3 v2 = v[1]->get().vertex;
+ Vector3 v3 = v[2]->get().vertex;
+
+ Vector2 w1 = v[0]->get().uv;
+ Vector2 w2 = v[1]->get().uv;
+ Vector2 w3 = v[2]->get().uv;
+
+
+ float x1 = v2.x - v1.x;
+ float x2 = v3.x - v1.x;
+ float y1 = v2.y - v1.y;
+ float y2 = v3.y - v1.y;
+ float z1 = v2.z - v1.z;
+ float z2 = v3.z - v1.z;
+
+ float s1 = w2.x - w1.x;
+ float s2 = w3.x - w1.x;
+ float t1 = w2.y - w1.y;
+ float t2 = w3.y - w1.y;
+
+ float r = (s1 * t2 - s2 * t1);
+
+ Vector3 binormal,tangent;
+
+ if (r==0) {
+ binormal=Vector3(0,0,0);
+ tangent=Vector3(0,0,0);
+ } else {
+ tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
+ (t2 * z1 - t1 * z2) * r);
+ binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
+ (s1 * z2 - s2 * z1) * r);
+ }
+
+ tangent.normalize();
+ binormal.normalize();
+ Vector3 normal=Plane( v1, v2, v3 ).normal;
+
+ Vector3 tangentp = tangent - normal * normal.dot( tangent );
+ Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
+
+ tangentp.normalize();
+ binormalp.normalize();
+
+
+ for (int j=0;j<3;j++) {
+ v[j]->get().binormal=binormalp;
+ v[j]->get().tangent=tangentp;
+
+ }
}
}
- format|=Surface::ARRAY_FORMAT_TANGENT;
- printf("adding tangents to the format\n");
+ format|=Mesh::ARRAY_FORMAT_TANGENT;
- vertex_array.write_unlock();
-#endif
}
-void SurfaceTool::generate_flat_normals() {
+void SurfaceTool::generate_normals() {
-}
-void SurfaceTool::generate_smooth_normals() {
+ ERR_FAIL_COND(primitive!=Mesh::PRIMITIVE_TRIANGLES);
+
+ bool was_indexed=index_array.size();
+
+ deindex();
+
+ HashMap<Vertex,Vector3,VertexHasher> vertex_hash;
+
+ int count=0;
+ bool smooth=false;
+ if (smooth_groups.has(0))
+ smooth=smooth_groups[0];
+
+ print_line("SMOOTH BEGIN? "+itos(smooth));
+
+ List< Vertex >::Element *B=vertex_array.front();
+ for(List< Vertex >::Element *E=B;E;) {
+
+ List< Vertex >::Element *v[3];
+ v[0]=E;
+ v[1]=v[0]->next();
+ ERR_FAIL_COND(!v[1]);
+ v[2]=v[1]->next();
+ ERR_FAIL_COND(!v[2]);
+ E=v[2]->next();
+
+ Vector3 normal = Plane(v[0]->get().vertex,v[1]->get().vertex,v[2]->get().vertex).normal;
+
+ if (smooth) {
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 *lv=vertex_hash.getptr(v[i]->get());
+ if (!lv) {
+ vertex_hash.set(v[i]->get(),normal);
+ } else {
+ (*lv)+=normal;
+ }
+ }
+ } else {
+
+ for(int i=0;i<3;i++) {
+
+ v[i]->get().normal=normal;
+
+ }
+ }
+ count+=3;
+
+ if (smooth_groups.has(count) || !E) {
+
+ if (vertex_hash.size()) {
+
+ while (B!=E) {
+
+
+ Vector3* lv=vertex_hash.getptr(B->get());
+ if (lv) {
+ B->get().normal=lv->normalized();
+ }
+
+ B=B->next();
+ }
+
+ } else {
+ B=E;
+ }
+
+ vertex_hash.clear();
+ if (E) {
+ smooth=smooth_groups[count];
+ print_line("SMOOTH AT "+itos(count)+": "+itos(smooth));
+
+ }
+ }
+
+ }
+
+ format|=Mesh::ARRAY_FORMAT_NORMAL;
+
+ if (was_indexed) {
+ index();
+ smooth_groups.clear();
+ }
}
@@ -722,6 +876,7 @@ void SurfaceTool::clear() {
last_weights.clear();
index_array.clear();
vertex_array.clear();
+ smooth_groups.clear();
}
@@ -736,12 +891,12 @@ void SurfaceTool::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_uv2","uv2"),&SurfaceTool::add_uv2);
ObjectTypeDB::bind_method(_MD("add_bones","bones"),&SurfaceTool::add_bones);
ObjectTypeDB::bind_method(_MD("add_weights","weights"),&SurfaceTool::add_weights);
+ ObjectTypeDB::bind_method(_MD("add_smooth_group","smooth"),&SurfaceTool::add_smooth_group);
ObjectTypeDB::bind_method(_MD("set_material","material:Material"),&SurfaceTool::set_material);
ObjectTypeDB::bind_method(_MD("index"),&SurfaceTool::index);
ObjectTypeDB::bind_method(_MD("deindex"),&SurfaceTool::deindex);
- ObjectTypeDB::bind_method(_MD("generate_flat_normals"),&SurfaceTool::generate_flat_normals);
- ObjectTypeDB::bind_method(_MD("generate_smooth_normals"),&SurfaceTool::generate_smooth_normals);
- ObjectTypeDB::bind_method(_MD("generate_tangents"),&SurfaceTool::generate_tangents);
+ ///ObjectTypeDB::bind_method(_MD("generate_flat_normals"),&SurfaceTool::generate_flat_normals);
+ ObjectTypeDB::bind_method(_MD("generate_normals"),&SurfaceTool::generate_normals);
ObjectTypeDB::bind_method(_MD("commit:Mesh","existing:Mesh"),&SurfaceTool::commit,DEFVAL( RefPtr() ));
ObjectTypeDB::bind_method(_MD("clear"),&SurfaceTool::clear);