2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* editor_import_collada.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2018-01-01 14:40:08 +01:00
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* 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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "editor_import_collada.h"
2017-01-16 08:04:19 +01:00
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2017-03-05 16:44:50 +01:00
# include "editor/collada/collada.h"
# include "editor/editor_node.h"
2014-02-10 02:10:30 +01:00
# include "scene/3d/camera.h"
# include "scene/3d/light.h"
# include "scene/3d/mesh_instance.h"
2017-03-05 16:44:50 +01:00
# include "scene/3d/path.h"
# include "scene/3d/skeleton.h"
# include "scene/3d/spatial.h"
# include "scene/animation/animation_player.h"
2014-02-10 02:10:30 +01:00
# include "scene/resources/animation.h"
# include "scene/resources/packed_scene.h"
2017-08-29 13:47:29 +02:00
# include "scene/resources/surface_tool.h"
2017-08-27 21:07:15 +02:00
2015-03-22 23:24:52 +01:00
# include <iostream>
2014-02-10 02:10:30 +01:00
struct ColladaImport {
Collada collada ;
Spatial * scene ;
Vector < Ref < Animation > > animations ;
struct NodeMap {
//String path;
Spatial * node ;
int bone ;
List < int > anim_tracks ;
2017-03-05 16:44:50 +01:00
NodeMap ( ) {
node = NULL ;
bone = - 1 ;
}
2014-02-10 02:10:30 +01:00
} ;
bool found_ambient ;
Color ambient ;
bool found_directional ;
bool force_make_tangents ;
2014-12-02 18:02:41 +01:00
bool apply_mesh_xform_to_vertices ;
2017-02-05 00:31:15 +01:00
bool use_mesh_builtin_materials ;
2014-11-02 15:31:01 +01:00
float bake_fps ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Map < String , NodeMap > node_map ; //map from collada node to engine node
Map < String , String > node_name_map ; //map from collada node to engine node
2017-06-07 23:18:55 +02:00
Map < String , Ref < ArrayMesh > > mesh_cache ;
2014-02-10 02:10:30 +01:00
Map < String , Ref < Curve3D > > curve_cache ;
Map < String , Ref < Material > > material_cache ;
2017-03-05 16:44:50 +01:00
Map < Collada : : Node * , Skeleton * > skeleton_map ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Map < Skeleton * , Map < String , int > > skeleton_bone_map ;
2014-02-10 02:10:30 +01:00
Set < String > valid_animated_nodes ;
Vector < int > valid_animated_properties ;
2017-03-05 16:44:50 +01:00
Map < String , bool > bones_with_animation ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error _populate_skeleton ( Skeleton * p_skeleton , Collada : : Node * p_node , int & r_bone , int p_parent ) ;
2014-12-02 18:02:41 +01:00
Error _create_scene_skeletons ( Collada : : Node * p_node ) ;
2014-02-10 02:10:30 +01:00
Error _create_scene ( Collada : : Node * p_node , Spatial * p_parent ) ;
2017-11-01 01:01:24 +01:00
Error _create_resources ( Collada : : Node * p_node , bool p_use_compression ) ;
2017-08-12 18:52:50 +02:00
Error _create_material ( const String & p_target ) ;
2017-11-01 01:01:24 +01:00
Error _create_mesh_surfaces ( bool p_optimize , Ref < ArrayMesh > & 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_controller , const Collada : : MorphControllerData * p_morph_data , Vector < Ref < ArrayMesh > > p_morph_meshes = Vector < Ref < ArrayMesh > > ( ) , bool p_use_compression = false , bool p_use_mesh_material = false ) ;
Error load ( const String & p_path , int p_flags , bool p_force_make_tangents = false , bool p_use_compression = false ) ;
2014-02-10 02:10:30 +01:00
void _fix_param_animation_tracks ( ) ;
2017-03-05 16:44:50 +01:00
void create_animation ( int p_clip , bool p_make_tracks_in_all_bones , bool p_import_value_tracks ) ;
2016-11-03 09:41:28 +01:00
void create_animations ( bool p_make_tracks_in_all_bones , bool p_import_value_tracks ) ;
2014-02-10 02:10:30 +01:00
Set < String > tracks_in_clips ;
Vector < String > missing_textures ;
void _pre_process_lights ( Collada : : Node * p_node ) ;
ColladaImport ( ) {
2017-03-05 16:44:50 +01:00
found_ambient = false ;
found_directional = false ;
force_make_tangents = false ;
apply_mesh_xform_to_vertices = true ;
bake_fps = 15 ;
2014-02-10 02:10:30 +01:00
}
} ;
2017-03-05 16:44:50 +01:00
Error ColladaImport : : _populate_skeleton ( Skeleton * p_skeleton , Collada : : Node * p_node , int & r_bone , int p_parent ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_node - > type ! = Collada : : Node : : TYPE_JOINT )
2014-02-10 02:10:30 +01:00
return OK ;
2017-03-05 16:44:50 +01:00
Collada : : NodeJoint * joint = static_cast < Collada : : NodeJoint * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
p_skeleton - > add_bone ( p_node - > name ) ;
2017-03-05 16:44:50 +01:00
if ( p_parent > = 0 )
p_skeleton - > set_bone_parent ( r_bone , p_parent ) ;
2014-02-10 02:10:30 +01:00
NodeMap nm ;
2017-03-05 16:44:50 +01:00
nm . node = p_skeleton ;
2014-02-10 02:10:30 +01:00
nm . bone = r_bone ;
2017-03-05 16:44:50 +01:00
node_map [ p_node - > id ] = nm ;
node_name_map [ p_node - > name ] = p_node - > id ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
skeleton_bone_map [ p_skeleton ] [ joint - > sid ] = r_bone ;
2014-02-10 02:10:30 +01:00
if ( collada . state . bone_rest_map . has ( joint - > sid ) ) {
2017-03-05 16:44:50 +01:00
p_skeleton - > set_bone_rest ( r_bone , collada . fix_transform ( collada . state . bone_rest_map [ joint - > sid ] ) ) ;
2014-02-10 02:10:30 +01:00
//should map this bone to something for animation?
} else {
2018-08-24 09:35:07 +02:00
WARN_PRINT ( " Collada: Joint has no rest. " ) ;
2014-02-10 02:10:30 +01:00
}
int id = r_bone + + ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error err = _populate_skeleton ( p_skeleton , p_node - > children [ i ] , r_bone , id ) ;
2014-02-10 02:10:30 +01:00
if ( err )
return err ;
}
return OK ;
}
void ColladaImport : : _pre_process_lights ( Collada : : Node * p_node ) {
2017-03-05 16:44:50 +01:00
if ( p_node - > type = = Collada : : Node : : TYPE_LIGHT ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Collada : : NodeLight * light = static_cast < Collada : : NodeLight * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
if ( collada . state . light_data_map . has ( light - > light ) ) {
Collada : : LightData & ld = collada . state . light_data_map [ light - > light ] ;
2017-03-05 16:44:50 +01:00
if ( ld . mode = = Collada : : LightData : : MODE_AMBIENT ) {
found_ambient = true ;
ambient = ld . color ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( ld . mode = = Collada : : LightData : : MODE_DIRECTIONAL ) {
found_directional = true ;
2014-02-10 02:10:30 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + )
2014-02-10 02:10:30 +01:00
_pre_process_lights ( p_node - > children [ i ] ) ;
}
2014-12-02 18:02:41 +01:00
Error ColladaImport : : _create_scene_skeletons ( Collada : : Node * p_node ) {
2017-03-05 16:44:50 +01:00
if ( p_node - > type = = Collada : : Node : : TYPE_SKELETON ) {
2014-12-02 18:02:41 +01:00
2017-03-05 16:44:50 +01:00
Skeleton * sk = memnew ( Skeleton ) ;
2014-12-02 18:02:41 +01:00
int bone = 0 ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
2014-12-02 18:02:41 +01:00
2017-03-05 16:44:50 +01:00
_populate_skeleton ( sk , p_node - > children [ i ] , bone , - 1 ) ;
2014-12-02 18:02:41 +01:00
}
sk - > localize_rests ( ) ; //after creating skeleton, rests must be localized...!
2017-03-05 16:44:50 +01:00
skeleton_map [ p_node ] = sk ;
2014-12-02 18:02:41 +01:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
2014-12-02 18:02:41 +01:00
Error err = _create_scene_skeletons ( p_node - > children [ i ] ) ;
if ( err )
return err ;
}
return OK ;
}
2014-02-10 02:10:30 +01:00
Error ColladaImport : : _create_scene ( Collada : : Node * p_node , Spatial * p_parent ) {
2017-03-05 16:44:50 +01:00
Spatial * node = NULL ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( p_node - > type ) {
2014-02-10 02:10:30 +01:00
case Collada : : Node : : TYPE_NODE : {
2017-03-05 16:44:50 +01:00
node = memnew ( Spatial ) ;
2014-02-10 02:10:30 +01:00
} break ;
case Collada : : Node : : TYPE_JOINT : {
return OK ; // do nothing
} break ;
case Collada : : Node : : TYPE_LIGHT : {
//node = memnew( Light)
2017-03-05 16:44:50 +01:00
Collada : : NodeLight * light = static_cast < Collada : : NodeLight * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
if ( collada . state . light_data_map . has ( light - > light ) ) {
Collada : : LightData & ld = collada . state . light_data_map [ light - > light ] ;
2017-03-05 16:44:50 +01:00
if ( ld . mode = = Collada : : LightData : : MODE_AMBIENT ) {
2014-02-10 02:10:30 +01:00
if ( found_directional )
return OK ; //do nothing not needed
2017-03-05 16:44:50 +01:00
if ( ! bool ( GLOBAL_DEF ( " collada/use_ambient " , false ) ) )
2014-02-10 02:10:30 +01:00
return OK ;
//well, it's an ambient light..
2017-03-05 16:44:50 +01:00
Light * l = memnew ( DirectionalLight ) ;
2017-01-14 12:26:56 +01:00
//l->set_color(Light::COLOR_AMBIENT,ld.color);
//l->set_color(Light::COLOR_DIFFUSE,Color(0,0,0));
//l->set_color(Light::COLOR_SPECULAR,Color(0,0,0));
2014-02-10 02:10:30 +01:00
node = l ;
2017-03-05 16:44:50 +01:00
} else if ( ld . mode = = Collada : : LightData : : MODE_DIRECTIONAL ) {
2014-02-10 02:10:30 +01:00
//well, it's an ambient light..
2017-03-05 16:44:50 +01:00
Light * l = memnew ( DirectionalLight ) ;
2017-01-14 12:26:56 +01:00
/*
if ( found_ambient ) //use it here
l - > set_color ( Light : : COLOR_AMBIENT , ambient ) ;
2014-02-10 02:10:30 +01:00
2017-01-14 12:26:56 +01:00
l - > set_color ( Light : : COLOR_DIFFUSE , ld . color ) ;
l - > set_color ( Light : : COLOR_SPECULAR , Color ( 1 , 1 , 1 ) ) ;
*/
2014-02-10 02:10:30 +01:00
node = l ;
} else {
Light * l ;
2017-03-05 16:44:50 +01:00
if ( ld . mode = = Collada : : LightData : : MODE_OMNI )
l = memnew ( OmniLight ) ;
2014-02-10 02:10:30 +01:00
else {
2017-03-05 16:44:50 +01:00
l = memnew ( SpotLight ) ;
2017-01-14 12:26:56 +01:00
//l->set_parameter(Light::PARAM_SPOT_ANGLE,ld.spot_angle);
//l->set_parameter(Light::PARAM_SPOT_ATTENUATION,ld.spot_exp);
2014-02-10 02:10:30 +01:00
}
//
2017-01-14 12:26:56 +01:00
//l->set_color(Light::COLOR_DIFFUSE,ld.color);
//l->set_color(Light::COLOR_SPECULAR,Color(1,1,1));
//l->approximate_opengl_attenuation(ld.constant_att,ld.linear_att,ld.quad_att);
2017-03-05 16:44:50 +01:00
node = l ;
2014-02-10 02:10:30 +01:00
}
} else {
2017-03-05 16:44:50 +01:00
node = memnew ( Spatial ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case Collada : : Node : : TYPE_CAMERA : {
2017-03-05 16:44:50 +01:00
Collada : : NodeCamera * cam = static_cast < Collada : : NodeCamera * > ( p_node ) ;
Camera * camera = memnew ( Camera ) ;
2014-02-10 02:10:30 +01:00
if ( collada . state . camera_data_map . has ( cam - > camera ) ) {
const Collada : : CameraData & cd = collada . state . camera_data_map [ cam - > camera ] ;
2017-03-05 16:44:50 +01:00
switch ( cd . mode ) {
2014-02-10 02:10:30 +01:00
case Collada : : CameraData : : MODE_ORTHOGONAL : {
2015-03-03 18:39:13 +01:00
if ( cd . orthogonal . y_mag ) {
2014-02-10 02:10:30 +01:00
2015-03-03 18:39:13 +01:00
camera - > set_keep_aspect_mode ( Camera : : KEEP_HEIGHT ) ;
2017-03-05 16:44:50 +01:00
camera - > set_orthogonal ( cd . orthogonal . y_mag * 2.0 , cd . z_near , cd . z_far ) ;
2014-02-10 02:10:30 +01:00
2015-03-03 18:39:13 +01:00
} else if ( ! cd . orthogonal . y_mag & & cd . orthogonal . x_mag ) {
2014-02-10 02:10:30 +01:00
2015-03-03 18:39:13 +01:00
camera - > set_keep_aspect_mode ( Camera : : KEEP_WIDTH ) ;
2017-03-05 16:44:50 +01:00
camera - > set_orthogonal ( cd . orthogonal . x_mag * 2.0 , cd . z_near , cd . z_far ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case Collada : : CameraData : : MODE_PERSPECTIVE : {
if ( cd . perspective . y_fov ) {
2017-03-05 16:44:50 +01:00
camera - > set_perspective ( cd . perspective . y_fov , cd . z_near , cd . z_far ) ;
2014-02-10 02:10:30 +01:00
} else if ( ! cd . perspective . y_fov & & cd . perspective . x_fov ) {
2017-03-05 16:44:50 +01:00
camera - > set_perspective ( cd . perspective . x_fov / cd . aspect , cd . z_near , cd . z_far ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
}
}
2017-03-05 16:44:50 +01:00
node = camera ;
2014-02-10 02:10:30 +01:00
} break ;
case Collada : : Node : : TYPE_GEOMETRY : {
2017-03-05 16:44:50 +01:00
Collada : : NodeGeometry * ng = static_cast < Collada : : NodeGeometry * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
if ( collada . state . curve_data_map . has ( ng - > source ) ) {
2017-03-05 16:44:50 +01:00
node = memnew ( Path ) ;
2014-02-10 02:10:30 +01:00
} else {
//mesh since nothing else
2017-03-05 16:44:50 +01:00
node = memnew ( MeshInstance ) ;
2018-10-07 16:18:27 +02:00
//Object::cast_to<MeshInstance>(node)->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT, true);
2014-02-10 02:10:30 +01:00
}
} break ;
case Collada : : Node : : TYPE_SKELETON : {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! skeleton_map . has ( p_node ) , ERR_CANT_CREATE ) ;
2014-12-02 18:02:41 +01:00
Skeleton * sk = skeleton_map [ p_node ] ;
2017-03-05 16:44:50 +01:00
node = sk ;
2014-02-10 02:10:30 +01:00
} break ;
}
2017-03-05 16:44:50 +01:00
if ( p_node - > name ! = " " )
2014-02-10 02:10:30 +01:00
node - > set_name ( p_node - > name ) ;
NodeMap nm ;
2017-03-05 16:44:50 +01:00
nm . node = node ;
node_map [ p_node - > id ] = nm ;
2018-05-22 12:58:28 +02:00
node_name_map [ node - > get_name ( ) ] = p_node - > id ;
2014-02-10 02:10:30 +01:00
Transform xf = p_node - > default_transform ;
2017-03-05 16:44:50 +01:00
xf = collada . fix_transform ( xf ) * p_node - > post_transform ;
2014-02-10 02:10:30 +01:00
node - > set_transform ( xf ) ;
p_parent - > add_child ( node ) ;
node - > set_owner ( scene ) ;
2017-03-05 16:44:50 +01:00
if ( p_node - > empty_draw_type ! = " " ) {
2016-06-05 20:59:21 +02:00
node - > set_meta ( " empty_draw_type " , Variant ( p_node - > empty_draw_type ) ) ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
Error err = _create_scene ( p_node - > children [ i ] , node ) ;
2014-02-10 02:10:30 +01:00
if ( err )
return err ;
}
return OK ;
}
2017-03-05 16:44:50 +01:00
Error ColladaImport : : _create_material ( const String & p_target ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( material_cache . has ( p_target ) , ERR_ALREADY_EXISTS ) ;
ERR_FAIL_COND_V ( ! collada . state . material_map . has ( p_target ) , ERR_INVALID_PARAMETER ) ;
Collada : : Material & src_mat = collada . state . material_map [ p_target ] ;
ERR_FAIL_COND_V ( ! collada . state . effect_map . has ( src_mat . instance_effect ) , ERR_INVALID_PARAMETER ) ;
Collada : : Effect & effect = collada . state . effect_map [ src_mat . instance_effect ] ;
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
Ref < SpatialMaterial > material = memnew ( SpatialMaterial ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( src_mat . name ! = " " )
2014-06-28 14:50:20 +02:00
material - > set_name ( src_mat . name ) ;
2017-03-05 16:44:50 +01:00
else if ( effect . name ! = " " )
2014-06-28 14:50:20 +02:00
material - > set_name ( effect . name ) ;
2014-02-10 02:10:30 +01:00
// DIFFUSE
2017-03-05 16:44:50 +01:00
if ( effect . diffuse . texture ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String texfile = effect . get_texture_path ( effect . diffuse . texture , collada ) ;
if ( texfile ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-09-21 01:59:19 +02:00
if ( texfile . begins_with ( " / " ) ) {
texfile = texfile . replace_first ( " / " , " res:// " ) ;
}
2017-03-05 16:44:50 +01:00
Ref < Texture > texture = ResourceLoader : : load ( texfile , " Texture " ) ;
2014-02-10 02:10:30 +01:00
if ( texture . is_valid ( ) ) {
2017-04-07 04:36:37 +02:00
material - > set_texture ( SpatialMaterial : : TEXTURE_ALBEDO , texture ) ;
2017-03-05 16:44:50 +01:00
material - > set_albedo ( Color ( 1 , 1 , 1 , 1 ) ) ;
2017-04-07 04:36:37 +02:00
//material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
2014-02-10 02:10:30 +01:00
} else {
missing_textures . push_back ( texfile . get_file ( ) ) ;
}
}
} else {
2017-08-15 16:41:17 +02:00
material - > set_albedo ( effect . diffuse . color ) ;
2014-02-10 02:10:30 +01:00
}
// SPECULAR
2017-03-05 16:44:50 +01:00
if ( effect . specular . texture ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String texfile = effect . get_texture_path ( effect . specular . texture , collada ) ;
if ( texfile ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-09-21 01:59:19 +02:00
if ( texfile . begins_with ( " / " ) ) {
texfile = texfile . replace_first ( " / " , " res:// " ) ;
}
2017-03-05 16:44:50 +01:00
Ref < Texture > texture = ResourceLoader : : load ( texfile , " Texture " ) ;
2014-02-10 02:10:30 +01:00
if ( texture . is_valid ( ) ) {
2017-06-01 01:16:38 +02:00
material - > set_texture ( SpatialMaterial : : TEXTURE_METALLIC , texture ) ;
material - > set_specular ( 1.0 ) ;
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
//material->set_texture(SpatialMaterial::PARAM_SPECULAR,texture);
//material->set_parameter(SpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
2014-02-10 02:10:30 +01:00
} else {
missing_textures . push_back ( texfile . get_file ( ) ) ;
}
}
2017-06-01 01:16:38 +02:00
2014-02-10 02:10:30 +01:00
} else {
2017-06-01 01:16:38 +02:00
material - > set_metallic ( effect . specular . color . get_v ( ) ) ;
2014-02-10 02:10:30 +01:00
}
// EMISSION
2017-03-05 16:44:50 +01:00
if ( effect . emission . texture ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String texfile = effect . get_texture_path ( effect . emission . texture , collada ) ;
if ( texfile ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-09-21 01:59:19 +02:00
if ( texfile . begins_with ( " / " ) ) {
texfile = texfile . replace_first ( " / " , " res:// " ) ;
}
2017-03-05 16:44:50 +01:00
Ref < Texture > texture = ResourceLoader : : load ( texfile , " Texture " ) ;
2014-02-10 02:10:30 +01:00
if ( texture . is_valid ( ) ) {
2017-04-07 04:36:37 +02:00
material - > set_feature ( SpatialMaterial : : FEATURE_EMISSION , true ) ;
material - > set_texture ( SpatialMaterial : : TEXTURE_EMISSION , texture ) ;
2017-03-05 16:44:50 +01:00
material - > set_emission ( Color ( 1 , 1 , 1 , 1 ) ) ;
2016-12-20 04:21:07 +01:00
2017-04-07 04:36:37 +02:00
//material->set_parameter(SpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
2017-03-05 16:44:50 +01:00
} else {
2017-02-06 04:38:39 +01:00
missing_textures . push_back ( texfile . get_file ( ) ) ;
2014-02-10 02:10:30 +01:00
}
}
} else {
2017-03-05 16:44:50 +01:00
if ( effect . emission . color ! = Color ( ) ) {
2017-04-07 04:36:37 +02:00
material - > set_feature ( SpatialMaterial : : FEATURE_EMISSION , true ) ;
2017-02-06 04:38:39 +01:00
material - > set_emission ( effect . emission . color ) ;
}
2014-02-10 02:10:30 +01:00
}
// NORMAL
2017-03-05 16:44:50 +01:00
if ( effect . bump . texture ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String texfile = effect . get_texture_path ( effect . bump . texture , collada ) ;
if ( texfile ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-09-21 01:59:19 +02:00
if ( texfile . begins_with ( " / " ) ) {
texfile = texfile . replace_first ( " / " , " res:// " ) ;
}
2017-03-05 16:44:50 +01:00
Ref < Texture > texture = ResourceLoader : : load ( texfile , " Texture " ) ;
2014-02-10 02:10:30 +01:00
if ( texture . is_valid ( ) ) {
2017-04-07 04:36:37 +02:00
material - > set_feature ( SpatialMaterial : : FEATURE_NORMAL_MAPPING , true ) ;
material - > set_texture ( SpatialMaterial : : TEXTURE_NORMAL , texture ) ;
2017-01-14 12:26:56 +01:00
//material->set_emission(Color(1,1,1,1));
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
//material->set_texture(SpatialMaterial::PARAM_NORMAL,texture);
2017-03-05 16:44:50 +01:00
} else {
2017-01-14 12:26:56 +01:00
//missing_textures.push_back(texfile.get_file());
2014-02-10 02:10:30 +01:00
}
}
}
2018-04-03 21:05:13 +02:00
float roughness = ( effect . shininess - 1.0 ) / 510 ;
2017-02-06 04:38:39 +01:00
material - > set_roughness ( roughness ) ;
2016-12-20 04:21:07 +01:00
if ( effect . double_sided ) {
2017-04-07 04:36:37 +02:00
material - > set_cull_mode ( SpatialMaterial : : CULL_DISABLED ) ;
2016-12-20 04:21:07 +01:00
}
2017-04-07 04:36:37 +02:00
material - > set_flag ( SpatialMaterial : : FLAG_UNSHADED , effect . unshaded ) ;
2014-06-28 14:50:20 +02:00
2017-03-05 16:44:50 +01:00
material_cache [ p_target ] = material ;
2014-02-10 02:10:30 +01:00
return OK ;
}
2017-11-01 01:01:24 +01:00
Error ColladaImport : : _create_mesh_surfaces ( bool p_optimize , Ref < ArrayMesh > & 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_controller , const Collada : : MorphControllerData * p_morph_data , Vector < Ref < ArrayMesh > > p_morph_meshes , bool p_use_compression , bool p_use_mesh_material ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool local_xform_mirror = p_local_xform . basis . determinant ( ) < 0 ;
2014-02-10 02:10:30 +01:00
if ( p_morph_data ) {
2014-09-03 04:13:40 +02:00
2014-02-10 02:10:30 +01:00
//add morphie target
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! p_morph_data - > targets . has ( " MORPH_TARGET " ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String mt = p_morph_data - > targets [ " MORPH_TARGET " ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! p_morph_data - > sources . has ( mt ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
int morph_targets = p_morph_data - > sources [ mt ] . sarray . size ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < morph_targets ; i + + ) {
2014-02-10 02:10:30 +01:00
String target = p_morph_data - > sources [ mt ] . sarray [ i ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! collada . state . mesh_data_map . has ( target ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String name = collada . state . mesh_data_map [ target ] . name ;
2017-01-12 12:34:00 +01:00
p_mesh - > add_blend_shape ( name ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( p_morph_data - > mode = = " RELATIVE " )
2017-01-12 12:34:00 +01:00
p_mesh - > set_blend_shape_mode ( Mesh : : BLEND_SHAPE_MODE_RELATIVE ) ;
2017-03-05 16:44:50 +01:00
else if ( p_morph_data - > mode = = " NORMALIZED " )
2017-01-12 12:34:00 +01:00
p_mesh - > set_blend_shape_mode ( Mesh : : BLEND_SHAPE_MODE_NORMALIZED ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int surface = 0 ;
for ( int p_i = 0 ; p_i < meshdata . primitives . size ( ) ; p_i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Primitives & p = meshdata . primitives [ p_i ] ;
2014-02-10 02:10:30 +01:00
/* VERTEX SOURCE */
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! p . sources . has ( " VERTEX " ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String vertex_src_id = p . sources [ " VERTEX " ] . source ;
2017-03-05 16:44:50 +01:00
int vertex_ofs = p . sources [ " VERTEX " ] . offset ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . vertices . has ( vertex_src_id ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . vertices [ vertex_src_id ] . sources . has ( " POSITION " ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String position_src_id = meshdata . vertices [ vertex_src_id ] . sources [ " POSITION " ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( position_src_id ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * vertex_src = & meshdata . sources [ position_src_id ] ;
2014-02-10 02:10:30 +01:00
/* NORMAL SOURCE */
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * normal_src = NULL ;
int normal_ofs = 0 ;
2014-02-10 02:10:30 +01:00
if ( p . sources . has ( " NORMAL " ) ) {
String normal_source_id = p . sources [ " NORMAL " ] . source ;
normal_ofs = p . sources [ " NORMAL " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( normal_source_id ) , ERR_INVALID_DATA ) ;
normal_src = & meshdata . sources [ normal_source_id ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * binormal_src = NULL ;
int binormal_ofs = 0 ;
2014-02-10 02:10:30 +01:00
if ( p . sources . has ( " TEXBINORMAL " ) ) {
String binormal_source_id = p . sources [ " TEXBINORMAL " ] . source ;
binormal_ofs = p . sources [ " TEXBINORMAL " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( binormal_source_id ) , ERR_INVALID_DATA ) ;
binormal_src = & meshdata . sources [ binormal_source_id ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * tangent_src = NULL ;
int tangent_ofs = 0 ;
2014-02-10 02:10:30 +01:00
if ( p . sources . has ( " TEXTANGENT " ) ) {
String tangent_source_id = p . sources [ " TEXTANGENT " ] . source ;
tangent_ofs = p . sources [ " TEXTANGENT " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( tangent_source_id ) , ERR_INVALID_DATA ) ;
tangent_src = & meshdata . sources [ tangent_source_id ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * uv_src = NULL ;
int uv_ofs = 0 ;
2014-02-10 02:10:30 +01:00
if ( p . sources . has ( " TEXCOORD0 " ) ) {
String uv_source_id = p . sources [ " TEXCOORD0 " ] . source ;
uv_ofs = p . sources [ " TEXCOORD0 " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( uv_source_id ) , ERR_INVALID_DATA ) ;
uv_src = & meshdata . sources [ uv_source_id ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * uv2_src = NULL ;
int uv2_ofs = 0 ;
2014-02-10 02:10:30 +01:00
if ( p . sources . has ( " TEXCOORD1 " ) ) {
String uv2_source_id = p . sources [ " TEXCOORD1 " ] . source ;
uv2_ofs = p . sources [ " TEXCOORD1 " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( uv2_source_id ) , ERR_INVALID_DATA ) ;
uv2_src = & meshdata . sources [ uv2_source_id ] ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const Collada : : MeshData : : Source * color_src = NULL ;
int color_ofs = 0 ;
2014-02-10 02:10:30 +01:00
2014-06-28 04:21:45 +02:00
if ( p . sources . has ( " COLOR " ) ) {
2014-02-10 02:10:30 +01:00
String color_source_id = p . sources [ " COLOR " ] . source ;
color_ofs = p . sources [ " COLOR " ] . offset ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! meshdata . sources . has ( color_source_id ) , ERR_INVALID_DATA ) ;
color_src = & meshdata . sources [ color_source_id ] ;
2014-02-10 02:10:30 +01:00
}
//find largest source..
2015-09-04 04:24:55 +02:00
/************************/
/* ADD WEIGHTS IF EXIST */
/************************/
2017-03-05 16:44:50 +01:00
Map < int , Vector < Collada : : Vertex : : Weight > > pre_weights ;
2015-09-04 04:24:55 +02:00
2017-03-05 16:44:50 +01:00
bool has_weights = false ;
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
if ( p_skin_controller ) {
2015-09-04 04:24:55 +02:00
2017-03-05 16:44:50 +01:00
const Collada : : SkinControllerData : : Source * weight_src = NULL ;
int weight_ofs = 0 ;
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
if ( p_skin_controller - > weights . sources . has ( " WEIGHT " ) ) {
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
String weight_id = p_skin_controller - > weights . sources [ " WEIGHT " ] . source ;
weight_ofs = p_skin_controller - > weights . sources [ " WEIGHT " ] . offset ;
if ( p_skin_controller - > sources . has ( weight_id ) ) {
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
weight_src = & p_skin_controller - > sources [ weight_id ] ;
2015-09-04 04:24:55 +02:00
}
}
2017-03-05 16:44:50 +01:00
int joint_ofs = 0 ;
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
if ( p_skin_controller - > weights . sources . has ( " JOINT " ) ) {
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
joint_ofs = p_skin_controller - > weights . sources [ " JOINT " ] . offset ;
2015-09-04 04:24:55 +02:00
}
//should be OK, given this was pre-checked.
2017-03-05 16:44:50 +01:00
int index_ofs = 0 ;
2017-08-12 18:52:50 +02:00
int wstride = p_skin_controller - > weights . sources . size ( ) ;
for ( int w_i = 0 ; w_i < p_skin_controller - > weights . sets . size ( ) ; w_i + + ) {
2015-09-04 04:24:55 +02:00
2017-08-12 18:52:50 +02:00
int amount = p_skin_controller - > weights . sets [ w_i ] ;
2015-09-04 04:24:55 +02:00
Vector < Collada : : Vertex : : Weight > weights ;
2017-03-05 16:44:50 +01:00
for ( int a_i = 0 ; a_i < amount ; a_i + + ) {
2015-09-04 04:24:55 +02:00
Collada : : Vertex : : Weight w ;
2017-03-05 16:44:50 +01:00
int read_from = index_ofs + a_i * wstride ;
2017-08-12 18:52:50 +02:00
ERR_FAIL_INDEX_V ( read_from + wstride - 1 , p_skin_controller - > weights . indices . size ( ) , ERR_INVALID_DATA ) ;
int weight_index = p_skin_controller - > weights . indices [ read_from + weight_ofs ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( weight_index , weight_src - > array . size ( ) , ERR_INVALID_DATA ) ;
2015-09-04 04:24:55 +02:00
w . weight = weight_src - > array [ weight_index ] ;
2017-08-12 18:52:50 +02:00
int bone_index = p_skin_controller - > weights . indices [ read_from + joint_ofs ] ;
2017-03-05 16:44:50 +01:00
if ( bone_index = = - 1 )
2015-09-04 04:24:55 +02:00
continue ; //ignore this weight (refers to bind shape)
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( bone_index , bone_remap . size ( ) , ERR_INVALID_DATA ) ;
2015-09-04 04:24:55 +02:00
2017-03-05 16:44:50 +01:00
w . bone_idx = bone_remap [ bone_index ] ;
2015-09-04 04:24:55 +02:00
weights . push_back ( w ) ;
}
/* FIX WEIGHTS */
weights . sort ( ) ;
2017-03-05 16:44:50 +01:00
if ( weights . size ( ) > 4 ) {
2015-09-04 04:24:55 +02:00
//cap to 4 and make weights add up 1
weights . resize ( 4 ) ;
}
2017-03-24 21:45:31 +01:00
//make sure weights always add up to 1
2017-03-05 16:44:50 +01:00
float total = 0 ;
for ( int i = 0 ; i < weights . size ( ) ; i + + )
total + = weights [ i ] . weight ;
2015-09-04 04:24:55 +02:00
if ( total )
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < weights . size ( ) ; i + + )
2018-07-25 03:11:03 +02:00
weights . write [ i ] . weight / = total ;
2015-09-04 04:24:55 +02:00
2017-03-05 16:44:50 +01:00
if ( weights . size ( ) = = 0 | | total = = 0 ) { //if nothing, add a weight to bone 0
2015-09-04 04:24:55 +02:00
//no weights assigned
Collada : : Vertex : : Weight w ;
2017-03-05 16:44:50 +01:00
w . bone_idx = 0 ;
w . weight = 1.0 ;
2015-09-04 04:24:55 +02:00
weights . clear ( ) ;
weights . push_back ( w ) ;
}
2017-03-05 16:44:50 +01:00
pre_weights [ w_i ] = weights ;
2015-09-04 04:24:55 +02:00
/*
for ( Set < int > : : Element * E = vertex_map [ w_i ] . front ( ) ; E ; E = E - > next ( ) ) {
int dst = E - > get ( ) ;
ERR_EXPLAIN ( " invalid vertex index in array " ) ;
ERR_FAIL_INDEX_V ( dst , vertex_array . size ( ) , ERR_INVALID_DATA ) ;
vertex_array [ dst ] . weights = weights ;
} */
2017-03-05 16:44:50 +01:00
index_ofs + = wstride * amount ;
2015-09-04 04:24:55 +02:00
}
//vertices need to be localized
2017-03-05 16:44:50 +01:00
has_weights = true ;
2015-09-04 04:24:55 +02:00
}
2014-02-10 02:10:30 +01:00
Set < Collada : : Vertex > vertex_set ; //vertex set will be the vertices
List < int > indices_list ; //indices will be the indices
2015-09-04 04:24:55 +02:00
//Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph)
2014-02-10 02:10:30 +01:00
/**************************/
/* CREATE PRIMITIVE ARRAY */
/**************************/
2017-03-24 21:45:31 +01:00
// The way collada uses indices is more optimal, and friendlier with 3D modelling software,
2014-02-10 02:10:30 +01:00
// because it can index everything, not only vertices (similar to how the WII works).
// This is, however, more incompatible with standard video cards, so arrays must be converted.
// Must convert to GL/DX format.
2017-03-05 16:44:50 +01:00
int _prim_ofs = 0 ;
int vertidx = 0 ;
for ( int p_i = 0 ; p_i < p . count ; p_i + + ) {
2014-02-10 02:10:30 +01:00
int amount ;
if ( p . polygons . size ( ) ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_i , p . polygons . size ( ) , ERR_INVALID_DATA ) ;
amount = p . polygons [ p_i ] ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
amount = 3 ; //triangles;
2014-02-10 02:10:30 +01:00
}
//COLLADA_PRINT("amount: "+itos(amount));
2017-03-05 16:44:50 +01:00
int prev2 [ 2 ] = { 0 , 0 } ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < amount ; j + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int src = _prim_ofs ;
2014-02-10 02:10:30 +01:00
//_prim_ofs+=p.sources.size()
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( src , p . indices . size ( ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
Collada : : Vertex vertex ;
2015-04-23 04:29:03 +02:00
if ( ! p_optimize )
2017-03-05 16:44:50 +01:00
vertex . uid = vertidx + + ;
2015-09-04 04:24:55 +02:00
2017-03-05 16:44:50 +01:00
int vertex_index = p . indices [ src + vertex_ofs ] ; //used for index field (later used by controllers)
int vertex_pos = ( vertex_src - > stride ? vertex_src - > stride : 3 ) * vertex_index ;
ERR_FAIL_INDEX_V ( vertex_pos , vertex_src - > array . size ( ) , ERR_INVALID_DATA ) ;
vertex . vertex = Vector3 ( vertex_src - > array [ vertex_pos + 0 ] , vertex_src - > array [ vertex_pos + 1 ] , vertex_src - > array [ vertex_pos + 2 ] ) ;
2014-02-10 02:10:30 +01:00
2015-09-04 04:24:55 +02:00
if ( pre_weights . has ( vertex_index ) ) {
2017-03-05 16:44:50 +01:00
vertex . weights = pre_weights [ vertex_index ] ;
2015-09-04 04:24:55 +02:00
}
2014-02-10 02:10:30 +01:00
if ( normal_src ) {
2017-03-05 16:44:50 +01:00
int normal_pos = ( normal_src - > stride ? normal_src - > stride : 3 ) * p . indices [ src + normal_ofs ] ;
ERR_FAIL_INDEX_V ( normal_pos , normal_src - > array . size ( ) , ERR_INVALID_DATA ) ;
vertex . normal = Vector3 ( normal_src - > array [ normal_pos + 0 ] , normal_src - > array [ normal_pos + 1 ] , normal_src - > array [ normal_pos + 2 ] ) ;
2014-02-10 02:10:30 +01:00
if ( tangent_src & & binormal_src ) {
2017-03-05 16:44:50 +01:00
int binormal_pos = ( binormal_src - > stride ? binormal_src - > stride : 3 ) * p . indices [ src + binormal_ofs ] ;
ERR_FAIL_INDEX_V ( binormal_pos , binormal_src - > array . size ( ) , ERR_INVALID_DATA ) ;
2018-11-17 02:11:35 +01:00
Vector3 binormal = Vector3 ( - binormal_src - > array [ binormal_pos + 0 ] , - binormal_src - > array [ binormal_pos + 1 ] , - binormal_src - > array [ binormal_pos + 2 ] ) ; // Due to Godots face order it seems we need to flip our binormal!
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int tangent_pos = ( tangent_src - > stride ? tangent_src - > stride : 3 ) * p . indices [ src + tangent_ofs ] ;
ERR_FAIL_INDEX_V ( tangent_pos , tangent_src - > array . size ( ) , ERR_INVALID_DATA ) ;
Vector3 tangent = Vector3 ( tangent_src - > array [ tangent_pos + 0 ] , tangent_src - > array [ tangent_pos + 1 ] , tangent_src - > array [ tangent_pos + 2 ] ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
vertex . tangent . normal = tangent ;
vertex . tangent . d = vertex . normal . cross ( tangent ) . dot ( binormal ) > 0 ? 1 : - 1 ;
2014-02-10 02:10:30 +01:00
}
}
if ( uv_src ) {
2017-03-05 16:44:50 +01:00
int uv_pos = ( uv_src - > stride ? uv_src - > stride : 2 ) * p . indices [ src + uv_ofs ] ;
ERR_FAIL_INDEX_V ( uv_pos , uv_src - > array . size ( ) , ERR_INVALID_DATA ) ;
vertex . uv = Vector3 ( uv_src - > array [ uv_pos + 0 ] , 1.0 - uv_src - > array [ uv_pos + 1 ] , 0 ) ;
2014-02-10 02:10:30 +01:00
}
if ( uv2_src ) {
2017-03-05 16:44:50 +01:00
int uv2_pos = ( uv2_src - > stride ? uv2_src - > stride : 2 ) * p . indices [ src + uv2_ofs ] ;
ERR_FAIL_INDEX_V ( uv2_pos , uv2_src - > array . size ( ) , ERR_INVALID_DATA ) ;
vertex . uv2 = Vector3 ( uv2_src - > array [ uv2_pos + 0 ] , 1.0 - uv2_src - > array [ uv2_pos + 1 ] , 0 ) ;
2014-02-10 02:10:30 +01:00
}
if ( color_src ) {
2017-03-05 16:44:50 +01:00
int color_pos = ( color_src - > stride ? color_src - > stride : 3 ) * p . indices [ src + color_ofs ] ; // colors are RGB in collada..
ERR_FAIL_INDEX_V ( color_pos , color_src - > array . size ( ) , ERR_INVALID_DATA ) ;
vertex . color = Color ( color_src - > array [ color_pos + 0 ] , color_src - > array [ color_pos + 1 ] , color_src - > array [ color_pos + 2 ] , ( color_src - > stride > 3 ) ? color_src - > array [ color_pos + 3 ] : 1.0 ) ;
2014-02-10 02:10:30 +01:00
}
# ifndef NO_UP_AXIS_SWAP
2017-03-05 16:44:50 +01:00
if ( collada . state . up_axis = = Vector3 : : AXIS_Z ) {
2014-02-10 02:10:30 +01:00
2017-07-03 15:44:45 +02:00
Vector3 bn = vertex . normal . cross ( vertex . tangent . normal ) * vertex . tangent . d ;
2017-03-05 16:44:50 +01:00
SWAP ( vertex . vertex . z , vertex . vertex . y ) ;
2014-02-10 02:10:30 +01:00
vertex . vertex . z = - vertex . vertex . z ;
2017-03-05 16:44:50 +01:00
SWAP ( vertex . normal . z , vertex . normal . y ) ;
2014-02-10 02:10:30 +01:00
vertex . normal . z = - vertex . normal . z ;
2017-03-05 16:44:50 +01:00
SWAP ( vertex . tangent . normal . z , vertex . tangent . normal . y ) ;
2014-10-14 06:01:25 +02:00
vertex . tangent . normal . z = - vertex . tangent . normal . z ;
2017-07-03 15:44:45 +02:00
SWAP ( bn . z , bn . y ) ;
bn . z = - bn . z ;
vertex . tangent . d = vertex . normal . cross ( vertex . tangent . normal ) . dot ( bn ) > 0 ? 1 : - 1 ;
2014-02-10 02:10:30 +01:00
}
# endif
vertex . fix_unit_scale ( collada ) ;
2017-03-05 16:44:50 +01:00
int index = 0 ;
2014-02-10 02:10:30 +01:00
//COLLADA_PRINT("vertex: "+vertex.vertex);
if ( vertex_set . has ( vertex ) ) {
2017-03-05 16:44:50 +01:00
index = vertex_set . find ( vertex ) - > get ( ) . idx ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
index = vertex_set . size ( ) ;
vertex . idx = index ;
2014-02-10 02:10:30 +01:00
vertex_set . insert ( vertex ) ;
}
2017-03-05 16:44:50 +01:00
/* if (!vertex_map.has(vertex_index))
2014-02-10 02:10:30 +01:00
vertex_map [ vertex_index ] = Set < int > ( ) ;
2015-09-04 04:24:55 +02:00
vertex_map [ vertex_index ] . insert ( index ) ; //should be outside..*/
2014-02-10 02:10:30 +01:00
//build triangles if needed
2017-03-05 16:44:50 +01:00
if ( j = = 0 )
prev2 [ 0 ] = index ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( j > = 2 ) {
2014-02-10 02:10:30 +01:00
//insert indices in reverse order (collada uses CCW as frontface)
if ( local_xform_mirror ) {
indices_list . push_back ( prev2 [ 0 ] ) ;
indices_list . push_back ( prev2 [ 1 ] ) ;
indices_list . push_back ( index ) ;
} else {
indices_list . push_back ( prev2 [ 0 ] ) ;
indices_list . push_back ( index ) ;
indices_list . push_back ( prev2 [ 1 ] ) ;
}
}
2017-03-05 16:44:50 +01:00
prev2 [ 1 ] = index ;
_prim_ofs + = p . vertex_size ;
2014-02-10 02:10:30 +01:00
}
}
Vector < Collada : : Vertex > vertex_array ; //there we go, vertex array
vertex_array . resize ( vertex_set . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( Set < Collada : : Vertex > : : Element * F = vertex_set . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
vertex_array . write [ F - > get ( ) . idx ] = F - > get ( ) ;
2014-02-10 02:10:30 +01:00
}
2015-09-04 04:24:55 +02:00
if ( has_weights ) {
2014-02-10 02:10:30 +01:00
2015-09-04 04:24:55 +02:00
//if skeleton, localize
2014-02-10 02:10:30 +01:00
Transform local_xform = p_local_xform ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < vertex_array . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
vertex_array . write [ i ] . vertex = local_xform . xform ( vertex_array [ i ] . vertex ) ;
vertex_array . write [ i ] . normal = local_xform . basis . xform ( vertex_array [ i ] . normal ) . normalized ( ) ;
vertex_array . write [ i ] . tangent . normal = local_xform . basis . xform ( vertex_array [ i ] . tangent . normal ) . normalized ( ) ;
2014-02-10 02:10:30 +01:00
if ( local_xform_mirror ) {
//i shouldn't do this? wtf?
//vertex_array[i].normal*=-1.0;
//vertex_array[i].tangent.normal*=-1.0;
}
}
}
/*****************/
/* MAKE SURFACES */
/*****************/
{
2017-04-07 04:36:37 +02:00
Ref < SpatialMaterial > material ;
2014-02-10 02:10:30 +01:00
{
if ( p_material_map . has ( p . material ) ) {
2017-03-05 16:44:50 +01:00
String target = p_material_map [ p . material ] . target ;
2014-02-10 02:10:30 +01:00
if ( ! material_cache . has ( target ) ) {
Error err = _create_material ( target ) ;
if ( ! err )
2017-03-05 16:44:50 +01:00
material = material_cache [ target ] ;
2014-02-10 02:10:30 +01:00
} else
2017-03-05 16:44:50 +01:00
material = material_cache [ target ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( p . material ! = " " ) {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Unreferenced material in geometry instance: " + p . material ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-08-29 13:47:29 +02:00
Ref < SurfaceTool > surftool ;
surftool . instance ( ) ;
surftool - > begin ( Mesh : : PRIMITIVE_TRIANGLES ) ;
2014-02-10 02:10:30 +01:00
2017-08-29 13:47:29 +02:00
for ( int k = 0 ; k < vertex_array . size ( ) ; k + + ) {
if ( normal_src ) {
surftool - > add_normal ( vertex_array [ k ] . normal ) ;
if ( binormal_src & & tangent_src ) {
surftool - > add_tangent ( vertex_array [ k ] . tangent ) ;
}
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
if ( uv_src ) {
surftool - > add_uv ( Vector2 ( vertex_array [ k ] . uv . x , vertex_array [ k ] . uv . y ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
if ( uv2_src ) {
surftool - > add_uv2 ( Vector2 ( vertex_array [ k ] . uv2 . x , vertex_array [ k ] . uv2 . y ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
if ( color_src ) {
surftool - > add_color ( vertex_array [ k ] . color ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
if ( has_weights ) {
Vector < float > weights ;
Vector < int > bones ;
weights . resize ( VS : : ARRAY_WEIGHTS_SIZE ) ;
bones . resize ( VS : : ARRAY_WEIGHTS_SIZE ) ;
//float sum=0.0;
for ( int l = 0 ; l < VS : : ARRAY_WEIGHTS_SIZE ; l + + ) {
if ( l < vertex_array [ k ] . weights . size ( ) ) {
2018-07-25 03:11:03 +02:00
weights . write [ l ] = vertex_array [ k ] . weights [ l ] . weight ;
bones . write [ l ] = vertex_array [ k ] . weights [ l ] . bone_idx ;
2017-08-29 13:47:29 +02:00
//sum += vertex_array[k].weights[l].weight;
} else {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
weights . write [ l ] = 0 ;
bones . write [ l ] = 0 ;
2017-08-29 13:47:29 +02:00
}
}
2014-02-10 02:10:30 +01:00
2017-08-29 13:47:29 +02:00
surftool - > add_bones ( bones ) ;
surftool - > add_weights ( weights ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
surftool - > add_vertex ( vertex_array [ k ] . vertex ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
for ( List < int > : : Element * E = indices_list . front ( ) ; E ; E = E - > next ( ) ) {
surftool - > add_index ( E - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-29 13:47:29 +02:00
if ( ! normal_src ) {
//should always be normals
surftool - > generate_normals ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-08-29 13:47:29 +02:00
if ( ( ! binormal_src | | ! tangent_src ) & & normal_src & & uv_src & & force_make_tangents ) {
2014-02-10 02:10:30 +01:00
2017-08-29 13:47:29 +02:00
surftool - > generate_tangents ( ) ;
2014-02-10 02:10:30 +01:00
}
////////////////////////////
// FINALLY CREATE SUFRACE //
////////////////////////////
2017-08-29 13:47:29 +02:00
Array d = surftool - > commit_to_arrays ( ) ;
2014-02-10 02:10:30 +01:00
d . resize ( VS : : ARRAY_MAX ) ;
Array mr ;
2017-08-27 21:07:15 +02:00
////////////////////////////
// THEN THE MORPH TARGETS //
////////////////////////////
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int mi = 0 ; mi < p_morph_meshes . size ( ) ; mi + + ) {
2015-04-23 04:29:03 +02:00
Array a = p_morph_meshes [ mi ] - > surface_get_arrays ( surface ) ;
2016-11-25 00:46:55 +01:00
//add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not)
2017-08-29 13:47:29 +02:00
if ( has_weights ) {
a [ Mesh : : ARRAY_WEIGHTS ] = d [ Mesh : : ARRAY_WEIGHTS ] ;
a [ Mesh : : ARRAY_BONES ] = d [ Mesh : : ARRAY_BONES ] ;
}
2016-11-25 00:46:55 +01:00
2017-03-05 16:44:50 +01:00
a [ Mesh : : ARRAY_INDEX ] = Variant ( ) ;
2015-04-23 04:29:03 +02:00
//a.resize(Mesh::ARRAY_MAX); //no need for index
mr . push_back ( a ) ;
}
2014-02-10 02:10:30 +01:00
2017-11-01 01:01:24 +01:00
p_mesh - > add_surface_from_arrays ( Mesh : : PRIMITIVE_TRIANGLES , d , mr , p_use_compression ? Mesh : : ARRAY_COMPRESS_DEFAULT : 0 ) ;
2014-02-10 02:10:30 +01:00
if ( material . is_valid ( ) ) {
2017-02-05 00:31:15 +01:00
if ( p_use_mesh_material ) {
p_mesh - > surface_set_material ( surface , material ) ;
}
2014-02-10 02:10:30 +01:00
p_mesh - > surface_set_name ( surface , material - > get_name ( ) ) ;
}
}
/*****************/
/* FIND MATERIAL */
/*****************/
surface + + ;
}
return OK ;
}
2017-11-01 01:01:24 +01:00
Error ColladaImport : : _create_resources ( Collada : : Node * p_node , bool p_use_compression ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_node - > type = = Collada : : Node : : TYPE_GEOMETRY & & node_map . has ( p_node - > id ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Spatial * node = node_map [ p_node - > id ] . node ;
Collada : : NodeGeometry * ng = static_cast < Collada : : NodeGeometry * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < Path > ( node ) ) {
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
Path * path = Object : : cast_to < Path > ( node ) ;
2014-02-10 02:10:30 +01:00
String curve = ng - > source ;
if ( curve_cache . has ( ng - > source ) ) {
path - > set_curve ( curve_cache [ ng - > source ] ) ;
} else {
2017-03-05 16:44:50 +01:00
Ref < Curve3D > c = memnew ( Curve3D ) ;
2014-02-10 02:10:30 +01:00
const Collada : : CurveData & cd = collada . state . curve_data_map [ ng - > source ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! cd . control_vertices . has ( " POSITION " ) , ERR_INVALID_DATA ) ;
ERR_FAIL_COND_V ( ! cd . control_vertices . has ( " IN_TANGENT " ) , ERR_INVALID_DATA ) ;
ERR_FAIL_COND_V ( ! cd . control_vertices . has ( " OUT_TANGENT " ) , ERR_INVALID_DATA ) ;
ERR_FAIL_COND_V ( ! cd . control_vertices . has ( " INTERPOLATION " ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! cd . sources . has ( cd . control_vertices [ " POSITION " ] ) , ERR_INVALID_DATA ) ;
const Collada : : CurveData : : Source & vertices = cd . sources [ cd . control_vertices [ " POSITION " ] ] ;
ERR_FAIL_COND_V ( vertices . stride ! = 3 , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! cd . sources . has ( cd . control_vertices [ " IN_TANGENT " ] ) , ERR_INVALID_DATA ) ;
const Collada : : CurveData : : Source & in_tangents = cd . sources [ cd . control_vertices [ " IN_TANGENT " ] ] ;
ERR_FAIL_COND_V ( in_tangents . stride ! = 3 , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! cd . sources . has ( cd . control_vertices [ " OUT_TANGENT " ] ) , ERR_INVALID_DATA ) ;
const Collada : : CurveData : : Source & out_tangents = cd . sources [ cd . control_vertices [ " OUT_TANGENT " ] ] ;
ERR_FAIL_COND_V ( out_tangents . stride ! = 3 , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! cd . sources . has ( cd . control_vertices [ " INTERPOLATION " ] ) , ERR_INVALID_DATA ) ;
const Collada : : CurveData : : Source & interps = cd . sources [ cd . control_vertices [ " INTERPOLATION " ] ] ;
ERR_FAIL_COND_V ( interps . stride ! = 1 , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const Collada : : CurveData : : Source * tilts = NULL ;
2014-02-10 02:10:30 +01:00
if ( cd . control_vertices . has ( " TILT " ) & & cd . sources . has ( cd . control_vertices [ " TILT " ] ) )
2017-03-05 16:44:50 +01:00
tilts = & cd . sources [ cd . control_vertices [ " TILT " ] ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int pc = vertices . array . size ( ) / 3 ;
for ( int i = 0 ; i < pc ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Vector3 pos ( vertices . array [ i * 3 + 0 ] , vertices . array [ i * 3 + 1 ] , vertices . array [ i * 3 + 2 ] ) ;
Vector3 in ( in_tangents . array [ i * 3 + 0 ] , in_tangents . array [ i * 3 + 1 ] , in_tangents . array [ i * 3 + 2 ] ) ;
Vector3 out ( out_tangents . array [ i * 3 + 0 ] , out_tangents . array [ i * 3 + 1 ] , out_tangents . array [ i * 3 + 2 ] ) ;
2014-02-10 02:10:30 +01:00
# ifndef NO_UP_AXIS_SWAP
2017-03-05 16:44:50 +01:00
if ( collada . state . up_axis = = Vector3 : : AXIS_Z ) {
SWAP ( pos . y , pos . z ) ;
pos . z = - pos . z ;
SWAP ( in . y , in . z ) ;
in . z = - in . z ;
SWAP ( out . y , out . z ) ;
out . z = - out . z ;
2014-02-10 02:10:30 +01:00
}
# endif
2017-03-05 16:44:50 +01:00
pos * = collada . state . unit_scale ;
in * = collada . state . unit_scale ;
out * = collada . state . unit_scale ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
c - > add_point ( pos , in - pos , out - pos ) ;
2014-02-10 02:10:30 +01:00
if ( tilts )
2017-03-05 16:44:50 +01:00
c - > set_point_tilt ( i , tilts - > array [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
curve_cache [ ng - > source ] = c ;
2014-02-10 02:10:30 +01:00
path - > set_curve ( c ) ;
}
}
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < MeshInstance > ( node ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Collada : : NodeGeometry * ng = static_cast < Collada : : NodeGeometry * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
MeshInstance * mi = Object : : cast_to < MeshInstance > ( node ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! mi , ERR_BUG ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Collada : : SkinControllerData * skin = NULL ;
Collada : : MorphControllerData * morph = NULL ;
2014-02-10 02:10:30 +01:00
String meshid ;
Transform apply_xform ;
Vector < int > bone_remap ;
2017-06-07 23:18:55 +02:00
Vector < Ref < ArrayMesh > > morphs ;
2014-02-10 02:10:30 +01:00
if ( ng - > controller ) {
2015-04-23 04:29:03 +02:00
String ngsource = ng - > source ;
if ( collada . state . skin_controller_data_map . has ( ngsource ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! collada . state . skin_controller_data_map . has ( ngsource ) , ERR_INVALID_DATA ) ;
skin = & collada . state . skin_controller_data_map [ ngsource ] ;
2014-02-10 02:10:30 +01:00
Vector < String > skeletons = ng - > skeletons ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( skeletons . empty ( ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String skname = skeletons [ 0 ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! node_map . has ( skname ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
NodeMap nmsk = node_map [ skname ] ;
2017-08-24 22:58:51 +02:00
Skeleton * sk = Object : : cast_to < Skeleton > ( nmsk . node ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! sk , ERR_INVALID_DATA ) ;
ERR_FAIL_COND_V ( ! skeleton_bone_map . has ( sk ) , ERR_INVALID_DATA ) ;
Map < String , int > & bone_remap_map = skeleton_bone_map [ sk ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
meshid = skin - > base ;
2014-02-10 02:10:30 +01:00
if ( collada . state . morph_controller_data_map . has ( meshid ) ) {
//it's a morph!!
2015-04-24 03:42:52 +02:00
morph = & collada . state . morph_controller_data_map [ meshid ] ;
2017-03-05 16:44:50 +01:00
ngsource = meshid ;
meshid = morph - > mesh ;
2015-04-23 04:29:03 +02:00
} else {
2017-03-05 16:44:50 +01:00
ngsource = " " ;
2014-02-10 02:10:30 +01:00
}
2014-12-02 18:02:41 +01:00
if ( apply_mesh_xform_to_vertices ) {
2017-03-05 16:44:50 +01:00
apply_xform = collada . fix_transform ( p_node - > default_transform ) ;
2014-12-02 18:02:41 +01:00
node - > set_transform ( Transform ( ) ) ;
} else {
2017-03-05 16:44:50 +01:00
apply_xform = Transform ( ) ;
2014-12-02 18:02:41 +01:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! skin - > weights . sources . has ( " JOINT " ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
String joint_id = skin - > weights . sources [ " JOINT " ] . source ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! skin - > sources . has ( joint_id ) , ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
2017-08-21 21:15:36 +02:00
Collada : : SkinControllerData : : Source * joint_src = & skin - > sources [ joint_id ] ;
2014-02-10 02:10:30 +01:00
bone_remap . resize ( joint_src - > sarray . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < bone_remap . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
String str = joint_src - > sarray [ i ] ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! bone_remap_map . has ( str ) , ERR_INVALID_DATA ) ;
2018-07-25 03:11:03 +02:00
bone_remap . write [ i ] = bone_remap_map [ str ] ;
2014-02-10 02:10:30 +01:00
}
2015-04-23 04:29:03 +02:00
}
if ( collada . state . morph_controller_data_map . has ( ngsource ) ) {
2017-10-21 19:31:23 +02:00
2014-02-10 02:10:30 +01:00
//it's a morph!!
2015-04-23 04:29:03 +02:00
morph = & collada . state . morph_controller_data_map [ ngsource ] ;
2017-03-05 16:44:50 +01:00
meshid = morph - > mesh ;
2015-04-23 04:29:03 +02:00
Vector < String > targets ;
morph - > targets . has ( " MORPH_TARGET " ) ;
String target = morph - > targets [ " MORPH_TARGET " ] ;
2017-03-05 16:44:50 +01:00
bool valid = false ;
2015-04-23 04:29:03 +02:00
if ( morph - > sources . has ( target ) ) {
2017-03-05 16:44:50 +01:00
valid = true ;
2015-04-23 04:29:03 +02:00
Vector < String > names = morph - > sources [ target ] . sarray ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < names . size ( ) ; i + + ) {
2015-04-23 04:29:03 +02:00
2017-03-05 16:44:50 +01:00
String meshid = names [ i ] ;
2015-04-23 04:29:03 +02:00
if ( collada . state . mesh_data_map . has ( meshid ) ) {
2017-06-07 23:18:55 +02:00
Ref < ArrayMesh > mesh = Ref < ArrayMesh > ( memnew ( ArrayMesh ) ) ;
2015-04-23 04:29:03 +02:00
const Collada : : MeshData & meshdata = collada . state . mesh_data_map [ meshid ] ;
2017-11-01 01:01:24 +01:00
Error err = _create_mesh_surfaces ( false , mesh , ng - > material_map , meshdata , apply_xform , bone_remap , skin , NULL , Vector < Ref < ArrayMesh > > ( ) , false ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err , err ) ;
2015-04-23 04:29:03 +02:00
morphs . push_back ( mesh ) ;
} else {
2017-03-05 16:44:50 +01:00
valid = false ;
2015-04-23 04:29:03 +02:00
}
}
}
if ( ! valid )
morphs . clear ( ) ;
2017-03-05 16:44:50 +01:00
ngsource = " " ;
2015-04-23 04:29:03 +02:00
}
2017-03-05 16:44:50 +01:00
if ( ngsource ! = " " ) {
ERR_EXPLAIN ( " Controller Instance Source ' " + ngsource + " ' is neither skin or morph! " ) ;
ERR_FAIL_V ( ERR_INVALID_DATA ) ;
2014-02-10 02:10:30 +01:00
}
} else {
2017-03-05 16:44:50 +01:00
meshid = ng - > source ;
2014-02-10 02:10:30 +01:00
}
2017-06-07 23:18:55 +02:00
Ref < ArrayMesh > mesh ;
2014-02-10 02:10:30 +01:00
if ( mesh_cache . has ( meshid ) ) {
2017-03-05 16:44:50 +01:00
mesh = mesh_cache [ meshid ] ;
2014-02-10 02:10:30 +01:00
} else {
if ( collada . state . mesh_data_map . has ( meshid ) ) {
//bleh, must ignore invalid
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! collada . state . mesh_data_map . has ( meshid ) , ERR_INVALID_DATA ) ;
2017-06-07 23:18:55 +02:00
mesh = Ref < ArrayMesh > ( memnew ( ArrayMesh ) ) ;
2014-02-10 02:10:30 +01:00
const Collada : : MeshData & meshdata = collada . state . mesh_data_map [ meshid ] ;
2017-03-05 16:44:50 +01:00
mesh - > set_name ( meshdata . name ) ;
2017-11-01 01:01:24 +01:00
Error err = _create_mesh_surfaces ( morphs . size ( ) = = 0 , mesh , ng - > material_map , meshdata , apply_xform , bone_remap , skin , morph , morphs , p_use_compression , use_mesh_builtin_materials ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err , err ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
mesh_cache [ meshid ] = mesh ;
2014-02-10 02:10:30 +01:00
} else {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Will not import geometry: " + meshid ) ;
2014-02-10 02:10:30 +01:00
}
}
if ( ! mesh . is_null ( ) ) {
2017-02-05 00:31:15 +01:00
2014-02-10 02:10:30 +01:00
mi - > set_mesh ( mesh ) ;
2017-02-05 00:31:15 +01:00
if ( ! use_mesh_builtin_materials ) {
const Collada : : MeshData & meshdata = collada . state . mesh_data_map [ meshid ] ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < meshdata . primitives . size ( ) ; i + + ) {
2017-02-05 00:31:15 +01:00
2017-03-05 16:44:50 +01:00
String matname = meshdata . primitives [ i ] . material ;
2017-02-05 00:31:15 +01:00
if ( ng - > material_map . has ( matname ) ) {
2017-03-05 16:44:50 +01:00
String target = ng - > material_map [ matname ] . target ;
2017-02-05 00:31:15 +01:00
Ref < Material > material ;
if ( ! material_cache . has ( target ) ) {
Error err = _create_material ( target ) ;
if ( ! err )
2017-03-05 16:44:50 +01:00
material = material_cache [ target ] ;
2017-02-05 00:31:15 +01:00
} else
2017-03-05 16:44:50 +01:00
material = material_cache [ target ] ;
2017-02-05 00:31:15 +01:00
2017-03-05 16:44:50 +01:00
mi - > set_surface_material ( i , material ) ;
} else if ( matname ! = " " ) {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Unreferenced material in geometry instance: " + matname ) ;
2017-02-05 00:31:15 +01:00
}
}
}
2014-02-10 02:10:30 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_node - > children . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-11-01 01:01:24 +01:00
Error err = _create_resources ( p_node - > children [ i ] , p_use_compression ) ;
2014-02-10 02:10:30 +01:00
if ( err )
return err ;
}
return OK ;
}
2017-11-01 01:01:24 +01:00
Error ColladaImport : : load ( const String & p_path , int p_flags , bool p_force_make_tangents , bool p_use_compression ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error err = collada . load ( p_path , p_flags ) ;
ERR_FAIL_COND_V ( err , err ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
force_make_tangents = p_force_make_tangents ;
ERR_FAIL_COND_V ( ! collada . state . visual_scene_map . has ( collada . state . root_visual_scene ) , ERR_INVALID_DATA ) ;
Collada : : VisualScene & vs = collada . state . visual_scene_map [ collada . state . root_visual_scene ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
scene = memnew ( Spatial ) ; // root
2014-02-10 02:10:30 +01:00
//determine what's going on with the lights
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
_pre_process_lights ( vs . root_nodes [ i ] ) ;
}
//import scene
2014-12-02 18:02:41 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
2014-12-02 18:02:41 +01:00
Error err = _create_scene_skeletons ( vs . root_nodes [ i ] ) ;
2017-03-05 16:44:50 +01:00
if ( err ! = OK ) {
2014-12-02 18:02:41 +01:00
memdelete ( scene ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err , err ) ;
2014-12-02 18:02:41 +01:00
}
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < vs . root_nodes . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error err = _create_scene ( vs . root_nodes [ i ] , scene ) ;
if ( err ! = OK ) {
2014-02-10 02:10:30 +01:00
memdelete ( scene ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err , err ) ;
2014-02-10 02:10:30 +01:00
}
2017-11-01 01:01:24 +01:00
Error err2 = _create_resources ( vs . root_nodes [ i ] , p_use_compression ) ;
2017-03-05 16:44:50 +01:00
if ( err2 ! = OK ) {
2014-02-10 02:10:30 +01:00
memdelete ( scene ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err2 , err2 ) ;
2014-02-10 02:10:30 +01:00
}
}
//optatively, set unit scale in the root
scene - > set_transform ( collada . get_root_transform ( ) ) ;
return OK ;
}
void ColladaImport : : _fix_param_animation_tracks ( ) {
2017-03-05 16:44:50 +01:00
for ( Map < String , Collada : : Node * > : : Element * E = collada . state . scene_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
Collada : : Node * n = E - > get ( ) ;
2017-03-05 16:44:50 +01:00
switch ( n - > type ) {
2014-02-10 02:10:30 +01:00
case Collada : : Node : : TYPE_NODE : {
// ? do nothing
} break ;
case Collada : : Node : : TYPE_JOINT : {
} break ;
case Collada : : Node : : TYPE_SKELETON : {
} break ;
case Collada : : Node : : TYPE_LIGHT : {
} break ;
case Collada : : Node : : TYPE_CAMERA : {
} break ;
case Collada : : Node : : TYPE_GEOMETRY : {
2017-03-05 16:44:50 +01:00
Collada : : NodeGeometry * ng = static_cast < Collada : : NodeGeometry * > ( n ) ;
2014-02-10 02:10:30 +01:00
// test source(s)
String source = ng - > source ;
2017-03-05 16:44:50 +01:00
while ( source ! = " " ) {
2014-02-10 02:10:30 +01:00
if ( collada . state . skin_controller_data_map . has ( source ) ) {
2017-03-05 16:44:50 +01:00
const Collada : : SkinControllerData & skin = collada . state . skin_controller_data_map [ source ] ;
2014-02-10 02:10:30 +01:00
//nothing to animate here i think
2017-03-05 16:44:50 +01:00
source = skin . base ;
2014-02-10 02:10:30 +01:00
} else if ( collada . state . morph_controller_data_map . has ( source ) ) {
2017-03-05 16:44:50 +01:00
const Collada : : MorphControllerData & morph = collada . state . morph_controller_data_map [ source ] ;
2014-10-10 00:44:27 +02:00
2014-02-10 02:10:30 +01:00
if ( morph . targets . has ( " MORPH_WEIGHT " ) & & morph . targets . has ( " MORPH_TARGET " ) ) {
2014-10-15 00:44:41 +02:00
2014-02-10 02:10:30 +01:00
String weights = morph . targets [ " MORPH_WEIGHT " ] ;
String targets = morph . targets [ " MORPH_TARGET " ] ;
2014-10-10 00:44:27 +02:00
//fails here
2014-02-10 02:10:30 +01:00
if ( morph . sources . has ( targets ) & & morph . sources . has ( weights ) ) {
2017-03-05 16:44:50 +01:00
const Collada : : MorphControllerData : : Source & weight_src = morph . sources [ weights ] ;
const Collada : : MorphControllerData : : Source & target_src = morph . sources [ targets ] ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( weight_src . array . size ( ) ! = target_src . sarray . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < weight_src . array . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String track_name = weights + " ( " + itos ( i ) + " ) " ;
2014-02-10 02:10:30 +01:00
String mesh_name = target_src . sarray [ i ] ;
if ( collada . state . mesh_name_map . has ( mesh_name ) & & collada . state . referenced_tracks . has ( track_name ) ) {
2014-10-10 00:44:27 +02:00
2017-03-05 16:44:50 +01:00
const Vector < int > & rt = collada . state . referenced_tracks [ track_name ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int rti = 0 ; rti < rt . size ( ) ; rti + + ) {
2018-07-25 03:11:03 +02:00
Collada : : AnimationTrack * at = & collada . state . animation_tracks . write [ rt [ rti ] ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
at - > target = E - > key ( ) ;
at - > param = " morph/ " + collada . state . mesh_name_map [ mesh_name ] ;
at - > property = true ;
2014-02-10 02:10:30 +01:00
//at->param
}
}
}
}
}
2017-03-05 16:44:50 +01:00
source = morph . mesh ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
source = " " ; // for now nothing else supported
2014-02-10 02:10:30 +01:00
}
}
} break ;
}
}
}
2016-11-03 09:41:28 +01:00
void ColladaImport : : create_animations ( bool p_make_tracks_in_all_bones , bool p_import_value_tracks ) {
2014-02-10 02:10:30 +01:00
_fix_param_animation_tracks ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < collada . state . animation_clips . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < collada . state . animation_clips [ i ] . tracks . size ( ) ; j + + )
2014-02-10 02:10:30 +01:00
tracks_in_clips . insert ( collada . state . animation_clips [ i ] . tracks [ j ] ) ;
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < collada . state . animation_tracks . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
const Collada : : AnimationTrack & at = collada . state . animation_tracks [ i ] ;
2015-12-21 13:05:49 +01:00
String node ;
2014-02-10 02:10:30 +01:00
if ( ! node_map . has ( at . target ) ) {
2015-12-21 13:05:49 +01:00
if ( node_name_map . has ( at . target ) ) {
2017-03-05 16:44:50 +01:00
node = node_name_map [ at . target ] ;
2015-12-21 13:05:49 +01:00
} else {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Couldn't find node: " + at . target ) ;
2015-12-21 13:05:49 +01:00
continue ;
}
} else {
2017-03-05 16:44:50 +01:00
node = at . target ;
2014-02-10 02:10:30 +01:00
}
if ( at . property ) {
valid_animated_properties . push_back ( i ) ;
} else {
2015-12-21 13:05:49 +01:00
node_map [ node ] . anim_tracks . push_back ( i ) ;
valid_animated_nodes . insert ( node ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
create_animation ( - 1 , p_make_tracks_in_all_bones , p_import_value_tracks ) ;
for ( int i = 0 ; i < collada . state . animation_clips . size ( ) ; i + + )
2016-11-03 09:41:28 +01:00
create_animation ( i , p_make_tracks_in_all_bones , p_import_value_tracks ) ;
2014-02-10 02:10:30 +01:00
}
2016-11-03 09:41:28 +01:00
void ColladaImport : : create_animation ( int p_clip , bool p_make_tracks_in_all_bones , bool p_import_value_tracks ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Ref < Animation > animation = Ref < Animation > ( memnew ( Animation ) ) ;
2015-12-21 13:05:49 +01:00
2017-03-05 16:44:50 +01:00
if ( p_clip = = - 1 ) {
2014-02-10 02:10:30 +01:00
animation - > set_name ( " default " ) ;
} else {
animation - > set_name ( collada . state . animation_clips [ p_clip ] . name ) ;
}
2017-03-05 16:44:50 +01:00
for ( Map < String , NodeMap > : : Element * E = node_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( E - > get ( ) . bone < 0 )
2014-02-10 02:10:30 +01:00
continue ;
2017-03-05 16:44:50 +01:00
bones_with_animation [ E - > key ( ) ] = false ;
2014-02-10 02:10:30 +01:00
}
//store and validate tracks
2017-03-05 16:44:50 +01:00
if ( p_clip = = - 1 ) {
2014-02-10 02:10:30 +01:00
//main anim
}
Set < int > track_filter ;
2017-03-05 16:44:50 +01:00
if ( p_clip = = - 1 ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < collada . state . animation_clips . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
int tc = collada . state . animation_clips [ i ] . tracks . size ( ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < tc ; j + + ) {
2014-02-10 02:10:30 +01:00
String n = collada . state . animation_clips [ i ] . tracks [ j ] ;
if ( collada . state . by_id_tracks . has ( n ) ) {
2017-03-05 16:44:50 +01:00
const Vector < int > & ti = collada . state . by_id_tracks [ n ] ;
for ( int k = 0 ; k < ti . size ( ) ; k + + ) {
2014-02-10 02:10:30 +01:00
track_filter . insert ( ti [ k ] ) ;
}
}
}
}
} else {
int tc = collada . state . animation_clips [ p_clip ] . tracks . size ( ) ;
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < tc ; j + + ) {
2014-02-10 02:10:30 +01:00
String n = collada . state . animation_clips [ p_clip ] . tracks [ j ] ;
if ( collada . state . by_id_tracks . has ( n ) ) {
2017-03-05 16:44:50 +01:00
const Vector < int > & ti = collada . state . by_id_tracks [ n ] ;
for ( int k = 0 ; k < ti . size ( ) ; k + + ) {
2014-02-10 02:10:30 +01:00
track_filter . insert ( ti [ k ] ) ;
}
}
}
}
//animation->set_loop(true);
//create animation tracks
Vector < float > base_snapshots ;
2017-03-05 16:44:50 +01:00
float f = 0 ;
float snapshot_interval = 1.0 / bake_fps ; //should be customizable somewhere...
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
float anim_length = collada . state . animation_length ;
if ( p_clip > = 0 & & collada . state . animation_clips [ p_clip ] . end )
anim_length = collada . state . animation_clips [ p_clip ] . end ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( f < anim_length ) {
2014-02-10 02:10:30 +01:00
base_snapshots . push_back ( f ) ;
2015-12-21 13:05:49 +01:00
2017-03-05 16:44:50 +01:00
f + = snapshot_interval ;
2014-11-12 15:23:23 +01:00
2017-03-05 16:44:50 +01:00
if ( f > = anim_length ) {
2014-11-12 15:23:23 +01:00
base_snapshots . push_back ( anim_length ) ;
}
2014-02-10 02:10:30 +01:00
}
2014-11-12 15:23:23 +01:00
2014-02-10 02:10:30 +01:00
animation - > set_length ( anim_length ) ;
2017-03-05 16:44:50 +01:00
bool tracks_found = false ;
2015-12-21 13:05:49 +01:00
2017-03-05 16:44:50 +01:00
for ( Set < String > : : Element * E = valid_animated_nodes . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
// take snapshots
2015-12-21 13:05:49 +01:00
if ( ! collada . state . scene_map . has ( E - > get ( ) ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2015-12-21 13:05:49 +01:00
}
2014-02-10 02:10:30 +01:00
NodeMap & nm = node_map [ E - > get ( ) ] ;
String path = scene - > get_path_to ( nm . node ) ;
2017-03-05 16:44:50 +01:00
if ( nm . bone > = 0 ) {
Skeleton * sk = static_cast < Skeleton * > ( nm . node ) ;
2014-02-10 02:10:30 +01:00
String name = sk - > get_bone_name ( nm . bone ) ;
2017-03-05 16:44:50 +01:00
path = path + " : " + name ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
bool found_anim = false ;
2014-02-10 02:10:30 +01:00
Collada : : Node * cn = collada . state . scene_map [ E - > get ( ) ] ;
if ( cn - > ignore_anim ) {
2015-12-21 13:05:49 +01:00
2014-02-10 02:10:30 +01:00
continue ;
}
animation - > add_track ( Animation : : TYPE_TRANSFORM ) ;
2017-03-05 16:44:50 +01:00
int track = animation - > get_track_count ( ) - 1 ;
animation - > track_set_path ( track , path ) ;
animation - > track_set_imported ( track , true ) ; //helps merging later
2014-02-10 02:10:30 +01:00
Vector < float > snapshots = base_snapshots ;
2017-03-05 16:44:50 +01:00
if ( nm . anim_tracks . size ( ) = = 1 ) {
2014-02-10 02:10:30 +01:00
//use snapshot keys from anim track instead, because this was most likely exported baked
2018-07-25 03:11:03 +02:00
const Collada : : AnimationTrack & at = collada . state . animation_tracks [ nm . anim_tracks . front ( ) - > get ( ) ] ;
2014-02-10 02:10:30 +01:00
snapshots . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < at . keys . size ( ) ; i + + )
2014-02-10 02:10:30 +01:00
snapshots . push_back ( at . keys [ i ] . time ) ;
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < snapshots . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( List < int > : : Element * ET = nm . anim_tracks . front ( ) ; ET ; ET = ET - > next ( ) ) {
2014-02-10 02:10:30 +01:00
//apply tracks
2017-03-05 16:44:50 +01:00
if ( p_clip = = - 1 ) {
2014-02-10 02:10:30 +01:00
2015-12-21 13:05:49 +01:00
if ( track_filter . has ( ET - > get ( ) ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2015-12-21 13:05:49 +01:00
}
2014-02-10 02:10:30 +01:00
} else {
if ( ! track_filter . has ( ET - > get ( ) ) )
continue ;
}
2017-03-05 16:44:50 +01:00
found_anim = true ;
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
const Collada : : AnimationTrack & at = collada . state . animation_tracks [ ET - > get ( ) ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int xform_idx = - 1 ;
for ( int j = 0 ; j < cn - > xform_list . size ( ) ; j + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( cn - > xform_list [ j ] . id = = at . param ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
xform_idx = j ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2017-03-05 16:44:50 +01:00
if ( xform_idx = = - 1 ) {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Couldn't find matching node " + at . target + " xform for track " + at . param ) ;
2017-03-05 16:44:50 +01:00
continue ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( xform_idx = = - 1 ) ;
2014-02-10 02:10:30 +01:00
Vector < float > data = at . get_value_at_time ( snapshots [ i ] ) ;
ERR_CONTINUE ( data . empty ( ) ) ;
2018-07-25 03:11:03 +02:00
Collada : : Node : : XForm & xf = cn - > xform_list . write [ xform_idx ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( at . component = = " ANGLE " ) {
ERR_CONTINUE ( data . size ( ) ! = 1 ) ;
ERR_CONTINUE ( xf . op ! = Collada : : Node : : XForm : : OP_ROTATE ) ;
ERR_CONTINUE ( xf . data . size ( ) < 4 ) ;
2018-07-25 03:11:03 +02:00
xf . data . write [ 3 ] = data [ 0 ] ;
2017-03-05 16:44:50 +01:00
} else if ( at . component = = " X " | | at . component = = " Y " | | at . component = = " Z " ) {
int cn = at . component [ 0 ] - ' X ' ;
ERR_CONTINUE ( cn > = xf . data . size ( ) ) ;
ERR_CONTINUE ( data . size ( ) > 1 ) ;
2018-07-25 03:11:03 +02:00
xf . data . write [ cn ] = data [ 0 ] ;
2017-03-05 16:44:50 +01:00
} else if ( data . size ( ) = = xf . data . size ( ) ) {
xf . data = data ;
2014-02-10 02:10:30 +01:00
} else {
2018-08-24 09:35:07 +02:00
ERR_EXPLAIN ( " Component " + at . component + " has datasize " + itos ( data . size ( ) ) + " , xfdatasize " + itos ( xf . data . size ( ) ) ) ;
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( data . size ( ) ! = xf . data . size ( ) ) ;
2014-02-10 02:10:30 +01:00
}
}
Transform xform = cn - > compute_transform ( collada ) ;
xform = collada . fix_transform ( xform ) * cn - > post_transform ;
2017-03-05 16:44:50 +01:00
if ( nm . bone > = 0 ) {
2014-02-10 02:10:30 +01:00
//make bone transform relative to rest (in case of skeleton)
2017-08-24 22:58:51 +02:00
Skeleton * sk = Object : : cast_to < Skeleton > ( nm . node ) ;
2014-02-10 02:10:30 +01:00
if ( sk ) {
xform = sk - > get_bone_rest ( nm . bone ) . affine_inverse ( ) * xform ;
} else {
2018-08-24 09:35:07 +02:00
ERR_PRINT ( " Collada: Invalid skeleton " ) ;
2014-02-10 02:10:30 +01:00
}
}
2018-11-21 16:15:08 +01:00
Quat q = Math : : is_equal_approx ( xform . basis . determinant ( ) , 0 ) ? Quat ( ) : xform . basis . get_rotation_quat ( ) ;
2014-02-10 02:10:30 +01:00
Vector3 s = xform . basis . get_scale ( ) ;
Vector3 l = xform . origin ;
2017-03-05 16:44:50 +01:00
animation - > transform_track_insert_key ( track , snapshots [ i ] , l , q , s ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( nm . bone > = 0 ) {
2014-02-10 02:10:30 +01:00
if ( found_anim )
2017-03-05 16:44:50 +01:00
bones_with_animation [ E - > get ( ) ] = true ;
2014-02-10 02:10:30 +01:00
}
if ( found_anim )
2017-03-05 16:44:50 +01:00
tracks_found = true ;
2014-02-10 02:10:30 +01:00
else {
2017-03-05 16:44:50 +01:00
animation - > remove_track ( track ) ;
2014-02-10 02:10:30 +01:00
}
}
2014-08-02 03:10:38 +02:00
if ( p_make_tracks_in_all_bones ) {
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
//some bones may lack animation, but since we don't store pose as a property, we must add keyframes!
2017-03-05 16:44:50 +01:00
for ( Map < String , bool > : : Element * E = bones_with_animation . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
if ( E - > get ( ) )
continue ;
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
NodeMap & nm = node_map [ E - > key ( ) ] ;
String path = scene - > get_path_to ( nm . node ) ;
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( nm . bone < 0 ) ;
Skeleton * sk = static_cast < Skeleton * > ( nm . node ) ;
2014-08-02 03:10:38 +02:00
String name = sk - > get_bone_name ( nm . bone ) ;
2017-03-05 16:44:50 +01:00
path = path + " : " + name ;
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
Collada : : Node * cn = collada . state . scene_map [ E - > key ( ) ] ;
if ( cn - > ignore_anim ) {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Ignoring animation on node: " + path ) ;
2014-08-02 03:10:38 +02:00
continue ;
}
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
animation - > add_track ( Animation : : TYPE_TRANSFORM ) ;
2017-03-05 16:44:50 +01:00
int track = animation - > get_track_count ( ) - 1 ;
animation - > track_set_path ( track , path ) ;
animation - > track_set_imported ( track , true ) ; //helps merging later
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
Transform xform = cn - > compute_transform ( collada ) ;
xform = collada . fix_transform ( xform ) * cn - > post_transform ;
2014-02-10 02:10:30 +01:00
2014-08-02 03:10:38 +02:00
xform = sk - > get_bone_rest ( nm . bone ) . affine_inverse ( ) * xform ;
2014-02-10 02:10:30 +01:00
2018-11-21 16:15:08 +01:00
Quat q = Math : : is_equal_approx ( xform . basis . determinant ( ) , 0 ) ? Quat ( ) : xform . basis . get_rotation_quat ( ) ;
2014-08-02 03:10:38 +02:00
Vector3 s = xform . basis . get_scale ( ) ;
Vector3 l = xform . origin ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
animation - > transform_track_insert_key ( track , 0 , l , q , s ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
tracks_found = true ;
2014-08-02 03:10:38 +02:00
}
2014-02-10 02:10:30 +01:00
}
2016-11-03 09:41:28 +01:00
if ( p_import_value_tracks ) {
for ( int i = 0 ; i < valid_animated_properties . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
int ti = valid_animated_properties [ i ] ;
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
if ( p_clip = = - 1 ) {
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
if ( track_filter . has ( ti ) )
continue ;
2017-03-05 16:44:50 +01:00
} else {
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
if ( ! track_filter . has ( ti ) )
continue ;
}
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
const Collada : : AnimationTrack & at = collada . state . animation_tracks [ ti ] ;
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
// take snapshots
if ( ! collada . state . scene_map . has ( at . target ) )
continue ;
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
NodeMap & nm = node_map [ at . target ] ;
String path = scene - > get_path_to ( nm . node ) ;
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
animation - > add_track ( Animation : : TYPE_VALUE ) ;
int track = animation - > get_track_count ( ) - 1 ;
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
path = path + " : " + at . param ;
animation - > track_set_path ( track , path ) ;
animation - > track_set_imported ( track , true ) ; //helps merging later
2016-06-20 05:19:04 +02:00
2016-11-03 09:41:28 +01:00
for ( int i = 0 ; i < at . keys . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
float time = at . keys [ i ] . time ;
Variant value ;
Vector < float > data = at . keys [ i ] . data ;
if ( data . size ( ) = = 1 ) {
//push a float
value = data [ 0 ] ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( data . size ( ) = = 16 ) {
2016-11-03 09:41:28 +01:00
//matrix
2018-08-24 09:35:07 +02:00
WARN_PRINT ( " Collada: Value keys for matrices not supported. " ) ;
2017-03-05 16:44:50 +01:00
} else {
2018-08-24 09:35:07 +02:00
WARN_PRINTS ( " Collada: Unexpected amount of value keys: " + itos ( data . size ( ) ) ) ;
2016-11-03 09:41:28 +01:00
}
2014-02-10 02:10:30 +01:00
2016-11-03 09:41:28 +01:00
animation - > track_insert_key ( track , time , value ) ;
2014-02-10 02:10:30 +01:00
}
2016-11-03 09:41:28 +01:00
tracks_found = true ;
}
2014-02-10 02:10:30 +01:00
}
if ( tracks_found ) {
animations . push_back ( animation ) ;
}
}
/*********************************************************************************/
/*************************************** SCENE ***********************************/
/*********************************************************************************/
uint32_t EditorSceneImporterCollada : : get_import_flags ( ) const {
2017-03-05 16:44:50 +01:00
return IMPORT_SCENE | IMPORT_ANIMATION ;
2014-02-10 02:10:30 +01:00
}
void EditorSceneImporterCollada : : get_extensions ( List < String > * r_extensions ) const {
r_extensions - > push_back ( " dae " ) ;
}
2017-03-05 16:44:50 +01:00
Node * EditorSceneImporterCollada : : import_scene ( const String & p_path , uint32_t p_flags , int p_bake_fps , List < String > * r_missing_deps , Error * r_err ) {
2014-02-10 02:10:30 +01:00
ColladaImport state ;
2017-03-05 16:44:50 +01:00
uint32_t flags = Collada : : IMPORT_FLAG_SCENE ;
if ( p_flags & IMPORT_ANIMATION )
flags | = Collada : : IMPORT_FLAG_ANIMATION ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
state . use_mesh_builtin_materials = ! ( p_flags & IMPORT_MATERIALS_IN_INSTANCES ) ;
state . bake_fps = p_bake_fps ;
2014-02-10 02:10:30 +01:00
2017-11-01 01:01:24 +01:00
Error err = state . load ( p_path , flags , p_flags & EditorSceneImporter : : IMPORT_GENERATE_TANGENT_ARRAYS , p_flags & EditorSceneImporter : : IMPORT_USE_COMPRESSION ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err ! = OK , NULL ) ;
2014-02-10 02:10:30 +01:00
if ( state . missing_textures . size ( ) ) {
2017-01-14 12:26:56 +01:00
/*
for ( int i = 0 ; i < state . missing_textures . size ( ) ; i + + ) {
EditorNode : : add_io_error ( " Texture Not Found: " + state . missing_textures [ i ] ) ;
}
*/
2014-05-05 03:50:23 +02:00
if ( r_missing_deps ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < state . missing_textures . size ( ) ; i + + ) {
2014-05-05 03:50:23 +02:00
//EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
r_missing_deps - > push_back ( state . missing_textures [ i ] ) ;
}
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( p_flags & IMPORT_ANIMATION ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
state . create_animations ( p_flags & IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS , p_flags & EditorSceneImporter : : IMPORT_ANIMATION_KEEP_VALUE_TRACKS ) ;
AnimationPlayer * ap = memnew ( AnimationPlayer ) ;
for ( int i = 0 ; i < state . animations . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
String name ;
2017-03-05 16:44:50 +01:00
if ( state . animations [ i ] - > get_name ( ) = = " " )
name = " default " ;
2014-02-10 02:10:30 +01:00
else
2017-03-05 16:44:50 +01:00
name = state . animations [ i ] - > get_name ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_flags & IMPORT_ANIMATION_DETECT_LOOP ) {
2014-02-10 02:10:30 +01:00
if ( name . begins_with ( " loop " ) | | name . ends_with ( " loop " ) | | name . begins_with ( " cycle " ) | | name . ends_with ( " cycle " ) ) {
2018-07-25 03:11:03 +02:00
state . animations . write [ i ] - > set_loop ( true ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
ap - > add_animation ( name , state . animations [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
state . scene - > add_child ( ap ) ;
ap - > set_owner ( state . scene ) ;
}
return state . scene ;
}
2017-12-10 01:27:02 +01:00
Ref < Animation > EditorSceneImporterCollada : : import_animation ( const String & p_path , uint32_t p_flags , int p_bake_fps ) {
2014-02-10 02:10:30 +01:00
ColladaImport state ;
2017-03-05 16:44:50 +01:00
state . use_mesh_builtin_materials = false ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error err = state . load ( p_path , Collada : : IMPORT_FLAG_ANIMATION , p_flags & EditorSceneImporter : : IMPORT_GENERATE_TANGENT_ARRAYS ) ;
ERR_FAIL_COND_V ( err ! = OK , RES ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
state . create_animations ( p_flags & EditorSceneImporter : : IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS , p_flags & EditorSceneImporter : : IMPORT_ANIMATION_KEEP_VALUE_TRACKS ) ;
2014-02-10 02:10:30 +01:00
if ( state . scene )
memdelete ( state . scene ) ;
2017-03-05 16:44:50 +01:00
if ( state . animations . size ( ) = = 0 )
2014-02-10 02:10:30 +01:00
return Ref < Animation > ( ) ;
2017-03-05 16:44:50 +01:00
Ref < Animation > anim = state . animations [ 0 ] ;
2017-01-14 04:51:09 +01:00
String base = p_path . get_basename ( ) . to_lower ( ) ;
2017-03-05 16:44:50 +01:00
if ( p_flags & IMPORT_ANIMATION_DETECT_LOOP ) {
2014-02-10 02:10:30 +01:00
if ( base . begins_with ( " loop " ) | | base . ends_with ( " loop " ) | | base . begins_with ( " cycle " ) | | base . ends_with ( " cycle " ) ) {
anim - > set_loop ( true ) ;
}
}
return anim ;
}
EditorSceneImporterCollada : : EditorSceneImporterCollada ( ) {
}