/*************************************************************************/ /* mesh.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "mesh.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" #include "surface_tool.h" static const char* _array_name[]={ "vertex_array", "normal_array", "tangent_array", "color_array", "tex_uv_array", "tex_uv2_array", "bone_array", "weights_array", "index_array", NULL }; static const Mesh::ArrayType _array_types[]={ Mesh::ARRAY_VERTEX, Mesh::ARRAY_NORMAL, Mesh::ARRAY_TANGENT, Mesh::ARRAY_COLOR, Mesh::ARRAY_TEX_UV, Mesh::ARRAY_TEX_UV2, Mesh::ARRAY_BONES, Mesh::ARRAY_WEIGHTS, Mesh::ARRAY_INDEX }; /* compatibility */ static const int _format_translate[]={ Mesh::ARRAY_FORMAT_VERTEX, Mesh::ARRAY_FORMAT_NORMAL, Mesh::ARRAY_FORMAT_TANGENT, Mesh::ARRAY_FORMAT_COLOR, Mesh::ARRAY_FORMAT_TEX_UV, Mesh::ARRAY_FORMAT_TEX_UV2, Mesh::ARRAY_FORMAT_BONES, Mesh::ARRAY_FORMAT_WEIGHTS, Mesh::ARRAY_FORMAT_INDEX, }; bool Mesh::_set(const StringName& p_name, const Variant& p_value) { String sname=p_name; if (p_name=="blend_shape/names") { PoolVector sk=p_value; int sz = sk.size(); PoolVector::Read r = sk.read(); for(int i=0;i array_data = d["array_data"]; PoolVector array_index_data; if (d.has("array_index_data")) array_index_data=d["array_index_data"]; ERR_FAIL_COND_V(!d.has("format"),false); uint32_t format = d["format"]; ERR_FAIL_COND_V(!d.has("primitive"),false); uint32_t primitive = d["primitive"]; ERR_FAIL_COND_V(!d.has("vertex_count"),false); int vertex_count = d["vertex_count"]; int index_count=0; if (d.has("index_count")) index_count=d["index_count"]; Vector< PoolVector > blend_shapes; if (d.has("blend_shape_data")) { Array blend_shape_data=d["blend_shape_data"]; for(int i=0;i shape = blend_shape_data[i]; blend_shapes.push_back(shape); } } ERR_FAIL_COND_V(!d.has("aabb"),false); Rect3 aabb = d["aabb"]; Vector bone_aabb; if (d.has("bone_aabb")) { Array baabb = d["bone_aabb"]; bone_aabb.resize(baabb.size()); for(int i=0;i sk; for(int i=0;imesh_surface_get_array(mesh,idx); d["vertex_count"]=VS::get_singleton()->mesh_surface_get_array_len(mesh,idx); d["array_index_data"]=VS::get_singleton()->mesh_surface_get_index_array(mesh,idx); d["index_count"]=VS::get_singleton()->mesh_surface_get_array_index_len(mesh,idx); d["primitive"]=VS::get_singleton()->mesh_surface_get_primitive_type(mesh,idx); d["format"]=VS::get_singleton()->mesh_surface_get_format(mesh,idx); d["aabb"]=VS::get_singleton()->mesh_surface_get_aabb(mesh,idx); Vector skel_aabb = VS::get_singleton()->mesh_surface_get_skeleton_aabb(mesh,idx); Array arr; for(int i=0;i > blend_shape_data = VS::get_singleton()->mesh_surface_get_blend_shapes(mesh,idx); Array md; for(int i=0;i m = surface_get_material(idx); if (m.is_valid()) d["material"]=m; String n = surface_get_name(idx); if (n!="") d["name"]=n; r_ret=d; return true; } void Mesh::_get_property_list( List *p_list) const { if (blend_shapes.size()) { p_list->push_back(PropertyInfo(Variant::POOL_STRING_ARRAY,"blend_shape/names",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::INT,"blend_shape/mode",PROPERTY_HINT_ENUM,"Normalized,Relative")); } for (int i=0;ipush_back( PropertyInfo( Variant::DICTIONARY,"surfaces/"+itos(i), PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR ) ); p_list->push_back( PropertyInfo( Variant::STRING,"surface_"+itos(i+1)+"/name", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR ) ); p_list->push_back( PropertyInfo( Variant::OBJECT,"surface_"+itos(i+1)+"/material", PROPERTY_HINT_RESOURCE_TYPE,"Material",PROPERTY_USAGE_EDITOR ) ); } p_list->push_back( PropertyInfo( Variant::RECT3,"custom_aabb/custom_aabb" ) ); } void Mesh::_recompute_aabb() { // regenerate AABB aabb=Rect3(); for (int i=0;i& p_array,int p_vertex_count,const PoolVector& p_index_array,int p_index_count,const Rect3& p_aabb,const Vector >& p_blend_shapes,const Vector& p_bone_aabbs) { Surface s; s.aabb=p_aabb; surfaces.push_back(s); VisualServer::get_singleton()->mesh_add_surface(mesh,p_format,(VS::PrimitiveType)p_primitive,p_array,p_vertex_count,p_index_array,p_index_count,p_aabb,p_blend_shapes,p_bone_aabbs); } void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,uint32_t p_flags) { ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX); Surface s; VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes,p_flags); surfaces.push_back(s); /* make aABB? */ { PoolVector vertices=p_arrays[ARRAY_VERTEX]; int len=vertices.size(); ERR_FAIL_COND(len==0); PoolVector::Read r=vertices.read(); const Vector3 *vtx=r.ptr(); // check AABB Rect3 aabb; for (int i=0;i(); _change_notify(); emit_changed(); } Array Mesh::surface_get_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface,surfaces.size(),Array()); return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh,p_surface); } Array Mesh::surface_get_blend_shape_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface,surfaces.size(),Array()); return Array(); } int Mesh::get_surface_count() const { return surfaces.size(); } void Mesh::add_blend_shape(const StringName& p_name) { if (surfaces.size()) { ERR_EXPLAIN("Can't add a shape key count if surfaces are already created."); ERR_FAIL_COND(surfaces.size()); } StringName name=p_name; if (blend_shapes.find(name)!=-1 ) { int count=2; do { name = String(p_name) + " " + itos(count); count++; } while(blend_shapes.find(name)!=-1); } blend_shapes.push_back(name); VS::get_singleton()->mesh_set_blend_shape_count(mesh,blend_shapes.size()); } int Mesh::get_blend_shape_count() const { return blend_shapes.size(); } StringName Mesh::get_blend_shape_name(int p_index) const { ERR_FAIL_INDEX_V( p_index, blend_shapes.size(),StringName() ); return blend_shapes[p_index]; } void Mesh::clear_blend_shapes() { if (surfaces.size()) { ERR_EXPLAIN("Can't set shape key count if surfaces are already created."); ERR_FAIL_COND(surfaces.size()); } blend_shapes.clear(); } void Mesh::set_blend_shape_mode(BlendShapeMode p_mode) { blend_shape_mode=p_mode; VS::get_singleton()->mesh_set_blend_shape_mode(mesh,(VS::BlendShapeMode)p_mode); } Mesh::BlendShapeMode Mesh::get_blend_shape_mode() const { return blend_shape_mode; } void Mesh::surface_remove(int p_idx) { ERR_FAIL_INDEX(p_idx, surfaces.size() ); VisualServer::get_singleton()->mesh_remove_surface(mesh,p_idx); surfaces.remove(p_idx); triangle_mesh=Ref(); _recompute_aabb(); _change_notify(); emit_changed(); } int Mesh::surface_get_array_len(int p_idx) const { ERR_FAIL_INDEX_V( p_idx, surfaces.size(), -1 ); return VisualServer::get_singleton()->mesh_surface_get_array_len( mesh, p_idx ); } int Mesh::surface_get_array_index_len(int p_idx) const { ERR_FAIL_INDEX_V( p_idx, surfaces.size(), -1 ); return VisualServer::get_singleton()->mesh_surface_get_array_index_len( mesh, p_idx ); } uint32_t Mesh::surface_get_format(int p_idx) const { ERR_FAIL_INDEX_V( p_idx, surfaces.size(), 0 ); return VisualServer::get_singleton()->mesh_surface_get_format( mesh, p_idx ); } Mesh::PrimitiveType Mesh::surface_get_primitive_type(int p_idx) const { ERR_FAIL_INDEX_V( p_idx, surfaces.size(), PRIMITIVE_LINES ); return (PrimitiveType)VisualServer::get_singleton()->mesh_surface_get_primitive_type( mesh, p_idx ); } void Mesh::surface_set_material(int p_idx, const Ref& p_material) { ERR_FAIL_INDEX( p_idx, surfaces.size() ); if (surfaces[p_idx].material==p_material) return; surfaces[p_idx].material=p_material; VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null()?RID():p_material->get_rid()); _change_notify("material"); } void Mesh::surface_set_name(int p_idx, const String& p_name) { ERR_FAIL_INDEX( p_idx, surfaces.size() ); surfaces[p_idx].name=p_name; } String Mesh::surface_get_name(int p_idx) const{ ERR_FAIL_INDEX_V( p_idx, surfaces.size(),String() ); return surfaces[p_idx].name; } void Mesh::surface_set_custom_aabb(int p_idx,const Rect3& p_aabb) { ERR_FAIL_INDEX( p_idx, surfaces.size() ); surfaces[p_idx].aabb=p_aabb; // set custom aabb too? } Ref Mesh::surface_get_material(int p_idx) const { ERR_FAIL_INDEX_V( p_idx, surfaces.size(), Ref() ); return surfaces[p_idx].material; } void Mesh::add_surface_from_mesh_data(const Geometry::MeshData& p_mesh_data) { VisualServer::get_singleton()->mesh_add_surface_from_mesh_data( mesh, p_mesh_data ); Rect3 aabb; for (int i=0;i(); surfaces.push_back(s); _change_notify(); emit_changed(); } RID Mesh::get_rid() const { return mesh; } Rect3 Mesh::get_aabb() const { return aabb; } void Mesh::set_custom_aabb(const Rect3& p_custom) { custom_aabb=p_custom; VS::get_singleton()->mesh_set_custom_aabb(mesh,custom_aabb); } Rect3 Mesh::get_custom_aabb() const { return custom_aabb; } PoolVector Mesh::get_faces() const { Ref tm = generate_triangle_mesh(); if (tm.is_valid()) return tm->get_faces(); return PoolVector(); /* for (int i=0;imesh_surface_get_primitive_type( mesh, i ) != VisualServer::PRIMITIVE_TRIANGLES ) continue; PoolVector indices; PoolVector vertices; vertices=VisualServer::get_singleton()->mesh_surface_get_array(mesh, i,VisualServer::ARRAY_VERTEX); int len=VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i); bool has_indices; if (len>0) { indices=VisualServer::get_singleton()->mesh_surface_get_array(mesh, i,VisualServer::ARRAY_INDEX); has_indices=true; } else { len=vertices.size(); has_indices=false; } if (len<=0) continue; PoolVector::Read indicesr = indices.read(); const int *indicesptr = indicesr.ptr(); PoolVector::Read verticesr = vertices.read(); const Vector3 *verticesptr = verticesr.ptr(); int old_faces=faces.size(); int new_faces=old_faces+(len/3); faces.resize(new_faces); PoolVector::Write facesw = faces.write(); Face3 *facesptr=facesw.ptr(); for (int i=0;i Mesh::create_convex_shape() const { PoolVector vertices; for(int i=0;i v=a[ARRAY_VERTEX]; vertices.append_array(v); } Ref shape = memnew( ConvexPolygonShape ); shape->set_points(vertices); return shape; } Ref Mesh::create_trimesh_shape() const { PoolVector faces = get_faces(); if (faces.size()==0) return Ref(); PoolVector face_points; face_points.resize( faces.size()*3 ); for (int i=0;i shape = memnew( ConcavePolygonShape ); shape->set_faces(face_points); return shape; } void Mesh::center_geometry() { /* Vector3 ofs = aabb.pos+aabb.size*0.5; for(int i=0;i geom = surface_get_array(i,ARRAY_VERTEX); int gc =geom.size(); PoolVector::Write w = geom.write(); surfaces[i].aabb.pos-=ofs; for(int i=0;i::Write(); surface_set_array(i,ARRAY_VERTEX,geom); } aabb.pos-=ofs; */ } void Mesh::regen_normalmaps() { Vector< Ref > surfs; for(int i=0;i st = memnew( SurfaceTool ); st->create_from(Ref(this),i); surfs.push_back(st); } while (get_surface_count()) { surface_remove(0); } for(int i=0;igenerate_tangents(); surfs[i]->commit(Ref(this)); } } Ref Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) return triangle_mesh; int facecount=0; for(int i=0;i faces; faces.resize(facecount); PoolVector::Write facesw=faces.write(); int widx=0; for(int i=0;i vertices = a[ARRAY_VERTEX]; PoolVector::Read vr=vertices.read(); if (surface_get_format(i)&ARRAY_FORMAT_INDEX) { int ic=surface_get_array_index_len(i); PoolVector indices = a[ARRAY_INDEX]; PoolVector::Read ir = indices.read(); for(int i=0;i::Write(); triangle_mesh = Ref( memnew( TriangleMesh )); triangle_mesh->create(faces); return triangle_mesh; } Ref Mesh::create_outline(float p_margin) const { Array arrays; int index_accum=0; for(int i=0;i v=a[ARRAY_VERTEX]; index_accum+=v.size(); } else { for(int j=0;j dst = arrays[j]; PoolVector 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: { PoolVector dst = arrays[j]; PoolVector 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: { PoolVector dst = arrays[j]; PoolVector 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: { PoolVector dst = arrays[j]; PoolVector 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: { PoolVector dst = arrays[j]; PoolVector src = a[j]; if (dst.size()==0 || src.size()==0) { arrays[j]=Variant(); continue; } { int ss = src.size(); PoolVector::Write w = src.write(); for(int k=0;k::Write ir; PoolVector indices =arrays[ARRAY_INDEX]; bool has_indices=false; PoolVector vertices =arrays[ARRAY_VERTEX]; int vc = vertices.size(); ERR_FAIL_COND_V(!vc,Ref()); PoolVector::Write r=vertices.write(); if (indices.size()) { vc=indices.size(); ir=indices.write(); has_indices=true; } Map normal_accum; //fill normals with triangle normals for(int i=0;i::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::Element *E=normal_accum.front();E;E=E->next()) { E->get().normalize(); } //displace normals int vc2 = vertices.size(); for(int i=0;i::Element *E=normal_accum.find(t); ERR_CONTINUE(!E); t+=E->get()*p_margin; r[i]=t; } r = PoolVector::Write(); arrays[ARRAY_VERTEX]=vertices; if (!has_indices) { PoolVector new_indices; new_indices.resize(vertices.size()); PoolVector::Write iw = new_indices.write(); for(int j=0;j::Write(); arrays[ARRAY_INDEX]=new_indices; } else { for(int j=0;j::Write(); arrays[ARRAY_INDEX]=indices; } } Ref newmesh = memnew( Mesh ); newmesh->add_surface_from_arrays(PRIMITIVE_TRIANGLES,arrays); return newmesh; } void Mesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_shape","name"),&Mesh::add_blend_shape); ClassDB::bind_method(D_METHOD("get_blend_shape_count"),&Mesh::get_blend_shape_count); ClassDB::bind_method(D_METHOD("get_blend_shape_name","index"),&Mesh::get_blend_shape_name); ClassDB::bind_method(D_METHOD("clear_blend_shapes"),&Mesh::clear_blend_shapes); ClassDB::bind_method(D_METHOD("set_blend_shape_mode","mode"),&Mesh::set_blend_shape_mode); ClassDB::bind_method(D_METHOD("get_blend_shape_mode"),&Mesh::get_blend_shape_mode); ClassDB::bind_method(D_METHOD("add_surface_from_arrays","primitive","arrays","blend_shapes","compress_flags"),&Mesh::add_surface_from_arrays,DEFVAL(Array()),DEFVAL(ARRAY_COMPRESS_DEFAULT)); ClassDB::bind_method(D_METHOD("get_surface_count"),&Mesh::get_surface_count); ClassDB::bind_method(D_METHOD("surface_remove","surf_idx"),&Mesh::surface_remove); ClassDB::bind_method(D_METHOD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len); ClassDB::bind_method(D_METHOD("surface_get_array_index_len","surf_idx"),&Mesh::surface_get_array_index_len); ClassDB::bind_method(D_METHOD("surface_get_format","surf_idx"),&Mesh::surface_get_format); ClassDB::bind_method(D_METHOD("surface_get_primitive_type","surf_idx"),&Mesh::surface_get_primitive_type); ClassDB::bind_method(D_METHOD("surface_set_material","surf_idx","material:Material"),&Mesh::surface_set_material); ClassDB::bind_method(D_METHOD("surface_get_material:Material","surf_idx"),&Mesh::surface_get_material); ClassDB::bind_method(D_METHOD("surface_set_name","surf_idx","name"),&Mesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name","surf_idx"),&Mesh::surface_get_name); ClassDB::bind_method(D_METHOD("center_geometry"),&Mesh::center_geometry); ClassDB::set_method_flags(get_class_static(),_scs_create("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("regen_normalmaps"),&Mesh::regen_normalmaps); ClassDB::set_method_flags(get_class_static(),_scs_create("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb); ClassDB::bind_method(D_METHOD("get_custom_aabb"),&Mesh::get_custom_aabb); BIND_CONSTANT( NO_INDEX_ARRAY ); BIND_CONSTANT( ARRAY_WEIGHTS_SIZE ); BIND_CONSTANT( ARRAY_VERTEX ); BIND_CONSTANT( ARRAY_NORMAL ); BIND_CONSTANT( ARRAY_TANGENT ); BIND_CONSTANT( ARRAY_COLOR ); BIND_CONSTANT( ARRAY_TEX_UV ); BIND_CONSTANT( ARRAY_TEX_UV2 ); BIND_CONSTANT( ARRAY_BONES ); BIND_CONSTANT( ARRAY_WEIGHTS ); BIND_CONSTANT( ARRAY_INDEX ); BIND_CONSTANT( ARRAY_FORMAT_VERTEX ); BIND_CONSTANT( ARRAY_FORMAT_NORMAL ); BIND_CONSTANT( ARRAY_FORMAT_TANGENT ); BIND_CONSTANT( ARRAY_FORMAT_COLOR ); BIND_CONSTANT( ARRAY_FORMAT_TEX_UV ); BIND_CONSTANT( ARRAY_FORMAT_TEX_UV2 ); BIND_CONSTANT( ARRAY_FORMAT_BONES ); BIND_CONSTANT( ARRAY_FORMAT_WEIGHTS ); BIND_CONSTANT( ARRAY_FORMAT_INDEX ); BIND_CONSTANT( PRIMITIVE_POINTS ); BIND_CONSTANT( PRIMITIVE_LINES ); BIND_CONSTANT( PRIMITIVE_LINE_STRIP ); BIND_CONSTANT( PRIMITIVE_LINE_LOOP ); BIND_CONSTANT( PRIMITIVE_TRIANGLES ); BIND_CONSTANT( PRIMITIVE_TRIANGLE_STRIP ); BIND_CONSTANT( PRIMITIVE_TRIANGLE_FAN ); } Mesh::Mesh() { mesh=VisualServer::get_singleton()->mesh_create(); blend_shape_mode=BLEND_SHAPE_MODE_RELATIVE; } Mesh::~Mesh() { VisualServer::get_singleton()->free(mesh); }