diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/SCsub | 1 | ||||
-rw-r--r-- | tools/editor/editor_import_export.cpp | 4 | ||||
-rw-r--r-- | tools/editor/editor_node.cpp | 3 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_import_collada.cpp | 76 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_scene_import_plugin.cpp | 32 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_scene_import_plugin.h | 8 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp | 1106 | ||||
-rw-r--r-- | tools/editor/io_plugins/editor_scene_importer_fbxconv.h | 81 | ||||
-rw-r--r-- | tools/editor/plugins/baked_light_baker.cpp | 4 | ||||
-rw-r--r-- | tools/editor/plugins/spatial_editor_plugin.cpp | 10 | ||||
-rw-r--r-- | tools/editor/spatial_editor_gizmos.cpp | 122 | ||||
-rw-r--r-- | tools/editor/spatial_editor_gizmos.h | 32 | ||||
-rw-r--r-- | tools/export/blender25/io_scene_dae/export_dae.py | 30 | ||||
-rw-r--r-- | tools/pck/SCsub | 5 | ||||
-rw-r--r-- | tools/pck/pck_packer.cpp | 162 | ||||
-rw-r--r-- | tools/pck/pck_packer.h | 31 |
16 files changed, 1655 insertions, 52 deletions
diff --git a/tools/SCsub b/tools/SCsub index 4f1432143b..528ffbf3c3 100644 --- a/tools/SCsub +++ b/tools/SCsub @@ -11,6 +11,7 @@ SConscript('collada/SCsub'); SConscript('docdump/SCsub'); SConscript('freetype/SCsub'); SConscript('doc/SCsub'); +SConscript('pck/SCsub'); lib = env.Library("tool",env.tool_sources, LIBSUFFIX=env['platform_libsuffix']) diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index 649db5fc45..8f9195110b 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -1032,7 +1032,7 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug, if (!dst) { EditorNode::add_io_error("Can't copy executable file to:\n "+p_path); - return ERR_FILE_CANT_READ; + return ERR_FILE_CANT_WRITE; } uint8_t buff[32768]; @@ -1061,7 +1061,7 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug, if (!dst) { EditorNode::add_io_error("Can't write data pack to:\n "+p_path); - return ERR_FILE_CANT_READ; + return ERR_FILE_CANT_WRITE; } } diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index a6243df69d..6ac72fc401 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -41,6 +41,7 @@ #include "scene/resources/packed_scene.h" #include "editor_settings.h" #include "io_plugins/editor_import_collada.h" +#include "io_plugins/editor_scene_importer_fbxconv.h" #include "globals.h" #include <stdio.h> #include "object_type_db.h" @@ -4048,6 +4049,8 @@ EditorNode::EditorNode() { Ref<EditorSceneImportPlugin> _scene_import = memnew(EditorSceneImportPlugin(this) ); Ref<EditorSceneImporterCollada> _collada_import = memnew( EditorSceneImporterCollada); _scene_import->add_importer(_collada_import); + Ref<EditorSceneImporterFBXConv> _fbxconv_import = memnew( EditorSceneImporterFBXConv); + _scene_import->add_importer(_fbxconv_import); editor_import_export->add_import_plugin( _scene_import); editor_import_export->add_import_plugin( Ref<EditorSceneAnimationImportPlugin>( memnew(EditorSceneAnimationImportPlugin(this)))); editor_import_export->add_import_plugin( Ref<EditorMeshImportPlugin>( memnew(EditorMeshImportPlugin(this)))); diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index a0f1626b03..15a671d623 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -82,8 +82,8 @@ struct ColladaImport { Error _create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data); Error load(const String& p_path, int p_flags, bool p_force_make_tangents=false); void _fix_param_animation_tracks(); - void create_animation(int p_clip=-1); - void create_animations(); + void create_animation(int p_clip,bool p_make_tracks_in_all_bones); + void create_animations(bool p_make_tracks_in_all_bones); Set<String> tracks_in_clips; Vector<String> missing_textures; @@ -1088,7 +1088,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co DVector<Vector3>::Write uv2arrayw = uv2array.write(); for(int k=0;k<vlen;k++) { - uv2arrayw[k]=vertex_array[k].uv; + uv2arrayw[k]=vertex_array[k].uv2; } uv2arrayw = DVector<Vector3>::Write(); @@ -1705,7 +1705,7 @@ void ColladaImport::_fix_param_animation_tracks() { } -void ColladaImport::create_animations() { +void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) { print_line("-=-=-=-=-PRE CA"); _fix_param_animation_tracks(); @@ -1737,14 +1737,14 @@ void ColladaImport::create_animations() { } - create_animation(); + create_animation(-1,p_make_tracks_in_all_bones); print_line("clipcount: "+itos(collada.state.animation_clips.size())); for(int i=0;i<collada.state.animation_clips.size();i++) - create_animation(i); + create_animation(i,p_make_tracks_in_all_bones); } -void ColladaImport::create_animation(int p_clip) { +void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones) { Ref<Animation> animation = Ref<Animation>( memnew( Animation )); @@ -1980,46 +1980,48 @@ void ColladaImport::create_animation(int p_clip) { } + if (p_make_tracks_in_all_bones) { - //some bones may lack animation, but since we don't store pose as a property, we must add keyframes! - for(Map<String,bool>::Element *E=bones_with_animation.front();E;E=E->next()) { + //some bones may lack animation, but since we don't store pose as a property, we must add keyframes! + for(Map<String,bool>::Element *E=bones_with_animation.front();E;E=E->next()) { - if (E->get()) - continue; + if (E->get()) + continue; - //print_line("BONE LACKS ANIM: "+E->key()); + //print_line("BONE LACKS ANIM: "+E->key()); - NodeMap &nm = node_map[E->key()]; - String path = scene->get_path_to(nm.node); - ERR_CONTINUE( nm.bone <0 ); - Skeleton *sk = static_cast<Skeleton*>(nm.node); - String name = sk->get_bone_name(nm.bone); - path=path+":"+name; + NodeMap &nm = node_map[E->key()]; + String path = scene->get_path_to(nm.node); + ERR_CONTINUE( nm.bone <0 ); + Skeleton *sk = static_cast<Skeleton*>(nm.node); + String name = sk->get_bone_name(nm.bone); + path=path+":"+name; - Collada::Node *cn = collada.state.scene_map[E->key()]; - if (cn->ignore_anim) { - print_line("warning, ignoring animation on node: "+path); - continue; - } + Collada::Node *cn = collada.state.scene_map[E->key()]; + if (cn->ignore_anim) { + print_line("warning, ignoring animation on node: "+path); + continue; + } - animation->add_track(Animation::TYPE_TRANSFORM); - int track = animation->get_track_count() -1; - animation->track_set_path( track , path ); + animation->add_track(Animation::TYPE_TRANSFORM); + int track = animation->get_track_count() -1; + animation->track_set_path( track , path ); - Transform xform = cn->compute_transform(collada); - xform = collada.fix_transform(xform) * cn->post_transform; + Transform xform = cn->compute_transform(collada); + xform = collada.fix_transform(xform) * cn->post_transform; - xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform; + xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform; - Quat q = xform.basis; - q.normalize(); - Vector3 s = xform.basis.get_scale(); - Vector3 l = xform.origin; + Quat q = xform.basis; + q.normalize(); + Vector3 s = xform.basis.get_scale(); + Vector3 l = xform.origin; - animation->transform_track_insert_key(track,0,l,q,s); + animation->transform_track_insert_key(track,0,l,q,s); - tracks_found=true; + tracks_found=true; + } } @@ -2149,7 +2151,7 @@ Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_ if (p_flags&IMPORT_ANIMATION) { - state.create_animations(); + state.create_animations(p_flags&IMPORT_ANIMATION_FORCE_TRACKS_IN_ALL_BONES); AnimationPlayer *ap = memnew( AnimationPlayer ); for(int i=0;i<state.animations.size();i++) { String name; @@ -2188,7 +2190,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String& p_path ERR_FAIL_COND_V(err!=OK,RES()); - state.create_animations(); + state.create_animations(p_flags&EditorSceneImporter::IMPORT_ANIMATION_FORCE_TRACKS_IN_ALL_BONES); if (state.scene) memdelete(state.scene); diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp index 0b7ffd55f0..3cc8ffd151 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp @@ -35,6 +35,7 @@ #include "scene/animation/animation_player.h" #include "io/resource_saver.h" #include "scene/3d/mesh_instance.h" +#include "scene/3d/navigation.h" #include "scene/3d/room_instance.h" #include "scene/3d/body_shape.h" #include "scene/3d/physics_body.h" @@ -176,6 +177,7 @@ static const char *anim_flag_names[]={ "Detect Loop (-loop,-cycle)", "Keep Value Tracks", "Optimize", + "Force Tracks in All Bones", NULL }; @@ -183,6 +185,7 @@ static const char *anim_flag_descript[]={ "Set loop flag for animation names that\ncontain 'cycle' or 'loop' in the name.", "When merging an existing aimation,\nkeep the user-created value-tracks.", "Remove redundant keyframes in\n transform tacks.", + "Some exporters will rely on default pose for some bones.\nThis forces those bones to have at least one animation key.", NULL }; @@ -806,7 +809,7 @@ EditorSceneImportDialog::EditorSceneImportDialog(EditorNode *p_editor, EditorSce animation_options = memnew( EditorImportAnimationOptions ); ovb->add_child(animation_options); animation_options->set_v_size_flags(SIZE_EXPAND_FILL); - animation_options->set_flags(EditorSceneAnimationImportPlugin::ANIMATION_DETECT_LOOP|EditorSceneAnimationImportPlugin::ANIMATION_KEEP_VALUE_TRACKS|EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE); + animation_options->set_flags(EditorSceneAnimationImportPlugin::ANIMATION_DETECT_LOOP|EditorSceneAnimationImportPlugin::ANIMATION_KEEP_VALUE_TRACKS|EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE|EditorSceneAnimationImportPlugin::ANIMATION_FORCE_TRACKS_IN_ALL_BONES); confirm_import = memnew( ConfirmationDialog ); @@ -1229,6 +1232,27 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh> sb->add_child(colshape); colshape->set_owner(p_node->get_owner()); + } else if (p_flags&SCENE_FLAG_CREATE_NAVMESH &&_teststr(name,"navmesh") && p_node->cast_to<MeshInstance>()) { + + if (isroot) + return p_node; + + MeshInstance *mi = p_node->cast_to<MeshInstance>(); + + Ref<Mesh> mesh=mi->get_mesh(); + ERR_FAIL_COND_V(mesh.is_null(),NULL); + NavigationMeshInstance *nmi = memnew( NavigationMeshInstance ); + + + nmi->set_name(_fixstr(name,"navmesh")); + Ref<NavigationMesh> nmesh = memnew( NavigationMesh); + nmesh->create_from_mesh(mesh); + nmi->set_navigation_mesh(nmesh); + nmi->cast_to<Spatial>()->set_transform(mi->get_transform()); + p_node->replace_by(nmi); + memdelete(p_node); + p_node=nmi; + } else if (p_flags&SCENE_FLAG_CREATE_ROOMS && _teststr(name,"room") && p_node->cast_to<MeshInstance>()) { @@ -1737,10 +1761,12 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from import_flags|=EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP; if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE) import_flags|=EditorSceneImporter::IMPORT_ANIMATION_OPTIMIZE; + if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_FORCE_TRACKS_IN_ALL_BONES) + import_flags|=EditorSceneImporter::IMPORT_ANIMATION_FORCE_TRACKS_IN_ALL_BONES; if (scene_flags&SCENE_FLAG_IMPORT_ANIMATIONS) import_flags|=EditorSceneImporter::IMPORT_ANIMATION; -// if (scene_flags&SCENE_FLAG_FAIL_ON_MISSING_IMAGES) -// import_flags|=EditorSceneImporter::IMPORT_FAIL_ON_MISSING_DEPENDENCIES; + //if (scene_flags&SCENE_FLAG_FAIL_ON_MISSING_IMAGES) + // import_flags|=EditorSceneImporter::IMPORT_FAIL_ON_MISSING_DEPENDENCIES; if (scene_flags&SCENE_FLAG_GENERATE_TANGENT_ARRAYS) import_flags|=EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS; diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h index 928fff2afb..114233df80 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.h +++ b/tools/editor/io_plugins/editor_scene_import_plugin.h @@ -58,8 +58,9 @@ public: IMPORT_ANIMATION=2, IMPORT_ANIMATION_DETECT_LOOP=4, IMPORT_ANIMATION_OPTIMIZE=8, - IMPORT_GENERATE_TANGENT_ARRAYS=16, - IMPORT_FAIL_ON_MISSING_DEPENDENCIES=128 + IMPORT_ANIMATION_FORCE_TRACKS_IN_ALL_BONES=16, + IMPORT_GENERATE_TANGENT_ARRAYS=256, + IMPORT_FAIL_ON_MISSING_DEPENDENCIES=512 }; @@ -160,7 +161,8 @@ public: ANIMATION_DETECT_LOOP=1, ANIMATION_KEEP_VALUE_TRACKS=2, - ANIMATION_OPTIMIZE=4 + ANIMATION_OPTIMIZE=4, + ANIMATION_FORCE_TRACKS_IN_ALL_BONES=8 }; virtual String get_name() const; diff --git a/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp new file mode 100644 index 0000000000..0c388b91ca --- /dev/null +++ b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp @@ -0,0 +1,1106 @@ +#include "editor_scene_importer_fbxconv.h" +#include "os/file_access.h" +#include "os/os.h" +#include "tools/editor/editor_settings.h" +#include "scene/3d/mesh_instance.h" +#include "scene/animation/animation_player.h" + + +String EditorSceneImporterFBXConv::_id(const String& p_id) const { + + return p_id.replace(":","_").replace("/","_"); +} + +uint32_t EditorSceneImporterFBXConv::get_import_flags() const { + + return IMPORT_SCENE|IMPORT_ANIMATION; +} +void EditorSceneImporterFBXConv::get_extensions(List<String> *r_extensions) const{ + + r_extensions->push_back("fbx"); + r_extensions->push_back("g3dj"); +} + + +Color EditorSceneImporterFBXConv::_get_color(const Array& a) { + + if (a.size()<3) + return Color(); + Color c; + c.r=a[0]; + c.g=a[1]; + c.b=a[2]; + if (a.size()>=4) + c.a=a[3]; + return c; + +} + +Transform EditorSceneImporterFBXConv::_get_transform_mixed(const Dictionary& d,const Dictionary& dbase) { + + + + + Array translation; + + if (d.has("translation")) + translation=d["translation"]; + else if (dbase.has("translation")) + translation=dbase["translation"]; + + Array rotation; + + if (d.has("rotation")) + rotation=d["rotation"]; + else if (dbase.has("rotation")) + rotation=dbase["rotation"]; + + Array scale; + + if (d.has("scale")) + scale=d["scale"]; + else if (dbase.has("scale")) + scale=dbase["scale"]; + + Transform t; + + + if (translation.size()) { + Array tr = translation; + if (tr.size()>=3) { + t.origin.x=tr[0]; + t.origin.y=tr[1]; + t.origin.z=tr[2]; + } + } + + if (rotation.size()) { + + Array r = rotation; + if (r.size()>=4) { + + Quat q; + q.x = r[0]; + q.y = r[1]; + q.z = r[2]; + q.w = r[3]; + t.basis=Matrix3(q); + } + } + + + if (scale.size()) { + + Array sc = scale; + if (sc.size()>=3) { + Vector3 s; + s.x=sc[0]; + s.y=sc[1]; + s.z=sc[2]; + t.basis.scale(s); + } + } + + return t; + + +} + +Transform EditorSceneImporterFBXConv::_get_transform(const Dictionary& d) { + + + Transform t; + + if (d.has("translation")) { + Array tr = d["translation"]; + if (tr.size()>=3) { + t.origin.x=tr[0]; + t.origin.y=tr[1]; + t.origin.z=tr[2]; + } + } + + if (d.has("rotation")) { + + Array r = d["rotation"]; + if (r.size()>=4) { + + Quat q; + q.x = r[0]; + q.y = r[1]; + q.z = r[2]; + q.w = r[3]; + t.basis=Matrix3(q); + } + } + + + if (d.has("scale")) { + + Array sc = d["scale"]; + if (sc.size()>=3) { + Vector3 s; + s.x=sc[0]; + s.y=sc[1]; + s.z=sc[2]; + t.basis.scale(s); + } + } + + return t; +} + + +void EditorSceneImporterFBXConv::_detect_bones_in_nodes(State& state,const Array& p_nodes) { + + + for(int i=0;i<p_nodes.size();i++) { + + Dictionary d = p_nodes[i]; + if (d.has("isBone") && bool(d["isBone"])) { + + String bone_name=_id(d["id"]); + print_line("IS BONE: "+bone_name); + if (!state.bones.has(bone_name)) { + state.bones.insert(bone_name,BoneInfo()); + } + + if (!state.bones[bone_name].has_rest) { + state.bones[bone_name].rest=_get_transform(d).affine_inverse(); + } + + state.bones[bone_name].node=d; + + //state.bones[name].rest=_get_transform(b); + } + + if (d.has("parts")) { + + Array parts=d["parts"]; + for(int j=0;j<parts.size();j++) { + + Dictionary p=parts[j]; + if (p.has("bones")) { + Array bones=p["bones"]; + //omfg + for(int k=0;k<bones.size();k++) { + + Dictionary b = bones[k]; + if (b.has("node")) { + + String name = _id(b["node"]); + if (!state.bones.has(name)) { + state.bones.insert(name,BoneInfo()); + } + + state.bones[name].rest=_get_transform(b); + state.bones[name].has_rest=true; + } + } + } + + } + } + + if (d.has("children")) { + + _detect_bones_in_nodes(state,d["children"]); + } + } + +} + +void EditorSceneImporterFBXConv::_parse_skeletons(const String& p_name,State& state, const Array &p_nodes, Skeleton *p_skeleton,int p_parent) { + + + + for(int i=0;i<p_nodes.size();i++) { + + + Dictionary d = p_nodes[i]; + int bone_idx=-1; + String id; + Skeleton* skeleton=p_skeleton; + if (d.has("id")) { + + id=_id(d["id"]); + if (state.bones.has(id)) { + //BONER + if (!skeleton) { + skeleton=memnew( Skeleton ); + state.skeletons[id]=skeleton; + } + bone_idx = skeleton->get_bone_count(); + skeleton->add_bone(id); + skeleton->set_bone_parent(bone_idx,p_parent); + skeleton->set_bone_rest(bone_idx,state.bones[id].rest); + state.bones[id].skeleton=skeleton; + } + } + + if (d.has("children")) { + + _parse_skeletons(id,state,d["children"],skeleton,bone_idx); + } + } + +} + +void EditorSceneImporterFBXConv::_detect_bones(State& state) { + //This format should mark when a node is a bone, + //which is the only thing that Collada does right. + //think about others implementing a parser. + //Just _one_ string and you avoid loads of lines of code to other people. + + for(int i=0;i<state.animations.size();i++) { + + Dictionary an = state.animations[i]; + if (an.has("bones")) { + + Array bo=an["bones"]; + for(int j=0;j<bo.size();j++) { + + Dictionary b=bo[j]; + if (b.has("boneId")) { + + String id = b["boneId"]; + if (!state.bones.has(id)) { + state.bones.insert(id,BoneInfo()); + } + state.bones[id].has_anim_chan=true; //used in anim + + + } + } + } + } + + _detect_bones_in_nodes(state,state.nodes); + _parse_skeletons("",state,state.nodes,NULL,-1); + + print_line("found bones: "+itos(state.bones.size())); + print_line("found skeletons: "+itos(state.skeletons.size())); +} + +Error EditorSceneImporterFBXConv::_parse_bones(State& state,const Array &p_bones,Skeleton* p_skeleton) { + + + + return OK; +} + + +void EditorSceneImporterFBXConv::_add_surface(State& state,Ref<Mesh>& m,const Dictionary &part) { + + if (part.has("meshpartid")) { + + String id = part["meshpartid"]; + ERR_FAIL_COND(!state.surface_cache.has(id)); + + + Ref<Material> mat; + if (part.has("materialid")) { + String matid=part["materialid"]; + if (state.material_cache.has(matid)) { + mat=state.material_cache[matid]; + } + } + int idx = m->get_surface_count(); + + Array array = state.surface_cache[id].array; + DVector<float> indices = array[Mesh::ARRAY_BONES]; + if (indices.size() && part.has("bones")) { + + + Map<int,int> index_map; + + Array bones=part["bones"]; + + for(int i=0;i<bones.size();i++) { + + Dictionary bone=bones[i]; + String name=_id(bone["node"]); + + if (state.bones.has(name)) { + int idx=state.bones[name].skeleton->find_bone(name); + if (idx==-1) + idx=0; + index_map[i]=idx; + } + } + + + + int ilen=indices.size(); + { + DVector<float>::Write iw=indices.write(); + for(int j=0;j<ilen;j++) { + int b = iw[j]; + ERR_CONTINUE(!index_map.has(b)); + b=index_map[b]; + iw[j]=b; + } + } + + array[Mesh::ARRAY_BONES]=indices; + + + } + + m->add_surface(state.surface_cache[id].primitive,array); + m->surface_set_material(idx,mat); + m->surface_set_name(idx,id); + } + +} + +Error EditorSceneImporterFBXConv::_parse_nodes(State& state,const Array &p_nodes,Node* p_base) { + + for(int i=0;i<p_nodes.size();i++) { + + Dictionary n = p_nodes[i]; + Spatial *node=NULL; + bool skip=false; + + String id; + if (n.has("id")) { + id=_id(n["id"]); + } + + print_line("ID: "+id); + + if (state.skeletons.has(id)) { + + Skeleton *skeleton = state.skeletons[id]; + node=skeleton; + skeleton->localize_rests(); + print_line("IS SKELETON! "); + } else if (state.bones.has(id)) { + if (p_base) + node=p_base->cast_to<Spatial>(); + if (!state.bones[id].has_anim_chan) { + print_line("no has anim "+id); + } + skip=true; + } else if (n.has("parts")) { + //is a mesh + MeshInstance *mesh = memnew( MeshInstance ); + node=mesh; + + Array parts=n["parts"]; + String long_identifier; + for(int j=0;j<parts.size();j++) { + + Dictionary part=parts[j]; + if (part.has("meshpartid")) { + String partid=part["meshpartid"]; + long_identifier+=partid; + } + } + + Ref<Mesh> m; + + if (state.mesh_cache.has(long_identifier)) { + m=state.mesh_cache[long_identifier]; + } else { + m = Ref<Mesh>( memnew( Mesh ) ); + + //and parts are surfaces + for(int j=0;j<parts.size();j++) { + + Dictionary part=parts[j]; + if (part.has("meshpartid")) { + _add_surface(state,m,part); + } + } + + + state.mesh_cache[long_identifier]=m; + } + + mesh->set_mesh(m); + } + + if (!skip) { + + if (!node) { + node = memnew( Spatial ); + } + + node->set_name(id); + node->set_transform(_get_transform(n)); + p_base->add_child(node); + node->set_owner(state.scene); + } + + + if (n.has("children")) { + Error err = _parse_nodes(state,n["children"],node); + if (err) + return err; + } + } + + return OK; +} + + +void EditorSceneImporterFBXConv::_parse_materials(State& state) { + + for(int i=0;i<state.materials.size();i++) { + + Dictionary material = state.materials[i]; + + ERR_CONTINUE(!material.has("id")); + String id = _id(material["id"]); + + Ref<FixedMaterial> mat = memnew( FixedMaterial ); + + if (material.has("diffuse")) { + mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"])); + } + + if (material.has("specular")) { + mat->set_parameter(FixedMaterial::PARAM_SPECULAR,_get_color(material["specular"])); + } + + if (material.has("emissive")) { + mat->set_parameter(FixedMaterial::PARAM_EMISSION,_get_color(material["emissive"])); + } + + if (material.has("shininess")) { + float exp = material["shininess"]; + mat->set_parameter(FixedMaterial::PARAM_SPECULAR_EXP,exp); + } + + if (material.has("opacity")) { + Color c = mat->get_parameter(FixedMaterial::PARAM_DIFFUSE); + c.a=material["opacity"]; + mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,c); + } + + + if (material.has("textures")) { + + Array textures = material["textures"]; + for(int j=0;j<textures.size();j++) { + + Dictionary texture=textures[j]; + Ref<Texture> tex; + if (texture.has("filename")) { + + + String filename=texture["filename"]; + String path=state.base_path+"/"+filename.replace("\\","/"); + if (state.texture_cache.has(path)) { + tex=state.texture_cache[path]; + } else { + tex = ResourceLoader::load(path,"ImageTexture"); + if (tex.is_null()) { + if (state.missing_deps) + state.missing_deps->push_back(path); + } + state.texture_cache[path]=tex; //add anyway + } + } + + if (tex.is_valid() && texture.has("type")) { + + String type=texture["type"]; + if (type=="DIFFUSE") + mat->set_texture(FixedMaterial::PARAM_DIFFUSE,tex); + else if (type=="SPECULAR") + mat->set_texture(FixedMaterial::PARAM_SPECULAR,tex); + else if (type=="SHININESS") + mat->set_texture(FixedMaterial::PARAM_SPECULAR_EXP,tex); + else if (type=="NORMAL") + mat->set_texture(FixedMaterial::PARAM_NORMAL,tex); + else if (type=="EMISSIVE") + mat->set_texture(FixedMaterial::PARAM_EMISSION,tex); + } + + } + } + + state.material_cache[id]=mat; + + } + +} + +void EditorSceneImporterFBXConv::_parse_surfaces(State& state) { + + for(int i=0;i<state.meshes.size();i++) { + + Dictionary mesh = state.meshes[i]; + + ERR_CONTINUE(!mesh.has("attributes")); + ERR_CONTINUE(!mesh.has("vertices")); + ERR_CONTINUE(!mesh.has("parts")); + + print_line("MESH #"+itos(i)); + + Array attrlist=mesh["attributes"]; + Array vertices=mesh["vertices"]; + bool exists[Mesh::ARRAY_MAX]; + int ofs[Mesh::ARRAY_MAX]; + int weight_max=0; + int binormal_ofs=-1; + int weight_ofs[4]; + + for(int j=0;j<Mesh::ARRAY_MAX;j++) { + exists[j]=false; + ofs[j]=0; + } + exists[Mesh::ARRAY_INDEX]=true; + float stride=0; + + for(int j=0;j<attrlist.size();j++) { + + String attr=attrlist[j]; + if (attr=="POSITION") { + exists[Mesh::ARRAY_VERTEX]=true; + ofs[Mesh::ARRAY_VERTEX]=stride; + stride+=3; + } else if (attr=="NORMAL") { + exists[Mesh::ARRAY_NORMAL]=true; + ofs[Mesh::ARRAY_NORMAL]=stride; + stride+=3; + } else if (attr=="COLOR") { + exists[Mesh::ARRAY_COLOR]=true; + ofs[Mesh::ARRAY_COLOR]=stride; + stride+=4; + } else if (attr=="COLORPACKED") { + stride+=1; //ignore + } else if (attr=="TANGENT") { + exists[Mesh::ARRAY_TANGENT]=true; + ofs[Mesh::ARRAY_TANGENT]=stride; + stride+=3; + } else if (attr=="BINORMAL") { + binormal_ofs=stride; + stride+=3; + } else if (attr=="TEXCOORD0") { + exists[Mesh::ARRAY_TEX_UV]=true; + ofs[Mesh::ARRAY_TEX_UV]=stride; + stride+=2; + } else if (attr=="TEXCOORD1") { + exists[Mesh::ARRAY_TEX_UV2]=true; + ofs[Mesh::ARRAY_TEX_UV2]=stride; + stride+=2; + } else if (attr.begins_with("TEXCOORD")) { + stride+=2; + } else if (attr.begins_with("BLENDWEIGHT")) { + int idx=attr.replace("BLENDWEIGHT","").to_int(); + if (idx==0) { + exists[Mesh::ARRAY_BONES]=true; + ofs[Mesh::ARRAY_BONES]=stride; + exists[Mesh::ARRAY_WEIGHTS]=true; + ofs[Mesh::ARRAY_WEIGHTS]=stride+1; + } if (idx<4) { + weight_ofs[idx]=stride; + weight_max=MAX(weight_max,idx+1); + } + + stride+=2; + } + + print_line("ATTR "+attr+" OFS: "+itos(stride)); + + } + + Array parts=mesh["parts"]; + + for(int j=0;j<parts.size();j++) { + + + + Dictionary part=parts[j]; + ERR_CONTINUE(!part.has("indices")); + ERR_CONTINUE(!part.has("id")); + + print_line("PART: "+String(part["id"])); + Array indices=part["indices"]; + Map<int,int> iarray; + Map<int,int> array; + + for(int k=0;k<indices.size();k++) { + + int idx = indices[k]; + if (!iarray.has(idx)) { + int map_to=array.size(); + iarray[idx]=map_to; + array[map_to]=idx; + } + } + + print_line("indices total "+itos(indices.size())+" vertices used: "+itos(array.size())); + + Array arrays; + arrays.resize(Mesh::ARRAY_MAX); + + + + for(int k=0;k<Mesh::ARRAY_MAX;k++) { + + + if (!exists[k]) + continue; + print_line("exists: "+itos(k)); + int lofs = ofs[k]; + switch(k) { + + case Mesh::ARRAY_VERTEX: + case Mesh::ARRAY_NORMAL: { + + DVector<Vector3> vtx; + vtx.resize(array.size()); + { + int len=array.size(); + DVector<Vector3>::Write w = vtx.write(); + for(int l=0;l<len;l++) { + + int pos = array[l]; + w[l].x=vertices[pos*stride+lofs+0]; + w[l].y=vertices[pos*stride+lofs+1]; + w[l].z=vertices[pos*stride+lofs+2]; + } + } + arrays[k]=vtx; + + } break; + case Mesh::ARRAY_TANGENT: { + + if (binormal_ofs<0) + break; + + DVector<float> tangents; + tangents.resize(array.size()*4); + { + int len=array.size(); + + DVector<float>::Write w = tangents.write(); + for(int l=0;l<len;l++) { + + int pos = array[l]; + Vector3 n; + n.x=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+0]; + n.y=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+1]; + n.z=vertices[pos*stride+ofs[Mesh::ARRAY_NORMAL]+2]; + Vector3 t; + t.x=vertices[pos*stride+lofs+0]; + t.y=vertices[pos*stride+lofs+1]; + t.z=vertices[pos*stride+lofs+2]; + Vector3 bi; + bi.x=vertices[pos*stride+binormal_ofs+0]; + bi.y=vertices[pos*stride+binormal_ofs+1]; + bi.z=vertices[pos*stride+binormal_ofs+2]; + float d = bi.dot(n.cross(t)); + + w[l*4+0]=t.x; + w[l*4+1]=t.y; + w[l*4+2]=t.z; + w[l*4+3]=d; + + } + } + arrays[k]=tangents; + + } break; + case Mesh::ARRAY_COLOR: { + + DVector<Color> cols; + cols.resize(array.size()); + { + int len=array.size(); + DVector<Color>::Write w = cols.write(); + for(int l=0;l<len;l++) { + + int pos = array[l]; + w[l].r=vertices[pos*stride+lofs+0]; + w[l].g=vertices[pos*stride+lofs+1]; + w[l].b=vertices[pos*stride+lofs+2]; + w[l].a=vertices[pos*stride+lofs+3]; + } + } + arrays[k]=cols; + + } break; + case Mesh::ARRAY_TEX_UV: + case Mesh::ARRAY_TEX_UV2: { + + DVector<Vector2> uvs; + uvs.resize(array.size()); + { + int len=array.size(); + DVector<Vector2>::Write w = uvs.write(); + for(int l=0;l<len;l++) { + + int pos = array[l]; + w[l].x=vertices[pos*stride+lofs+0]; + w[l].y=vertices[pos*stride+lofs+1]; + w[l].y=1.0-w[l].y; + } + } + arrays[k]=uvs; + + } break; + case Mesh::ARRAY_BONES: + case Mesh::ARRAY_WEIGHTS: { + + DVector<float> arr; + arr.resize(array.size()*4); + int po=k==Mesh::ARRAY_WEIGHTS?1:0; + lofs=ofs[Mesh::ARRAY_BONES]; + { + int len=array.size(); + + DVector<float>::Write w = arr.write(); + for(int l=0;l<len;l++) { + + int pos = array[l]; + + for(int m=0;m<4;m++) { + + float val=0; + if (m<=weight_max) + val=vertices[pos*stride+lofs+m*2+po]; + w[l*4+m]=val; + } + } + } + + arrays[k]=arr; + } break; + case Mesh::ARRAY_INDEX: { + + DVector<int> arr; + arr.resize(indices.size()); + { + int len=indices.size(); + + DVector<int>::Write w = arr.write(); + for(int l=0;l<len;l++) { + + w[l]=iarray[ indices[l] ]; + } + } + + arrays[k]=arr; + + } break; + + + } + + + } + + Mesh::PrimitiveType pt=Mesh::PRIMITIVE_TRIANGLES; + + if (part.has("type")) { + String type=part["type"]; + if (type=="LINES") + pt=Mesh::PRIMITIVE_LINES; + else if (type=="POINTS") + pt=Mesh::PRIMITIVE_POINTS; + else if (type=="TRIANGLE_STRIP") + pt=Mesh::PRIMITIVE_TRIANGLE_STRIP; + else if (type=="LINE_STRIP") + pt=Mesh::PRIMITIVE_LINE_STRIP; + } + + if (pt==Mesh::PRIMITIVE_TRIANGLES) { + DVector<int> ia=arrays[Mesh::ARRAY_INDEX]; + int len=ia.size(); + { + DVector<int>::Write w=ia.write(); + for(int l=0;l<len;l+=3) { + SWAP(w[l+1],w[l+2]); + } + } + arrays[Mesh::ARRAY_INDEX]=ia; + + + } + SurfaceInfo si; + si.array=arrays; + si.primitive=pt; + state.surface_cache[_id(part["id"])]=si; + + } + } +} + + +Error EditorSceneImporterFBXConv::_parse_animations(State& state) { + + AnimationPlayer *ap = memnew( AnimationPlayer ); + + state.scene->add_child(ap); + ap->set_owner(state.scene); + + for(int i=0;i<state.animations.size();i++) { + + Dictionary anim = state.animations[i]; + ERR_CONTINUE(!anim.has("id")); + Ref<Animation> an = memnew( Animation ); + an->set_name(_id(anim["id"])); + + + if (anim.has("bones")) { + + Array bone_tracks = anim["bones"]; + for(int j=0;j<bone_tracks.size();j++) { + Dictionary bone_track=bone_tracks[j]; + String bone = bone_track["boneId"]; + if (!bone_track.has("keyframes")) + continue; + if (!state.bones.has(bone)) + continue; + + Skeleton *sk = state.bones[bone].skeleton; + + if (!sk) + continue; + int bone_idx=sk->find_bone(bone); + if (bone_idx==-1) + continue; + + + + String path = state.scene->get_path_to(sk); + path+=":"+bone; + an->add_track(Animation::TYPE_TRANSFORM); + int tidx = an->get_track_count()-1; + an->track_set_path(tidx,path); + + + Dictionary parent_xform_dict; + Dictionary xform_dict; + + if (state.bones.has(bone)) { + xform_dict=state.bones[bone].node; + } + + + Array parent_keyframes; + if (sk->get_bone_parent(bone_idx)!=-1) { + String parent_name = sk->get_bone_name(sk->get_bone_parent(bone_idx)); + if (state.bones.has(parent_name)) { + parent_xform_dict=state.bones[parent_name].node; + } + + print_line("parent for "+bone+"? "+parent_name+" XFD: "+String(Variant(parent_xform_dict))); + for(int k=0;k<bone_tracks.size();k++) { + Dictionary d = bone_tracks[k]; + if (d["boneId"]==parent_name) { + parent_keyframes=d["keyframes"]; + print_line("found keyframes"); + break; + } + } + + + } + + print_line("BONE XFD "+String(Variant(xform_dict))); + + Array keyframes=bone_track["keyframes"]; + + for(int k=0;k<keyframes.size();k++) { + + Dictionary key=keyframes[k]; + Transform xform=_get_transform_mixed(key,xform_dict); + float time = key["keytime"]; + time=time/1000.0; +#if 0 + if (parent_keyframes.size()) { + //localize + print_line(itos(k)+" localizate for: "+bone); + + float prev_kt=-1; + float kt; + int idx=0; + + for(int l=0;l<parent_keyframes.size();l++) { + + Dictionary d=parent_keyframes[l]; + kt=d["keytime"]; + kt=kt/1000.0; + if (kt>time) + break; + prev_kt=kt; + idx++; + + } + + Transform t; + if (idx==0) { + t=_get_transform_mixed(parent_keyframes[0],parent_xform_dict); + } else if (idx==parent_keyframes.size()){ + t=_get_transform_mixed(parent_keyframes[idx-1],parent_xform_dict); + } else { + t=_get_transform_mixed(parent_keyframes[idx-1],parent_xform_dict); + float d = (time-prev_kt)/(kt-prev_kt); + if (d>0) { + Transform t2=_get_transform_mixed(parent_keyframes[idx],parent_xform_dict); + t=t.interpolate_with(t2,d); + } else { + print_line("exact: "+rtos(kt)); + } + } + + xform = t.affine_inverse() * xform; //localize + } else if (!parent_xform_dict.empty()) { + Transform t = _get_transform(parent_xform_dict); + xform = t.affine_inverse() * xform; //localize + } +#endif + + xform = sk->get_bone_rest(bone_idx).affine_inverse() * xform; + + + Quat q = xform.basis; + q.normalize(); + Vector3 s = xform.basis.get_scale(); + Vector3 l = xform.origin; + + + + an->transform_track_insert_key(tidx,time,l,q,s); + + } + + } + + + } + + + ap->add_animation(_id(anim["id"]),an); + + } + + return OK; +} + +Error EditorSceneImporterFBXConv::_parse_json(State& state, const String &p_path) { + + //not the happiest.... + Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); + ERR_FAIL_COND_V(!data.size(),ERR_FILE_CANT_OPEN); + String str; + bool utferr = str.parse_utf8((const char*)data.ptr(),data.size()); + ERR_FAIL_COND_V(utferr,ERR_PARSE_ERROR); + + Dictionary dict; + Error err = dict.parse_json(str); + str=String(); //free mem immediately + ERR_FAIL_COND_V(err,err); + + if (dict.has("meshes")) + state.meshes=dict["meshes"]; + if (dict.has("materials")) + state.materials=dict["materials"]; + if (dict.has("nodes")) + state.nodes=dict["nodes"]; + if (dict.has("animations")) + state.animations=dict["animations"]; + + + state.scene = memnew( Spatial ); + _detect_bones(state); + _parse_surfaces(state); + _parse_materials(state); + err = _parse_nodes(state,state.nodes,state.scene); + if (err) + return err; + + if (state.import_animations) { + err = _parse_animations(state); + if (err) + return err; + } + + print_line("JSON PARSED O-K!"); + + return OK; +} + +Error EditorSceneImporterFBXConv::_parse_fbx(State& state,const String& p_path) { + + state.base_path=p_path.get_base_dir(); + + if (p_path.to_lower().ends_with("g3dj")) { + return _parse_json(state,p_path.basename()+".g3dj"); + } + + String tool = EDITOR_DEF("fbxconv/path",""); + ERR_FAIL_COND_V( !FileAccess::exists(tool),ERR_UNCONFIGURED); + String wine = EDITOR_DEF("fbxconv/use_wine",""); + + List<String> args; + String path=p_path; + if (wine!="") { + List<String> wpargs; + wpargs.push_back("-w"); + wpargs.push_back(p_path); + String pipe; //winepath to convert to windows path + int wpres; + Error wperr = OS::get_singleton()->execute(wine+"path",wpargs,true,NULL,&pipe,&wpres); + ERR_FAIL_COND_V(wperr!=OK,ERR_CANT_CREATE); + ERR_FAIL_COND_V(wpres!=0,ERR_CANT_CREATE); + path=pipe.strip_edges(); + args.push_back(tool); + tool=wine; + } + + args.push_back("-o"); + args.push_back("G3DJ"); + args.push_back(path); + + int res; + Error err = OS::get_singleton()->execute(tool,args,true,NULL,NULL,&res); + ERR_FAIL_COND_V(err!=OK,ERR_CANT_CREATE); + ERR_FAIL_COND_V(res!=0,ERR_CANT_CREATE); + + return _parse_json(state,p_path.basename()+".g3dj"); + + +} + +Node* EditorSceneImporterFBXConv::import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps,Error* r_err){ + + State state; + state.scene=NULL; + state.missing_deps=r_missing_deps; + state.import_animations=p_flags&IMPORT_ANIMATION; + Error err = _parse_fbx(state,p_path); + if (err!=OK) { + if (r_err) + *r_err=err; + return NULL; + } + + + return state.scene; +} +Ref<Animation> EditorSceneImporterFBXConv::import_animation(const String& p_path,uint32_t p_flags){ + + + return Ref<Animation>(); +} + + +EditorSceneImporterFBXConv::EditorSceneImporterFBXConv() { + + EDITOR_DEF("fbxconv/path",""); +#ifndef WINDOWS_ENABLED + EDITOR_DEF("fbxconv/use_wine",""); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/use_wine",PROPERTY_HINT_GLOBAL_FILE)); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/path",PROPERTY_HINT_GLOBAL_FILE)); +#else + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"fbxconv/path",PROPERTY_HINT_GLOBAL_FILE,"exe")); +#endif + +} diff --git a/tools/editor/io_plugins/editor_scene_importer_fbxconv.h b/tools/editor/io_plugins/editor_scene_importer_fbxconv.h new file mode 100644 index 0000000000..261b072b04 --- /dev/null +++ b/tools/editor/io_plugins/editor_scene_importer_fbxconv.h @@ -0,0 +1,81 @@ +#ifndef EDITOR_SCENE_IMPORTER_FBXCONV_H +#define EDITOR_SCENE_IMPORTER_FBXCONV_H + +#include "tools/editor/io_plugins/editor_scene_import_plugin.h" +#include "scene/3d/skeleton.h" + + +class EditorSceneImporterFBXConv : public EditorSceneImporter { + + OBJ_TYPE(EditorSceneImporterFBXConv,EditorSceneImporter ); + + + struct BoneInfo { + + Skeleton *skeleton; + Transform rest; + int index; + bool has_anim_chan; + bool has_rest; + Dictionary node; + BoneInfo() { + has_rest=false; + skeleton=NULL; + index=-1; + has_anim_chan=false; + } + }; + + struct SurfaceInfo { + Array array; + Mesh::PrimitiveType primitive; + }; + + struct State { + + Node *scene; + Array meshes; + Array materials; + Array nodes; + Array animations; + Map<String,BoneInfo > bones; + Map<String,Skeleton*> skeletons; + Map<String,Ref<Mesh> > mesh_cache; + Map<String,SurfaceInfo> surface_cache; + Map<String,Ref<Material> > material_cache; + Map<String,Ref<Texture> > texture_cache; + List<String> *missing_deps; + String base_path; + bool import_animations; + }; + + String _id(const String& p_id) const; + + Transform _get_transform_mixed(const Dictionary& d, const Dictionary& dbase); + Transform _get_transform(const Dictionary& d); + Color _get_color(const Array& a); + void _detect_bones_in_nodes(State& state,const Array& p_nodes); + void _detect_bones(State& state); + + Error _parse_bones(State& state,const Array &p_bones,Skeleton* p_skeleton); + void _parse_skeletons(const String& p_name,State& state, const Array &p_nodes, Skeleton*p_skeleton=NULL, int p_parent=-1); + + void _add_surface(State& state,Ref<Mesh>& m,const Dictionary &part); + Error _parse_nodes(State& state,const Array &p_nodes,Node* p_base); + Error _parse_animations(State& state); + void _parse_materials(State& state); + void _parse_surfaces(State& state); + Error _parse_json(State& state,const String& p_path); + Error _parse_fbx(State &state, const String &p_path); + +public: + + virtual uint32_t get_import_flags() const; + virtual void get_extensions(List<String> *r_extensions) const; + virtual Node* import_scene(const String& p_path,uint32_t p_flags,List<String> *r_missing_deps=NULL,Error* r_err=NULL); + virtual Ref<Animation> import_animation(const String& p_path,uint32_t p_flags); + + EditorSceneImporterFBXConv(); +}; + +#endif // EDITOR_SCENE_IMPORTER_FBXCONV_H diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp index 1fa4d8d06c..2be6d3da24 100644 --- a/tools/editor/plugins/baked_light_baker.cpp +++ b/tools/editor/plugins/baked_light_baker.cpp @@ -720,7 +720,7 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, float intensity = 1.0 - (d/r)*(d/r); //not gauss but.. float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]))); intensity*=pow(damp,edge_damp); - //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); + intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); octant.light[p_light_index].accum[i][0]+=p_light.r*intensity; octant.light[p_light_index].accum[i][1]+=p_light.g*intensity; octant.light[p_light_index].accum[i][2]+=p_light.b*intensity; @@ -1023,7 +1023,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons if (!p_first_bounce) { - float r = plot_size * cell_size; + float r = plot_size * cell_size*4; if (ret<r) { //avoid accumulaiton of light on corners //plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 1bf425f3f3..e9020c91f5 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2345,8 +2345,7 @@ void SpatialEditor::set_state(const Dictionary& p_state) { bool use = d["show_grid"]; if (use!=view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) { - view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), use ); - grid_enabled=use; + _menu_item_pressed(MENU_VIEW_GRID); } } @@ -2653,6 +2652,13 @@ void SpatialEditor::_menu_item_pressed(int p_option) { grid_enabled=!is_checked; + for(int i=0;i<3;++i) { + if (grid_enable[i]) { + VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,grid_enabled); + grid_visible[i]=grid_enabled; + } + } + view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(p_option), grid_enabled ); diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index 83efb48bd3..c5bf43884e 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -2100,6 +2100,101 @@ VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier* p_notifier) set_spatial_node(p_notifier);
}
+////////
+
+
+
+void NavigationMeshSpatialGizmo::redraw() {
+
+ clear();
+ Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
+ if (navmeshie.is_null())
+ return;
+
+ DVector<Vector3> vertices = navmeshie->get_vertices();
+ DVector<Vector3>::Read vr=vertices.read();
+ List<Face3> faces;
+ for(int i=0;i<navmeshie->get_polygon_count();i++) {
+ Vector<int> p = navmeshie->get_polygon(i);
+
+ for(int j=2;j<p.size();j++) {
+ Face3 f;
+ f.vertex[0]=vr[p[0]];
+ f.vertex[1]=vr[p[j-1]];
+ f.vertex[2]=vr[p[j]];
+
+ faces.push_back(f);
+ }
+ }
+
+
+ Map<_EdgeKey,bool> edge_map;
+ DVector<Vector3> tmeshfaces;
+ tmeshfaces.resize(faces.size()*3);
+
+ {
+ DVector<Vector3>::Write tw=tmeshfaces.write();
+ int tidx=0;
+
+
+ for(List<Face3>::Element *E=faces.front();E;E=E->next()) {
+
+ const Face3 &f = E->get();
+
+ for(int j=0;j<3;j++) {
+
+ tw[tidx++]=f.vertex[j];
+ _EdgeKey ek;
+ ek.from=f.vertex[j].snapped(CMP_EPSILON);
+ ek.to=f.vertex[(j+1)%3].snapped(CMP_EPSILON);
+ if (ek.from<ek.to)
+ SWAP(ek.from,ek.to);
+
+ Map<_EdgeKey,bool>::Element *E=edge_map.find(ek);
+
+ if (E) {
+
+ E->get()=false;
+
+ } else {
+
+ edge_map[ek]=true;
+ }
+
+ }
+ }
+ }
+ Vector<Vector3> lines;
+
+ for(Map<_EdgeKey,bool>::Element *E=edge_map.front();E;E=E->next()) {
+
+ if (E->get()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
+ }
+
+ Ref<TriangleMesh> tmesh = memnew( TriangleMesh);
+ tmesh->create(tmeshfaces);
+
+ add_lines(lines,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_edge_material:SpatialEditorGizmos::singleton->navmesh_edge_material_disabled);
+ add_collision_triangles(tmesh);
+ Ref<Mesh> m = memnew( Mesh );
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[0]=tmeshfaces;
+ m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+ m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
+ add_mesh(m);
+ add_collision_segments(lines);
+
+}
+
+NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh){
+
+ set_spatial_node(p_navmesh);
+ navmesh=p_navmesh;
+}
////////
@@ -2144,6 +2239,12 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg;
}
+ if (p_spatial->cast_to<NavigationMeshInstance>()) {
+
+ Ref<NavigationMeshSpatialGizmo> misg = memnew( NavigationMeshSpatialGizmo(p_spatial->cast_to<NavigationMeshInstance>()) );
+ return misg;
+ }
+
if (p_spatial->cast_to<RayCast>()) {
Ref<RayCastSpatialGizmo> misg = memnew( RayCastSpatialGizmo(p_spatial->cast_to<RayCast>()) );
@@ -2209,6 +2310,17 @@ Ref<FixedMaterial> SpatialEditorGizmos::create_line_material(const Color& p_base }
+Ref<FixedMaterial> SpatialEditorGizmos::create_solid_material(const Color& p_base_color) {
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color);
+
+ return line_material;
+
+}
+
SpatialEditorGizmos::SpatialEditorGizmos() {
singleton=this;
@@ -2249,6 +2361,16 @@ SpatialEditorGizmos::SpatialEditorGizmos() { camera_material = create_line_material(Color(1.0,0.5,1.0));
+ navmesh_edge_material = create_line_material(Color(0.1,0.8,1.0));
+ navmesh_solid_material = create_solid_material(Color(0.1,0.8,1.0,0.4));
+ navmesh_edge_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
+ navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+
+ navmesh_edge_material_disabled = create_line_material(Color(1.0,0.8,0.1));
+ navmesh_solid_material_disabled = create_solid_material(Color(1.0,0.8,0.1,0.4));
+ navmesh_edge_material_disabled->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
+ navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+
skeleton_material = create_line_material(Color(0.6,1.0,0.3));
skeleton_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
skeleton_material->set_flag(Material::FLAG_UNSHADED,true);
diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 8176157bc9..e5c3417166 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -43,6 +43,7 @@ #include "scene/3d/visibility_notifier.h"
#include "scene/3d/portal.h"
#include "scene/3d/ray_cast.h"
+#include "scene/3d/navigation_mesh.h"
#include "scene/3d/car_body.h"
@@ -327,11 +328,36 @@ public: };
+class NavigationMeshSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(NavigationMeshSpatialGizmo,SpatialGizmoTool);
+
+
+ struct _EdgeKey {
+
+ Vector3 from;
+ Vector3 to;
+
+ bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
+ };
+
+
+
+ NavigationMeshInstance* navmesh;
+
+public:
+
+ void redraw();
+ NavigationMeshSpatialGizmo(NavigationMeshInstance* p_navmesh=NULL);
+
+};
+
class SpatialEditorGizmos {
public:
Ref<FixedMaterial> create_line_material(const Color& p_base_color);
+ Ref<FixedMaterial> create_solid_material(const Color& p_base_color);
Ref<FixedMaterial> handle2_material;
Ref<FixedMaterial> handle_material;
Ref<FixedMaterial> light_material;
@@ -345,6 +371,12 @@ public: Ref<FixedMaterial> visibility_notifier_material;
Ref<FixedMaterial> car_wheel_material;
+ Ref<FixedMaterial> navmesh_edge_material;
+ Ref<FixedMaterial> navmesh_solid_material;
+ Ref<FixedMaterial> navmesh_edge_material_disabled;
+ Ref<FixedMaterial> navmesh_solid_material_disabled;
+
+
Ref<FixedMaterial> sample_player_icon;
Ref<FixedMaterial> stream_player_icon;
Ref<FixedMaterial> visibility_notifier_icon;
diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index 1a0cb37a17..15ec77cf8f 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -1030,7 +1030,7 @@ class DaeExporter: return [anim_id] - def export_animation(self,start,end): + def export_animation(self,start,end,allowed=None): #Blender -> Collada frames needs a little work #Collada starts from 0, blender usually from 1 @@ -1047,7 +1047,7 @@ class DaeExporter: # Change frames first, export objects last # This improves performance enormously - print("anim from: "+str(start)+" to "+str(end)) + print("anim from: "+str(start)+" to "+str(end)+" allowed: "+str(allowed)) for t in range(start,end+1): self.scene.frame_set(t) key = t * frame_len - frame_sub @@ -1057,6 +1057,8 @@ class DaeExporter: if (not node in self.valid_nodes): continue + if (allowed!=None and not (node in allowed)): + continue if (node.type=="MESH" and node.parent and node.parent.type=="ARMATURE"): continue #In Collada, nodes that have skin modifier must not export animation, animate the skin instead. @@ -1080,6 +1082,7 @@ class DaeExporter: bone_name=self.skeleton_info[node]["bone_ids"][bone] if (not (bone_name in xform_cache)): + print("has bone: "+bone_name) xform_cache[bone_name]=[] posebone = node.pose.bones[bone.name] @@ -1113,12 +1116,33 @@ class DaeExporter: for x in bpy.data.actions[:]: if x in self.action_constraints: continue + + bones=[] + #find bones used + for p in x.fcurves: + dp = str(p.data_path) + base = "pose.bones[\"" + if (dp.find(base)==0): + dp=dp[len(base):] + if (dp.find('"')!=-1): + dp=dp[:dp.find('"')] + if (not dp in bones): + bones.append(dp) + + allowed_skeletons=[] for y in self.skeletons: if (y.animation_data): + for z in y.pose.bones: + if (z.bone.name in bones): + if (not y in allowed_skeletons): + allowed_skeletons.append(y) y.animation_data.action=x; - tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1])) + + print(str(x)) + + tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1]),allowed_skeletons) framelen=(1.0/self.scene.render.fps) start = x.frame_range[0]*framelen end = x.frame_range[1]*framelen diff --git a/tools/pck/SCsub b/tools/pck/SCsub new file mode 100644 index 0000000000..b1fed9a472 --- /dev/null +++ b/tools/pck/SCsub @@ -0,0 +1,5 @@ +Import('env') + +if env["tools"] == "yes": + env.add_source_files(env.tool_sources, "*.cpp") + diff --git a/tools/pck/pck_packer.cpp b/tools/pck/pck_packer.cpp new file mode 100644 index 0000000000..aade9fafe1 --- /dev/null +++ b/tools/pck/pck_packer.cpp @@ -0,0 +1,162 @@ +#include "pck_packer.h" + +#include "core/os/file_access.h" + +static uint64_t _align(uint64_t p_n, int p_alignment) { + + if (p_alignment == 0) + return p_n; + + uint64_t rest = p_n % p_alignment; + if (rest == 0) + return p_n; + else + return p_n + (p_alignment - rest); +}; + +static void _pad(FileAccess* p_file, int p_bytes) { + + for (int i=0; i<p_bytes; i++) { + + p_file->store_8(0); + }; +}; + +void PCKPacker::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("pck_start","pck_name","alignment"),&PCKPacker::pck_start); + ObjectTypeDB::bind_method(_MD("add_file","pck_path","source_path"),&PCKPacker::add_file); + ObjectTypeDB::bind_method(_MD("flush"),&PCKPacker::flush); +}; + + +Error PCKPacker::pck_start(const String& p_file, int p_alignment) { + + file = FileAccess::open(p_file, FileAccess::WRITE); + if (file == NULL) { + + return ERR_CANT_CREATE; + }; + + alignment = p_alignment; + + file->store_32(0x43504447); // MAGIC + file->store_32(0); // # version + file->store_32(0); // # major + file->store_32(0); // # minor + file->store_32(0); // # revision + + for (int i=0; i<16; i++) { + + file->store_32(0); // reserved + }; + + files.clear(); + + return OK; +}; + +Error PCKPacker::add_file(const String& p_file, const String& p_src) { + + FileAccess* f = FileAccess::open(p_src, FileAccess::READ); + if (!f) { + return ERR_FILE_CANT_OPEN; + }; + + File pf; + pf.path = p_file; + pf.src_path = p_src; + pf.size = f->get_len(); + pf.offset_offset = 0; + + files.push_back(pf); + + f->close(); + memdelete(f); + + return OK; +}; + +Error PCKPacker::flush(bool p_verbose) { + + if (!file) { + ERR_FAIL_COND_V(!file, ERR_INVALID_PARAMETER); + return ERR_INVALID_PARAMETER; + }; + + // write the index + + file->store_32(files.size()); + + for (int i=0; i<files.size(); i++) { + + file->store_pascal_string(files[i].path); + files[i].offset_offset = file->get_pos(); + file->store_64(0); // offset + file->store_64(files[i].size); // size + + // # empty md5 + file->store_32(0); + file->store_32(0); + file->store_32(0); + file->store_32(0); + }; + + + uint64_t ofs = file->get_pos(); + ofs = _align(ofs, alignment); + + _pad(file, ofs - file->get_pos()); + + const uint32_t buf_max = 65536; + uint8_t *buf = memnew_arr(uint8_t, buf_max); + + int count = 0; + for (int i=0; i<files.size(); i++) { + + FileAccess* src = FileAccess::open(files[i].src_path, FileAccess::READ); + uint64_t to_write = files[i].size; + while (to_write > 0) { + + int read = src->get_buffer(buf, MIN(to_write, buf_max)); + file->store_buffer(buf, read); + to_write -= read; + }; + + uint64_t pos = file->get_pos(); + file->seek(files[i].offset_offset); // go back to store the file's offset + file->store_64(ofs); + file->seek(pos); + + ofs = _align(ofs + files[i].size, alignment); + _pad(file, ofs - pos); + + src->close(); + memdelete(src); + count += 1; + if (p_verbose) { + if (count % 100 == 0) { + printf("%i/%i (%.2f\%)\r", count, files.size(), float(count) / files.size() * 100); + }; + }; + }; + + if (p_verbose) + printf("\n"); + + file->close(); + + return OK; +}; + +PCKPacker::PCKPacker() { + + file = NULL; +}; + +PCKPacker::~PCKPacker() { + if (file != NULL) { + memdelete(file); + }; + file = NULL; +}; diff --git a/tools/pck/pck_packer.h b/tools/pck/pck_packer.h new file mode 100644 index 0000000000..76752a6170 --- /dev/null +++ b/tools/pck/pck_packer.h @@ -0,0 +1,31 @@ +#include "core/object.h" + +class FileAccess; + +class PCKPacker : public Object { + + OBJ_TYPE(PCKPacker, Object); + + FileAccess* file; + int alignment; + + static void _bind_methods(); + + struct File { + + String path; + String src_path; + int size; + uint64_t offset_offset; + }; + Vector<File> files; + +public: + Error pck_start(const String& p_file, int p_alignment); + Error add_file(const String& p_file, const String& p_src); + Error flush(bool p_verbose = false); + + + PCKPacker(); + ~PCKPacker(); +}; |