Browse Source

Collada
-=-=-=-

-Fixed some DAE import & export bugs
-Changed Collada exporter to use the mesh loops API
-Added tangent export to Collada exporter
-Added triangulation option to Collada exporter
-Changed a little how normalmaps are handled in shader. Not sure if it's working properly, be careful.
-Fixed some strange bug with kinematic bodies #776
-Fix release compilaiton issues #782

Juan Linietsky 11 years ago
parent
commit
a84ba9c853

+ 4 - 1
drivers/gles2/rasterizer_gles2.cpp

@@ -4419,7 +4419,7 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
 			enablers.push_back("#define ENABLE_UV_INTERP\n");
 		if (fragment_flags.use_uv2_interp || vertex_flags.use_uv2_interp)
 			enablers.push_back("#define ENABLE_UV2_INTERP\n");
-		if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp)
+		if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp || fragment_flags.uses_normalmap)
 			enablers.push_back("#define ENABLE_TANGENT_INTERP\n");
 		if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp)
 			enablers.push_back("#define ENABLE_VAR1_INTERP\n");
@@ -4434,6 +4434,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
 		if (fragment_flags.uses_discard) {
 			enablers.push_back("#define ENABLE_DISCARD\n");
 		}
+		if (fragment_flags.uses_normalmap) {
+			enablers.push_back("#define ENABLE_NORMALMAP\n");
+		}
 		if (light_flags.uses_light) {
 			enablers.push_back("#define USE_LIGHT_SHADER_CODE\n");
 		}

+ 9 - 0
drivers/gles2/shader_compiler_gles2.cpp

@@ -176,6 +176,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 				if (vnode->name==vname_discard) {
 					uses_discard=true;
 				}
+				if (vnode->name==vname_normalmap) {
+					uses_normalmap=true;
+				}
 				if (vnode->name==vname_screen_uv) {
 					uses_screen_uv=true;
 				}
@@ -546,6 +549,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	uses_screen_uv=false;
 	uses_light=false;
 	uses_time=false;
+	uses_normalmap=false;
 	vertex_code_writes_vertex=false;
 	uniforms=r_uniforms;
 	flags=&r_flags;
@@ -555,6 +559,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.use_tangent_interp=false;
 	r_flags.use_var1_interp=false;
 	r_flags.use_var2_interp=false;
+	r_flags.uses_normalmap=false;
 
 	String error;
 	int errline,errcol;
@@ -576,8 +581,10 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.uses_screen_uv=uses_screen_uv;
 	r_flags.uses_light=uses_light;
 	r_flags.uses_time=uses_time;
+	r_flags.uses_normalmap=uses_normalmap;
 	r_code_line=code;
 	r_globals_line=global_code;
+
 	return OK;
 }
 
@@ -670,6 +677,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	mode_replace_table[1]["NORMAL"]="normal";
 	mode_replace_table[1]["TANGENT"]="tangent";
 	mode_replace_table[1]["BINORMAL"]="binormal";
+	mode_replace_table[1]["NORMALMAP"]="normalmap";
 	mode_replace_table[1]["VAR1"]="var1_interp";
 	mode_replace_table[1]["VAR2"]="var2_interp";
 	mode_replace_table[1]["UV"]="uv";
@@ -728,5 +736,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	vname_vertex="VERTEX";
 	vname_light="LIGHT";
 	vname_time="TIME";
+	vname_normalmap="NORMALMAP";
 
 }

+ 3 - 0
drivers/gles2/shader_compiler_gles2.h

@@ -50,6 +50,7 @@ private:
 	bool uses_discard;
 	bool uses_time;
 	bool uses_screen_uv;
+	bool uses_normalmap;
 	bool vertex_code_writes_vertex;
 	Flags *flags;
 
@@ -66,6 +67,7 @@ private:
 	StringName vname_vertex;
 	StringName vname_light;
 	StringName vname_time;
+	StringName vname_normalmap;
 
 	Map<StringName,ShaderLanguage::Uniform> *uniforms;
 
@@ -87,6 +89,7 @@ public:
 		bool uses_alpha;
 		bool uses_texscreen;
 		bool uses_texpos;
+		bool uses_normalmap;
 		bool vertex_code_writes_vertex;
 		bool uses_discard;
 		bool uses_screen_uv;

+ 9 - 0
drivers/gles2/shaders/material.glsl

@@ -819,6 +819,10 @@ void main() {
 	vec4 color = color_interp;
 #endif
 
+#if defined(ENABLE_NORMALMAP)
+
+	vec3 normalmap = vec3(0.0);
+#endif
 
 
 
@@ -833,6 +837,11 @@ FRAGMENT_SHADER_CODE
 
 }
 
+#if defined(ENABLE_NORMALMAP)
+
+	normal = normalize( tangent_interp * normalmap.x + binormal_interp * normalmap.y + normal_interp * normalmap.z ) * side;
+#endif
+
 #if defined(ENABLE_DISCARD)
 	if (discard_) {
 	//easy to eliminate dead code

+ 10 - 0
scene/2d/physics_body_2d.cpp

@@ -925,6 +925,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 			normal=rest_info.normal;
 			collider=rest_info.collider_id;
 			collider_vel=rest_info.linear_velocity;
+			collider_shape=rest_info.shape;
 		}
 
 	}
@@ -1013,6 +1014,12 @@ ObjectID KinematicBody2D::get_collider() const {
 	return collider;
 }
 
+
+int KinematicBody2D::get_collider_shape() const {
+
+	ERR_FAIL_COND_V(!colliding,0);
+	return collider_shape;
+}
 void KinematicBody2D::set_collide_with_static_bodies(bool p_enable) {
 
 	collide_static=p_enable;
@@ -1076,6 +1083,7 @@ void KinematicBody2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody2D::get_collision_normal);
 	ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity);
 	ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider);
+	ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape);
 
 
 	ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody2D::set_collide_with_static_bodies);
@@ -1112,6 +1120,8 @@ KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KI
 	colliding=false;
 	collider=0;
 
+	collider_shape=0;
+
 	margin=0.08;
 }
 KinematicBody2D::~KinematicBody2D()  {

+ 2 - 1
scene/2d/physics_body_2d.h

@@ -254,7 +254,7 @@ class KinematicBody2D : public PhysicsBody2D {
 	Vector2 normal;
 	Vector2 collider_vel;
 	ObjectID collider;
-
+	int collider_shape;
 
 	Variant _get_collider() const;
 
@@ -273,6 +273,7 @@ public:
 	Vector2 get_collision_normal() const;
 	Vector2 get_collider_velocity() const;
 	ObjectID get_collider() const;
+	int get_collider_shape() const;
 
 	void set_collide_with_static_bodies(bool p_enable);
 	bool can_collide_with_static_bodies() const;

+ 6 - 1
scene/3d/light.cpp

@@ -435,15 +435,20 @@ void Light::_update_visibility() {
 	if (!is_inside_scene())
 		return;
 
+
+
+#ifdef TOOLS_ENABLED
 	bool editor_ok=true;
 	if (editor_only) {
-
 		if (!get_scene()->is_editor_hint()) {
 			editor_ok=false;
 		} else {
 			editor_ok = (get_scene()->get_edited_scene_root() && (this==get_scene()->get_edited_scene_root() || get_owner()==get_scene()->get_edited_scene_root()));
 		}
 	}
+#else
+	bool editor_ok=false;
+#endif
 
 
 	VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && enabled && editor_ok);

+ 8 - 0
scene/3d/physics_body.cpp

@@ -967,6 +967,7 @@ Vector3 KinematicBody::move(const Vector3& p_motion) {
 			normal=rest.normal;
 			collider=rest.collider_id;
 			collider_vel=rest.linear_velocity;
+			collider_shape=rest.shape;
 		}
 	}
 
@@ -1055,7 +1056,12 @@ ObjectID KinematicBody::get_collider() const {
 	ERR_FAIL_COND_V(!colliding,0);
 	return collider;
 }
+int KinematicBody::get_collider_shape() const {
 
+	ERR_FAIL_COND_V(!colliding,-1);
+	return collider_shape;
+
+}
 void KinematicBody::set_collide_with_static_bodies(bool p_enable) {
 
 	collide_static=p_enable;
@@ -1119,6 +1125,7 @@ void KinematicBody::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody::get_collision_normal);
 	ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody::get_collider_velocity);
 	ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody::_get_collider);
+	ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody::get_collider_shape);
 
 
 	ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody::set_collide_with_static_bodies);
@@ -1155,6 +1162,7 @@ KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC)
 	colliding=false;
 	collider=0;
 	margin=0.001;
+	collider_shape=0;
 }
 KinematicBody::~KinematicBody()  {
 

+ 2 - 0
scene/3d/physics_body.h

@@ -266,6 +266,7 @@ class KinematicBody : public PhysicsBody {
 	Vector3 normal;
 	Vector3 collider_vel;
 	ObjectID collider;
+	int collider_shape;
 
 
 	Variant _get_collider() const;
@@ -291,6 +292,7 @@ public:
 	Vector3 get_collision_normal() const;
 	Vector3 get_collider_velocity() const;
 	ObjectID get_collider() const;
+	int get_collider_shape() const;
 
 	void set_collide_with_static_bodies(bool p_enable);
 	bool can_collide_with_static_bodies() const;

+ 2 - 0
scene/main/scene_main_loop.cpp

@@ -1085,7 +1085,9 @@ SceneMainLoop::SceneMainLoop() {
 
 	root->set_physics_object_picking(GLOBAL_DEF("physics/enable_object_picking",true));
 
+#ifdef TOOLS_ENABLED
 	edited_scene_root=NULL;
+#endif
 
 	ADD_SIGNAL( MethodInfo("idle_frame"));
 	ADD_SIGNAL( MethodInfo("fixed_frame"));

+ 3 - 2
scene/main/timer.cpp

@@ -37,9 +37,10 @@ void Timer::_notification(int p_what) {
 		case NOTIFICATION_READY: {
 
 			if (autostart) {
-				if (get_scene()->is_editor_hint() && get_scene()->get_edited_scene_root() &&  (get_scene()->get_edited_scene_root()==this || get_scene()->get_edited_scene_root()->is_a_parent_of(this)))
+#ifdef TOOLS_ENABLED
+				if (get_scene()->is_editor_hint() && get_scene()->get_edited_scene_root() && (get_scene()->get_edited_scene_root()==this || get_scene()->get_edited_scene_root()->is_a_parent_of(this)))
 					break;
-				start();
+#endif				start();
 			}
 		} break;
 		case NOTIFICATION_PROCESS: {

+ 27 - 0
scene/resources/mesh.cpp

@@ -29,6 +29,7 @@
 #include "mesh.h"
 #include "scene/resources/concave_polygon_shape.h"
 #include "scene/resources/convex_polygon_shape.h"
+#include "surface_tool.h"
 
 static const char*_array_name[]={
 	"vertex_array",
@@ -648,6 +649,30 @@ void Mesh::center_geometry() {
 
 }
 
+void Mesh::regen_normalmaps() {
+
+
+	Vector< Ref<SurfaceTool> > surfs;
+	for(int i=0;i<get_surface_count();i++) {
+
+		Ref<SurfaceTool> st = memnew( SurfaceTool );
+		st->create_from(Ref<Mesh>(this),i);
+		surfs.push_back(st);
+	}
+
+	while (get_surface_count()) {
+		surface_remove(0);
+	}
+
+	for(int i=0;i<surfs.size();i++) {
+
+		surfs[i]->generate_tangents();
+		surfs[i]->commit(Ref<Mesh>(this));
+	}
+}
+
+
+
 Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
 
 	if (triangle_mesh.is_valid())
@@ -740,6 +765,8 @@ void Mesh::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("surface_get_name","surf_idx"),&Mesh::surface_get_name);
 	ObjectTypeDB::bind_method(_MD("center_geometry"),&Mesh::center_geometry);
 	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+	ObjectTypeDB::bind_method(_MD("regen_normalmaps"),&Mesh::regen_normalmaps);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
 
 	ObjectTypeDB::bind_method(_MD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb);
 	ObjectTypeDB::bind_method(_MD("get_custom_aabb"),&Mesh::get_custom_aabb);

+ 1 - 0
scene/resources/mesh.h

@@ -167,6 +167,7 @@ public:
 	Ref<Shape> create_convex_shape() const;
 
 	void center_geometry();
+	void regen_normalmaps();
 
 	DVector<Face3> get_faces() const;
 	Ref<TriangleMesh> generate_triangle_mesh() const;

+ 70 - 136
scene/resources/surface_tool.cpp

@@ -105,7 +105,7 @@ void SurfaceTool::add_vertex( const Vector3& p_vertex) {
 	vtx.weights=last_weights;
 	vtx.bones=last_bones;
 	vtx.tangent=last_tangent.normal;
-	vtx.binormal=last_tangent.normal.cross(last_normal).normalized() * last_tangent.d;
+	vtx.binormal=last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
 	vertex_array.push_back(vtx);
 	first=false;
 	format|=Mesh::ARRAY_FORMAT_VERTEX;
@@ -299,7 +299,9 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
 					w[idx+0]=v.tangent.x;
 					w[idx+1]=v.tangent.y;
 					w[idx+2]=v.tangent.z;
-					float d = v.binormal.dot(v.normal.cross(v.tangent));
+
+					//float d = v.tangent.dot(v.binormal,v.normal);
+					float d = v.binormal.dot( v.normal.cross(v.tangent));
 					w[idx+3]=d<0 ? -1 : 1;
 				}
 
@@ -565,6 +567,7 @@ void SurfaceTool::create_from(const Ref<Mesh>& p_existing, int p_surface) {
 	clear();
 	primitive=p_existing->surface_get_primitive_type(p_surface);
 	_create_list(p_existing,p_surface,&vertex_array,&index_array,format);
+	material=p_existing->surface_get_material(p_surface);
 
 }
 
@@ -611,165 +614,96 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T
 
 }
 
+//mikktspace callbacks
+int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext * pContext) {
 
-void SurfaceTool::generate_tangents() {
-
-	ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
-	ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
-
-
-	if (index_array.size()) {
-
-		Vector<List<Vertex>::Element*> vtx;
-		vtx.resize(vertex_array.size());
-		int idx=0;
-		for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
-			vtx[idx++]=E;
-			E->get().binormal=Vector3();
-			E->get().tangent=Vector3();
-		}
-
-		for (List<int>::Element *E=index_array.front();E;) {
-
-			int i[3];
-			i[0]=E->get();
-			E=E->next();
-			ERR_FAIL_COND(!E);
-			i[1]=E->get();
-			E=E->next();
-			ERR_FAIL_COND(!E);
-			i[2]=E->get();
-			E=E->next();
-			ERR_FAIL_COND(!E);
-
-
-			Vector3 v1 = vtx[ i[0] ]->get().vertex;
-			Vector3 v2 = vtx[ i[1] ]->get().vertex;
-			Vector3 v3 = vtx[ i[2] ]->get().vertex;
-
-			Vector2 w1 = vtx[ i[0] ]->get().uv;
-			Vector2 w2 = vtx[ i[1] ]->get().uv;
-			Vector2 w3 = vtx[ i[2] ]->get().uv;
-
-
-			float x1 = v2.x - v1.x;
-			float x2 = v3.x - v1.x;
-			float y1 = v2.y - v1.y;
-			float y2 = v3.y - v1.y;
-			float z1 = v2.z - v1.z;
-			float z2 = v3.z - v1.z;
-
-			float s1 = w2.x - w1.x;
-			float s2 = w3.x - w1.x;
-			float t1 = w2.y - w1.y;
-			float t2 = w3.y - w1.y;
-
-			float r  = (s1 * t2 - s2 * t1);
-
-			Vector3 binormal,tangent;
-
-			if (r==0) {
-				binormal=Vector3(0,0,0);
-				tangent=Vector3(0,0,0);
-			} else {
-				tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
-				(t2 * z1 - t1 * z2) * r);
-				binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
-				(s1 * z2 - s2 * z1) * r);
-			}
-
-			tangent.normalize();
-			binormal.normalize();
-			Vector3 normal=Plane( v1, v2, v3 ).normal;
-
-			Vector3 tangentp = tangent - normal * normal.dot( tangent );
-			Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
-
-			tangentp.normalize();
-			binormalp.normalize();
+	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+	return varr.size()/3;
+}
+int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace){
 
+	return 3; //always 3
+}
+void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){
 
-			for (int j=0;j<3;j++) {
-				vtx[ i[j] ]->get().binormal+=binormalp;
-				vtx[ i[j] ]->get().tangent+=tangentp;
+	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+	Vector3 v = varr[iFace*3+iVert]->get().vertex;
+	fvPosOut[0]=v.x;
+	fvPosOut[1]=v.y;
+	fvPosOut[2]=v.z;
 
-			}
-		}
 
-		for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
-			E->get().binormal.normalize();
-			E->get().tangent.normalize();
-		}
+}
 
+void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){
 
-	} else {
 
+	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+	Vector3 v = varr[iFace*3+iVert]->get().normal;
+	fvNormOut[0]=v.x;
+	fvNormOut[1]=v.y;
+	fvNormOut[2]=v.z;
 
-		for (List<Vertex>::Element *E=vertex_array.front();E;) {
+}
+void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){
 
-			List< Vertex >::Element *v[3];
-			v[0]=E;
-			v[1]=v[0]->next();
-			ERR_FAIL_COND(!v[1]);
-			v[2]=v[1]->next();
-			ERR_FAIL_COND(!v[2]);
-			E=v[2]->next();
+	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+	Vector2 v = varr[iFace*3+iVert]->get().uv;
+	fvTexcOut[0]=v.x;
+	//fvTexcOut[1]=v.y;
+	fvTexcOut[1]=1.0-v.y;
 
-			Vector3 v1 = v[0]->get().vertex;
-			Vector3 v2 = v[1]->get().vertex;
-			Vector3 v3 = v[2]->get().vertex;
+}
+void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){
 
-			Vector2 w1 = v[0]->get().uv;
-			Vector2 w2 = v[1]->get().uv;
-			Vector2 w3 = v[2]->get().uv;
+	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
+	Vertex &vtx = varr[iFace*3+iVert]->get();
 
+	vtx.tangent = Vector3(fvTangent[0],fvTangent[1],fvTangent[2]);
+	vtx.binormal = vtx.normal.cross(vtx.tangent) * fSign;
+}
 
-			float x1 = v2.x - v1.x;
-			float x2 = v3.x - v1.x;
-			float y1 = v2.y - v1.y;
-			float y2 = v3.y - v1.y;
-			float z1 = v2.z - v1.z;
-			float z2 = v3.z - v1.z;
 
-			float s1 = w2.x - w1.x;
-			float s2 = w3.x - w1.x;
-			float t1 = w2.y - w1.y;
-			float t2 = w3.y - w1.y;
+void SurfaceTool::generate_tangents() {
 
-			float r  = (s1 * t2 - s2 * t1);
+	ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV));
+	ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL));
 
-			Vector3 binormal,tangent;
+	bool indexed = index_array.size()>0;
+	if (indexed)
+		deindex();
 
-			if (r==0) {
-				binormal=Vector3(0,0,0);
-				tangent=Vector3(0,0,0);
-			} else {
-				tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
-				(t2 * z1 - t1 * z2) * r);
-				binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
-				(s1 * z2 - s2 * z1) * r);
-			}
 
-			tangent.normalize();
-			binormal.normalize();
-			Vector3 normal=Plane( v1, v2, v3 ).normal;
+	SMikkTSpaceInterface mkif;
+	mkif.m_getNormal=mikktGetNormal;
+	mkif.m_getNumFaces=mikktGetNumFaces;
+	mkif.m_getNumVerticesOfFace=mikktGetNumVerticesOfFace;
+	mkif.m_getPosition=mikktGetPosition;
+	mkif.m_getTexCoord=mikktGetTexCoord;
+	mkif.m_setTSpaceBasic=mikktSetTSpaceBasic;
+	mkif.m_setTSpace=NULL;
 
-			Vector3 tangentp = tangent - normal * normal.dot( tangent );
-			Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal));
+	SMikkTSpaceContext msc;
+	msc.m_pInterface=&mkif;
 
-			tangentp.normalize();
-			binormalp.normalize();
+	Vector<List<Vertex>::Element*> vtx;
+	vtx.resize(vertex_array.size());
+	int idx=0;
+	for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) {
+		vtx[idx++]=E;
+		E->get().binormal=Vector3();
+		E->get().tangent=Vector3();
+	}
+	msc.m_pUserData=&vtx;
 
+	bool res = genTangSpaceDefault(&msc);
 
-			for (int j=0;j<3;j++) {
-				v[j]->get().binormal=binormalp;
-				v[j]->get().tangent=tangentp;
+	ERR_FAIL_COND(!res);
+	format|=Mesh::ARRAY_FORMAT_TANGENT;
 
-			}
-		}
-	}
+	if (indexed)
+		index();
 
-	format|=Mesh::ARRAY_FORMAT_TANGENT;
 
 }
 

+ 9 - 1
scene/resources/surface_tool.h

@@ -30,7 +30,7 @@
 #define SURFACE_TOOL_H
 
 #include "scene/resources/mesh.h"
-
+#include "mikktspace.h"
 
 
 class SurfaceTool : public Reference {
@@ -82,6 +82,14 @@ private:
 
 	void _create_list(const Ref<Mesh>& p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index,int &lformat);
 
+
+	//mikktspace callbacks
+	static int mikktGetNumFaces(const SMikkTSpaceContext * pContext);
+	static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace);
+	static void mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert);
+	static void mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert);
+	static void mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert);
+	static void mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert);
 protected:
 
 	static void _bind_methods();

+ 11 - 0
servers/physics/body_sw.cpp

@@ -185,6 +185,7 @@ float BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
 
 void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
 
+	PhysicsServer::BodyMode prev=mode;
 	mode=p_mode;
 
 	switch(p_mode) {
@@ -199,6 +200,10 @@ void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
 			set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC && contacts.size());
 			linear_velocity=Vector3();
 			angular_velocity=Vector3();
+			if (mode==PhysicsServer::BODY_MODE_KINEMATIC && prev!=mode) {
+				first_time_kinematic=true;
+			}
+
 		} break;
 		case PhysicsServer::BODY_MODE_RIGID: {
 
@@ -238,6 +243,11 @@ void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant& p_varian
 				new_transform=p_variant;
 				//wakeup_neighbours();
 				set_active(true);
+				if (first_time_kinematic) {
+					_set_transform(p_variant);
+					_set_inv_transform(get_transform().affine_inverse());
+					first_time_kinematic=false;
+				}
 
 			} else if (mode==PhysicsServer::BODY_MODE_STATIC) {
 				_set_transform(p_variant);
@@ -669,6 +679,7 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda
 	island_step=0;
 	island_next=NULL;
 	island_list_next=NULL;
+	first_time_kinematic=false;
 	_set_static(false);
 	density=0;
 	contact_count=0;

+ 1 - 0
servers/physics/body_sw.h

@@ -74,6 +74,7 @@ class BodySW : public CollisionObjectSW {
 
 	bool continuous_cd;
 	bool can_sleep;
+	bool first_time_kinematic;
 	void _update_inertia();
 	virtual void _shapes_changed();
 	Transform new_transform;

+ 12 - 1
servers/physics_2d/body_2d_sw.cpp

@@ -176,6 +176,7 @@ float Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
 
 void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
 
+	Physics2DServer::BodyMode prev=mode;
 	mode=p_mode;
 
 	switch(p_mode) {
@@ -189,6 +190,9 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
 			set_active(p_mode==Physics2DServer::BODY_MODE_KINEMATIC && contacts.size());
 			linear_velocity=Vector2();
 			angular_velocity=0;
+			if (mode==Physics2DServer::BODY_MODE_KINEMATIC && prev!=mode) {
+				first_time_kinematic=true;
+			}
 		} break;
 		case Physics2DServer::BODY_MODE_RIGID: {
 
@@ -226,9 +230,15 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant& p_va
 
 
 			if (mode==Physics2DServer::BODY_MODE_KINEMATIC) {
-				new_transform=p_variant;
+
+				new_transform=p_variant;				
 				//wakeup_neighbours();
 				set_active(true);
+				if (first_time_kinematic) {
+					_set_transform(p_variant);
+					_set_inv_transform(get_transform().affine_inverse());
+					first_time_kinematic=false;
+				}
 			} else if (mode==Physics2DServer::BODY_MODE_STATIC) {
 				_set_transform(p_variant);
 				_set_inv_transform(get_transform().affine_inverse());
@@ -591,6 +601,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
 	island_next=NULL;
 	island_list_next=NULL;
 	_set_static(false);
+	first_time_kinematic=false;
 	density=0;
 	contact_count=0;
 

+ 1 - 0
servers/physics_2d/body_2d_sw.h

@@ -72,6 +72,7 @@ class Body2DSW : public CollisionObject2DSW {
 	bool omit_force_integration;
 	bool active;
 	bool can_sleep;
+	bool first_time_kinematic;
 	void _update_inertia();
 	virtual void _shapes_changed();
 	Matrix32 new_transform;

+ 2 - 3
servers/visual/rasterizer.cpp

@@ -98,11 +98,10 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) {
 		}
 		if (p_key.use_xy_normalmap) {
 			scode+="vec2 ywnormal=tex( fmp_normal_tex,"+uv_str+").wy * vec2(2.0,2.0) - vec2(1.0,1.0);\n";
-			scode+="vec3 normal=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n";
+			scode+="NORMALMAP=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n";
 		} else {
-			scode+="vec3 normal=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n";
+			scode+="NORMALMAP=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n";
 		}
-		scode+="NORMAL = mix( NORMAL,mat3(TANGENT,BINORMAL,NORMAL) * normal,  fmp_normal);\n";
 		code+=scode;
 	}
 

+ 1 - 0
servers/visual/shader_language.cpp

@@ -1042,6 +1042,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={
 	{ "NORMAL", TYPE_VEC3},
 	{ "TANGENT", TYPE_VEC3},
 	{ "BINORMAL", TYPE_VEC3},
+	{ "NORMALMAP", TYPE_VEC3},
 	{ "UV", TYPE_VEC2},
 	{ "UV2", TYPE_VEC2},
 	{ "COLOR", TYPE_VEC4},

+ 3 - 1
tools/editor/io_plugins/editor_import_collada.cpp

@@ -749,7 +749,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
 						Vector3 tangent =Vector3(tangent_src->array[tangent_pos+0],tangent_src->array[tangent_pos+1],tangent_src->array[tangent_pos+2]);
 
 						vertex.tangent.normal=tangent;
-						vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? -1 : 1;
+						vertex.tangent.d= vertex.normal.cross(tangent).dot(binormal) > 0 ? 1 : -1;
 					}
 
 				}
@@ -784,6 +784,8 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
 					vertex.vertex.z = -vertex.vertex.z;
 					SWAP( vertex.normal.z, vertex.normal.y );
 					vertex.normal.z = -vertex.normal.z;
+					SWAP( vertex.tangent.normal.z, vertex.tangent.normal.y );
+					vertex.tangent.normal.z = -vertex.tangent.normal.z;
 
 				}
 

+ 1 - 1
tools/editor/plugins/spatial_editor_plugin.cpp

@@ -2468,7 +2468,7 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
 	}
 
 	if (d.has("default_srgb")) {
-		bool use = d["default_light"];
+		bool use = d["default_srgb"];
 
 		viewport_environment->set_enable_fx(Environment::FX_SRGB,use);
 		view_menu->get_popup()->set_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB), use );

+ 13 - 0
tools/export/blender25/io_scene_dae/__init__.py

@@ -83,6 +83,17 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
             description="Apply modifiers to mesh objects (on a copy!).",
             default=True,
             )
+    use_tangent_arrays = BoolProperty(
+	    name="Tangent Arrays",
+	    description="Export Tangent and Binormal arrays (for normalmapping).",
+	    default=False,
+	    )
+    use_triangles = BoolProperty(
+	    name="Triangulate",
+	    description="Export Triangles instead of Polygons.",
+	    default=False,
+	    )
+
     use_copy_images = BoolProperty(
             name="Copy Images",
             description="Copy Images (create images/ subfolder)",
@@ -118,6 +129,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
             description="Remove double keyframes",
             default=True,
             )
+
     anim_optimize_precision = FloatProperty(
             name="Precision",
             description=("Tolerence for comparing double keyframes "
@@ -126,6 +138,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
             soft_min=1, soft_max=16,
             default=6.0,
             )
+
     use_metadata = BoolProperty(
             name="Use Metadata",
             default=True,

+ 139 - 36
tools/export/blender25/io_scene_dae/export_dae.py

@@ -43,6 +43,7 @@ import time
 import math  # math.pi
 import shutil
 import bpy
+import bmesh
 from mathutils import Vector, Matrix
 
 #according to collada spec, order matters
@@ -125,6 +126,12 @@ class DaeExporter:
 			tup = (self.vertex.x,self.vertex.y,self.vertex.z,self.normal.x,self.normal.y,self.normal.z)
 			for t in self.uv:
 				tup = tup + (t.x,t.y)
+			if (self.color!=None):
+				tup = tup + (self.color.x,self.color.y,self.color.z)
+			if (self.tangent!=None):
+				tup = tup + (self.tangent.x,self.tangent.y,self.tangent.z)
+			if (self.bitangent!=None):
+				tup = tup + (self.bitangent.x,self.bitangent.y,self.bitangent.z)
 			#for t in self.bones:
 			#	tup = tup + (t)
 			#for t in self.weights:
@@ -135,7 +142,9 @@ class DaeExporter:
 		def __init__(self):
 			self.vertex = Vector( (0.0,0.0,0.0) )
 			self.normal = Vector( (0.0,0.0,0.0) )
-			self.color = Vector( (0.0,0.0,0.0) )
+			self.tangent = None
+			self.bitangent = None
+			self.color = None
 			self.uv = []
 			self.uv2 = Vector( (0.0,0.0) )
 			self.bones=[]
@@ -442,10 +451,18 @@ class DaeExporter:
 			self.mesh_cache[node.data]=meshdata
 			return meshdata
 
-		if (len(node.modifiers) and self.config["use_mesh_modifiers"]):
-			mesh=node.to_mesh(self.scene,True,"RENDER") #is this allright?
-		else:
-			mesh=node.data
+		apply_modifiers = len(node.modifiers) and self.config["use_mesh_modifiers"]
+
+		mesh=node.to_mesh(self.scene,apply_modifiers,"RENDER") #is this allright?
+
+		triangulate=self.config["use_triangles"]
+		if (triangulate):
+			bm = bmesh.new()
+			bm.from_mesh(mesh)
+			bmesh.ops.triangulate(bm, faces=bm.faces)
+			bm.to_mesh(mesh)
+			bm.free()
+
 
 		mesh.update(calc_tessface=True)
 		vertices=[]
@@ -462,20 +479,22 @@ class DaeExporter:
 		has_uv=False
 		has_uv2=False
 		has_weights=armature!=None
-		has_colors=False
+		has_tangents=self.config["use_tangent_arrays"] # could detect..
+		has_colors=len(mesh.vertex_colors)
 		mat_assign=[]
 
 		uv_layer_count=len(mesh.uv_textures)
+		mesh.calc_tangents()
+
 
-		for fi in range(len(mesh.tessfaces)):
-			f=mesh.tessfaces[fi]
+		for fi in range(len(mesh.polygons)):
+			f=mesh.polygons[fi]
 
 			if (not (f.material_index in surface_indices)):
 				surface_indices[f.material_index]=[]
 				print("Type: "+str(type(f.material_index)))
 				print("IDX: "+str(f.material_index)+"/"+str(len(mesh.materials)))
 
-
 				try:
 					#Bizarre blender behavior i don't understand, so catching exception
 					mat = mesh.materials[f.material_index]
@@ -489,35 +508,42 @@ class DaeExporter:
 
 			indices = surface_indices[f.material_index]
 			vi=[]
-			#make triangles always
+			#vertices always 3
+			"""
 			if (len(f.vertices)==3):
 				vi.append(0)
 				vi.append(1)
 				vi.append(2)
 			elif (len(f.vertices)==4):
+				#todo, should use shortest path
 				vi.append(0)
 				vi.append(1)
 				vi.append(2)
 				vi.append(0)
 				vi.append(2)
 				vi.append(3)
+			"""
 
-			for x in vi:
-				mv = mesh.vertices[f.vertices[x]]
+			for lt in range(f.loop_total):
+				loop_index = f.loop_start + lt
+				ml = mesh.loops[loop_index]
+				mv = mesh.vertices[ml.vertex_index]
 
 				v = self.Vertex()
 				v.vertex = Vector( mv.co )
 
-				for xt in mesh.tessface_uv_textures:
-					d = xt.data[fi]
-					uvsrc = [d.uv1,d.uv2,d.uv3,d.uv4]
-					v.uv.append( Vector( uvsrc[x] ) )
+				for xt in mesh.uv_layers:
+					v.uv.append( Vector( xt.data[loop_index].uv ) )
 
+				if (has_colors):
+					v.color = Vector( mesh.vertex_colors[0].data[loop_index].color )
+
+				v.normal = Vector( ml.normal )
+
+				if (has_tangents):
+					v.tangent = Vector( ml.tangent )
+					v.bitangent = Vector( ml.bitangent )
 
-				if (f.use_smooth):
-					v.normal=Vector( mv.normal )
-				else:
-					v.normal=Vector( f.normal )
 
 			       # if (armature):
 			       #         v.vertex = node.matrix_world * v.vertex
@@ -531,6 +557,7 @@ class DaeExporter:
 							continue;
 						name = node.vertex_groups[vg.group].name
 						if (name in si["bone_index"]):
+							#could still put the weight as 0.0001 maybe
 							if (vg.weight>0.001): #blender has a lot of zero weight stuff
 								v.bones.append(si["bone_index"][name])
 								v.weights.append(vg.weight)
@@ -546,7 +573,11 @@ class DaeExporter:
 					vertices.append(v)
 					vertex_map[tup]=idx
 
-				indices.append(idx)
+				vi.append(idx)
+
+			if (len(vi)>2):
+				#only triangles and above
+				indices.append(vi)
 
 
 		meshid = self.new_id("mesh")
@@ -586,6 +617,37 @@ class DaeExporter:
 		self.writel(S_GEOM,4,'</technique_common>')
 		self.writel(S_GEOM,3,'</source>')
 
+		if (has_tangents):
+			self.writel(S_GEOM,3,'<source id="'+meshid+'-tangents">')
+			float_values=""
+			for v in vertices:
+				float_values+=" "+str(v.tangent.x)+" "+str(v.tangent.y)+" "+str(v.tangent.z)
+			self.writel(S_GEOM,4,'<float_array id="'+meshid+'-tangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+			self.writel(S_GEOM,4,'<technique_common>')
+			self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-tangents-array" count="'+str(len(vertices))+'" stride="3">')
+			self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+			self.writel(S_GEOM,4,'</accessor>')
+			self.writel(S_GEOM,4,'</technique_common>')
+			self.writel(S_GEOM,3,'</source>')
+
+			self.writel(S_GEOM,3,'<source id="'+meshid+'-bitangents">')
+			float_values=""
+			for v in vertices:
+				float_values+=" "+str(v.bitangent.x)+" "+str(v.bitangent.y)+" "+str(v.bitangent.z)
+			self.writel(S_GEOM,4,'<float_array id="'+meshid+'-bitangents-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+			self.writel(S_GEOM,4,'<technique_common>')
+			self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-bitangents-array" count="'+str(len(vertices))+'" stride="3">')
+			self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+			self.writel(S_GEOM,4,'</accessor>')
+			self.writel(S_GEOM,4,'</technique_common>')
+			self.writel(S_GEOM,3,'</source>')
+
+
+
 		# UV Arrays
 
 		for uvi in range(uv_layer_count):
@@ -608,36 +670,75 @@ class DaeExporter:
 			self.writel(S_GEOM,4,'</technique_common>')
 			self.writel(S_GEOM,3,'</source>')
 
+		# Color Arrays
+
+		if (has_colors):
+			self.writel(S_GEOM,3,'<source id="'+meshid+'-colors">')
+			float_values=""
+			for v in vertices:
+				float_values+=" "+str(v.color.x)+" "+str(v.color.y)+" "+str(v.color.z)
+			self.writel(S_GEOM,4,'<float_array id="'+meshid+'-colors-array" count="'+str(len(vertices)*3)+'">'+float_values+'</float_array>')
+			self.writel(S_GEOM,4,'<technique_common>')
+			self.writel(S_GEOM,4,'<accessor source="#'+meshid+'-colors-array" count="'+str(len(vertices))+'" stride="3">')
+			self.writel(S_GEOM,5,'<param name="X" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Y" type="float"/>')
+			self.writel(S_GEOM,5,'<param name="Z" type="float"/>')
+			self.writel(S_GEOM,4,'</accessor>')
+			self.writel(S_GEOM,4,'</technique_common>')
+			self.writel(S_GEOM,3,'</source>')
+
 		# Triangle Lists
 		self.writel(S_GEOM,3,'<vertices id="'+meshid+'-vertices">')
 		self.writel(S_GEOM,4,'<input semantic="POSITION" source="#'+meshid+'-positions"/>')
 		self.writel(S_GEOM,3,'</vertices>')
 
+		prim_type=""
+		if (triangulate):
+			prim_type="triangles"
+		else:
+			prim_type="polygons"
+
+
 		for m in surface_indices:
 			indices = surface_indices[m]
 			mat = materials[m]
+
 			if (mat!=None):
 				matref = self.new_id("trimat")
-				self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'" material="'+matref+'">') # todo material
+				self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'" material="'+matref+'">') # todo material
 				mat_assign.append( (mat,matref) )
 			else:
-				self.writel(S_GEOM,3,'<triangles count="'+str(int(len(indices)/3))+'">') # todo material
+				self.writel(S_GEOM,3,'<'+prim_type+' count="'+str(int(len(indices)))+'">') # todo material
+
+
 			self.writel(S_GEOM,4,'<input semantic="VERTEX" source="#'+meshid+'-vertices" offset="0"/>')
-			self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="1"/>')
-			extra_indices=0
+			self.writel(S_GEOM,4,'<input semantic="NORMAL" source="#'+meshid+'-normals" offset="0"/>')
+
 			for uvi in range(uv_layer_count):
-				self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="'+str(2+uvi)+'" set="'+str(uvi)+'"/>')
-				extra_indices+=1
+				self.writel(S_GEOM,4,'<input semantic="TEXCOORD" source="#'+meshid+'-texcoord-'+str(uvi)+'" offset="0" set="'+str(uvi)+'"/>')
+
+			if (has_colors):
+				self.writel(S_GEOM,4,'<input semantic="COLOR" source="#'+meshid+'-colors" offset="0"/>')
+			if (has_tangents):
+				self.writel(S_GEOM,4,'<input semantic="TEXTANGENT" source="#'+meshid+'-tangents" offset="0"/>')
+				self.writel(S_GEOM,4,'<input semantic="TEXBINORMAL" source="#'+meshid+'-bitangents" offset="0"/>')
+
+			if (triangulate):
+				int_values="<p>"
+				for p in indices:
+					for i in p:
+						int_values+=" "+str(i)
+				int_values+=" </p>"
+				self.writel(S_GEOM,4,int_values)
+			else:
+				for p in indices:
+					int_values="<p>"
+					for i in p:
+						int_values+=" "+str(i)
+					int_values+=" </p>"
+					self.writel(S_GEOM,4,int_values)
 
-			int_values="<p>"
-			for i in range(len(indices)):
-				int_values+=" "+str(indices[i]) # vertex index
-				int_values+=" "+str(indices[i]) # normal index
-				for e in range(extra_indices):
-					int_values+=" "+str(indices[i]) # normal index
-			int_values+="</p>"
-			self.writel(S_GEOM,4,int_values)
-			self.writel(S_GEOM,3,'</triangles>')
+			self.writel(S_GEOM,3,'</'+prim_type+'>')
 
 
 		self.writel(S_GEOM,2,'</mesh>')
@@ -1355,6 +1456,8 @@ class DaeExporter:
 			self.writel(S_ANIM_CLIPS,0,'</library_animation_clips>')
 
 			for s in self.skeletons:
+				if (s.animation_data==None):
+					continue
 				if s in cached_actions:
 					s.animation_data.action = bpy.data.actions[cached_actions[s]]
 				else: