Browse Source

-Rasterizer supports meshes with both skeletons and blend shapes
-Collada exporter supports Blend Shapes (even on actions via set driven keys)

Juan Linietsky 11 years ago
parent
commit
01ffe6cf89

+ 36 - 0
core/ustring.cpp

@@ -555,6 +555,42 @@ String String::get_slice(String p_splitter, int p_slice) const {
 
 }
 
+
+Vector<String> String::split_spaces() const {
+
+	Vector<String> ret;
+	int from=0;
+	int i=0;
+	int len = length();
+	bool inside=false;
+
+	while(true) {
+
+		bool empty=operator[](i)<33;
+
+		if (i==0)
+			inside=!empty;
+
+		if (!empty && !inside) {
+			inside=true;
+			from=i;
+		}
+
+		if (empty && inside) {
+
+			ret.push_back(substr(from,i-from));
+			inside=false;
+		}
+
+		if (i==len)
+			break;
+		i++;
+	}
+
+	return ret;
+
+}
+
 Vector<String> String::split(const String &p_splitter,bool p_allow_empty) const {
 
 	Vector<String> ret;

+ 1 - 0
core/ustring.h

@@ -150,6 +150,7 @@ public:
 	String get_slice(String p_splitter,int p_slice) const;
 
 	Vector<String> split(const String &p_splitter,bool p_allow_empty=true) const;
+	Vector<String> split_spaces() const;
 	Vector<float> split_floats(const String &p_splitter,bool p_allow_empty=true) const;
 	Vector<float> split_floats_mk(const Vector<String> &p_splitters,bool p_allow_empty=true) const;
 	Vector<int> split_ints(const String &p_splitter,bool p_allow_empty=true) const;

+ 116 - 22
drivers/gles2/rasterizer_gles2.cpp

@@ -5011,7 +5011,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
 }
 
 
-template<bool USE_NORMAL, bool USE_TANGENT>
+template<bool USE_NORMAL, bool USE_TANGENT,bool INPLACE>
 void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms) {
 
 	uint32_t basesize = 3;
@@ -5021,6 +5021,8 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
 		basesize+=4;
 
 	uint32_t extra=(p_dst_stride-basesize*4);
+	const int dstvec_size=3+(USE_NORMAL?3:0)+(USE_TANGENT?4:0);
+	float dstcopy[dstvec_size];
 
 	for(int i=0;i<p_elements;i++) {
 
@@ -5029,7 +5031,11 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
 		const uint16_t *bi = (const uint16_t*)&p_src_bones[ss];
 		const float *bw = (const float *)&p_src_weights[ss];
 		const float *src_vec=(const float *)&p_src_array[ss];
-		float *dst_vec=(float*)&p_dst_array[ds];
+		float *dst_vec;
+		if (INPLACE)
+			dst_vec=dstcopy;
+		else
+			dst_vec=(float*)&p_dst_array[ds];
 
 		dst_vec[0]=0.0;
 		dst_vec[1]=0.0;
@@ -5082,16 +5088,28 @@ void RasterizerGLES2::_skeleton_xform(const uint8_t * p_src_array, int p_src_str
 
 		end:
 
-		//copy extra stuff
-		const uint8_t *esp =(const uint8_t*) &src_vec[basesize];
-		uint8_t *edp =(uint8_t*) &dst_vec[basesize];
+		if (INPLACE) {
 
+			const uint8_t *esp =(const uint8_t*) dstcopy;
+			uint8_t *edp =(uint8_t*)&p_dst_array[ds];
 
-		for(uint32_t j=0;j<extra;j++) {
 
-			edp[j]=esp[j];
-		}
+			for(uint32_t j=0;j<dstvec_size*4;j++) {
+
+				edp[j]=esp[j];
+			}
+
+		} else {
+			//copy extra stuff
+			const uint8_t *esp =(const uint8_t*) &src_vec[basesize];
+			uint8_t *edp =(uint8_t*) &dst_vec[basesize];
+
 
+			for(uint32_t j=0;j<extra;j++) {
+
+				edp[j]=esp[j];
+			}
+		}
 	}
 }
 
@@ -5166,6 +5184,8 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 					}
 
+					int16_t coeffp = CLAMP(coef*255,0,255);
+
 
 					for(int i=0;i<VS::ARRAY_MAX-1;i++) {
 
@@ -5175,9 +5195,13 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 						int ofs = ad.ofs;
 						int src_stride=surf->stride;
-						int dst_stride=surf->local_stride;
+						int dst_stride=skeleton_valid?surf->stride:surf->local_stride;
 						int count = surf->array_len;
 
+						if (!skeleton_valid && i>=VS::ARRAY_MAX-3)
+							break;
+
+
 						switch(i) {
 
 							case VS::ARRAY_VERTEX:
@@ -5193,7 +5217,21 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 									dst[0]= src[0]*coef;
 									dst[1]= src[1]*coef;
 									dst[2]= src[2]*coef;
-								} break;
+								};
+
+							} break;
+							case VS::ARRAY_COLOR: {
+
+								for(int k=0;k<count;k++) {
+
+									const uint8_t *src = (const uint8_t*)&surf->array_local[ofs+k*src_stride];
+									uint8_t *dst = (uint8_t*)&base[ofs+k*dst_stride];
+
+									dst[0]=	(src[0]*coeffp)>>8;
+									dst[1]=	(src[1]*coeffp)>>8;
+									dst[2]=	(src[2]*coeffp)>>8;
+									dst[3]=	(src[3]*coeffp)>>8;
+								}
 
 							} break;
 							case VS::ARRAY_TEX_UV:
@@ -5206,16 +5244,32 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 									dst[0]= src[0]*coef;
 									dst[1]= src[1]*coef;
-								} break;
+								}
+
+							} break;
+							case VS::ARRAY_BONES:
+							case VS::ARRAY_WEIGHTS: {
+
+								for(int k=0;k<count;k++) {
+
+									const float *src = (const float*)&surf->array_local[ofs+k*src_stride];
+									float *dst = (float*)&base[ofs+k*dst_stride];
+
+									dst[0]= src[0];
+									dst[1]= src[1];
+									dst[2]= src[2];
+									dst[3]= src[3];
+								}
 
 							} break;
+
 						}
 					}
 
 
 					for(int j=0;j<surf->morph_target_count;j++) {
 
-						for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+						for(int i=0;i<VS::ARRAY_MAX-3;i++) {
 
 							const Surface::ArrayData& ad=surf->array[i];
 							if (ad.size==0)
@@ -5223,10 +5277,12 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 
 							int ofs = ad.ofs;
-							int dst_stride=surf->local_stride;
+							int src_stride=surf->local_stride;
+							int dst_stride=skeleton_valid?surf->stride:surf->local_stride;
 							int count = surf->array_len;
 							const uint8_t *morph=surf->morph_targets_local[j].array;
 							float w = p_morphs[j];
+							int16_t wfp = CLAMP(w*255,0,255);
 
 							switch(i) {
 
@@ -5237,13 +5293,26 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 									for(int k=0;k<count;k++) {
 
-										const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
+										const float *src_morph = (const float*)&morph[ofs+k*src_stride];
 										float *dst = (float*)&base[ofs+k*dst_stride];
 
 										dst[0]+= src_morph[0]*w;
 										dst[1]+= src_morph[1]*w;
 										dst[2]+= src_morph[2]*w;
-									} break;
+									}
+
+								} break;
+								case VS::ARRAY_COLOR: {
+									for(int k=0;k<count;k++) {
+
+										const uint8_t *src = (const uint8_t*)&morph[ofs+k*src_stride];
+										uint8_t *dst = (uint8_t*)&base[ofs+k*dst_stride];
+
+										dst[0]=	(src[0]*wfp)>>8;
+										dst[1]=	(src[1]*wfp)>>8;
+										dst[2]=	(src[2]*wfp)>>8;
+										dst[3]=	(src[3]*wfp)>>8;
+									}
 
 								} break;
 								case VS::ARRAY_TEX_UV:
@@ -5251,18 +5320,43 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 
 									for(int k=0;k<count;k++) {
 
-										const float *src_morph = (const float*)&morph[ofs+k*dst_stride];
+										const float *src_morph = (const float*)&morph[ofs+k*src_stride];
 										float *dst = (float*)&base[ofs+k*dst_stride];
 
 										dst[0]+= src_morph[0]*w;
 										dst[1]+= src_morph[1]*w;
-									} break;
+									}
 
 								} break;
 							}
 						}
 					}
 
+
+
+					if (skeleton_valid) {
+
+
+
+						const uint8_t *src_weights=&surf->array_local[surf->array[VS::ARRAY_WEIGHTS].ofs];
+						const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs];
+						const Skeleton::Bone *skeleton = &p_skeleton->bones[0];
+
+
+						if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
+							_skeleton_xform<true,true,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+						else if (surf->format&(VS::ARRAY_FORMAT_NORMAL))
+							_skeleton_xform<true,false,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+						else if (surf->format&(VS::ARRAY_FORMAT_TANGENT))
+							_skeleton_xform<false,true,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+						else
+							_skeleton_xform<false,false,true>(base,surf->stride,base,surf->stride,surf->array_len,src_bones,src_weights,skeleton);
+
+					}
+
+					stride=skeleton_valid?surf->stride:surf->local_stride;
+
+
 #if 0
 					{
 						//in-place skeleton tansformation, only used for morphs, slow.
@@ -5356,14 +5450,14 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
 					const uint8_t *src_bones=&surf->array_local[surf->array[VS::ARRAY_BONES].ofs];
 					const Skeleton::Bone *skeleton = &p_skeleton->bones[0];
 
-						if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
-						_skeleton_xform<true,true>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+					if (surf->format&VS::ARRAY_FORMAT_NORMAL && surf->format&VS::ARRAY_FORMAT_TANGENT)
+						_skeleton_xform<true,true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
 					else if (surf->format&(VS::ARRAY_FORMAT_NORMAL))
-						_skeleton_xform<true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+						_skeleton_xform<true,false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
 					else if (surf->format&(VS::ARRAY_FORMAT_TANGENT))
-						_skeleton_xform<false,true>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+						_skeleton_xform<false,true,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
 					else
-						_skeleton_xform<false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
+						_skeleton_xform<false,false,false>(surf->array_local,surf->stride,base,dst_stride,surf->array_len,src_bones,src_weights,skeleton);
 
 
 					stride=dst_stride;

+ 1 - 1
drivers/gles2/rasterizer_gles2.h

@@ -608,7 +608,7 @@ class RasterizerGLES2 : public Rasterizer {
 	mutable SelfList<Skeleton>::List _skeleton_dirty_list;
 
 
-	template<bool USE_NORMAL, bool USE_TANGENT>
+	template<bool USE_NORMAL, bool USE_TANGENT,bool INPLACE>
 	void _skeleton_xform(const uint8_t * p_src_array, int p_src_stride, uint8_t * p_dst_array, int p_dst_stride, int p_elements,const uint8_t *p_src_bones, const uint8_t *p_src_weights, const Skeleton::Bone *p_bone_xforms);
 
 	struct Light {

+ 3 - 0
platform/windows/detect.py

@@ -64,6 +64,7 @@ def get_flags():
 	return [
 		('freetype','builtin'), #use builtin freetype
 		('openssl','builtin'), #use builtin openssl
+		('theora','no'), #use builtin openssl
 	]
 			
 
@@ -137,6 +138,8 @@ def configure(env):
 		#build using mingw
 		if (os.name=="nt"):
 			env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes
+		else:
+			env["PROGSUFFIX"]=env["PROGSUFFIX"]+".exe"
 
 		mingw_prefix=""
 

+ 6 - 1
tools/collada/collada.cpp

@@ -443,7 +443,10 @@ Vector<String> Collada::_read_string_array(XMLParser& parser) {
 		if (parser.get_node_type() == XMLParser::NODE_TEXT) {
 			// parse String data
 			String str = parser.get_node_data();
-			array=str.split(" ",false);
+			array=str.split_spaces();
+			for(int i=0;i<array.size();i++) {
+				print_line(itos(i)+": "+array[i]);
+			}
 		}
 		else
 		if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
@@ -2066,6 +2069,8 @@ void Collada::_parse_animation(XMLParser& parser) {
 				track.target=target;
 			}
 
+			print_line("TARGET: "+track.target);
+
 			state.animation_tracks.push_back(track);
 
 			if (!state.referenced_tracks.has(target))

+ 15 - 9
tools/collada/collada.h

@@ -302,6 +302,7 @@ public:
 		Vector3 uv2;
 		Plane tangent;
 		Color color;
+		int uid;
 		struct Weight {
 			int bone_idx;
 			float weight;
@@ -331,21 +332,26 @@ public:
 
 		bool operator<(const Vertex& p_vert) const {
 
-			if (vertex==p_vert.vertex) {
-				if(normal==p_vert.normal) {
-					if(uv==p_vert.uv) {
-						if(uv2==p_vert.uv2) {
-							return (color<p_vert.color);
+			if (uid==p_vert.uid) {
+				if (vertex==p_vert.vertex) {
+					if(normal==p_vert.normal) {
+						if(uv==p_vert.uv) {
+							if(uv2==p_vert.uv2) {
+								return (color<p_vert.color);
+							} else
+								return (uv2<p_vert.uv2);
 						} else
-							return (uv2<p_vert.uv2);
+							return (uv<p_vert.uv);
 					} else
-						return (uv<p_vert.uv);
+						return (normal<p_vert.normal);
 				} else
-					return (normal<p_vert.normal);
+					return vertex<p_vert.vertex;
 			} else
-				return vertex<p_vert.vertex;
+				return uid < p_vert.uid;
 
 		}
+
+		Vertex() { uid=0; idx=0; }
 	};
 	struct Node {
 

+ 11 - 0
tools/editor/io_plugins/editor_import_collada.cpp

@@ -694,6 +694,7 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
 		// Must convert to GL/DX format.
 
 		int _prim_ofs=0;
+		int vertidx=0;
 		for(int p_i=0;p_i<p.count;p_i++) {
 
 
@@ -718,6 +719,8 @@ Error ColladaImport::_create_mesh_surfaces(Ref<Mesh>& p_mesh,const Map<String,Co
 				ERR_FAIL_INDEX_V(src,p.indices.size(),ERR_INVALID_DATA);
 
 				Collada::Vertex vertex;
+				if (p_morph_data)
+					vertex.uid=vertidx++;
 
 				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;
@@ -1670,15 +1673,20 @@ void ColladaImport::_fix_param_animation_tracks() {
 						source=skin.base;
 					} else if (collada.state.morph_controller_data_map.has(source)) {
 
+						print_line("has morph");
 						const Collada::MorphControllerData& morph = collada.state.morph_controller_data_map[source];
+
 						if (morph.targets.has("MORPH_WEIGHT") && morph.targets.has("MORPH_TARGET")) {
+							print_line("weight and target");
 
 							String weights = morph.targets["MORPH_WEIGHT"];
 							String targets = morph.targets["MORPH_TARGET"];
+							//fails here
 
 							if (morph.sources.has(targets) && morph.sources.has(weights)) {
 								const Collada::MorphControllerData::Source &weight_src=morph.sources[weights];
 								const Collada::MorphControllerData::Source &target_src=morph.sources[targets];
+								print_line("sources OK");
 
 								ERR_FAIL_COND(weight_src.array.size() != target_src.sarray.size());
 
@@ -1687,6 +1695,8 @@ void ColladaImport::_fix_param_animation_tracks() {
 									String track_name = weights+"("+itos(i)+")";
 									String mesh_name = target_src.sarray[i];
 									if (collada.state.mesh_name_map.has(mesh_name) && collada.state.referenced_tracks.has(track_name)) {
+										print_line("refe tracks");
+
 
 										const Vector<int>&rt = collada.state.referenced_tracks[track_name];
 
@@ -1731,6 +1741,7 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) {
 	for(int i=0;i<collada.state.animation_tracks.size();i++) {
 
 		Collada::AnimationTrack &at = collada.state.animation_tracks[i];
+		print_line("CHANNEL: "+at.target+" PARAM: "+at.param);
 		if (!node_map.has(at.target)) {
 			print_line("Coudlnt find node: "+at.target);
 			continue;

+ 4 - 4
tools/export/blender25/io_scene_dae/__init__.py

@@ -19,14 +19,14 @@
 # <pep8-80 compliant>
 
 bl_info = {
-    "name": "Khronos Collada format",
+    "name": "Better Collada Exporter",
     "author": "Juan Linietsky",
     "blender": (2, 5, 8),
     "api": 38691,
     "location": "File > Import-Export",
-    "description": ("Export DAE Scenes"),
+    "description": ("Export DAE Scenes, This plugin actually works better! otherwise contact me."),
     "warning": "",
-    "wiki_url": ("None"),
+    "wiki_url": ("http://www.godotengine.org"),
     "tracker_url": "",
     "support": 'OFFICIAL',
     "category": "Import-Export"}
@@ -171,7 +171,7 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
 
 
 def menu_func(self, context):
-    self.layout.operator(ExportDAE.bl_idname, text="Khronos Collada (.dae)")
+    self.layout.operator(ExportDAE.bl_idname, text="Better Collada (.dae)")
 
 
 def register():

+ 213 - 63
tools/export/blender25/io_scene_dae/export_dae.py

@@ -123,6 +123,11 @@ 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)
+			#for t in self.bones:
+			#	tup = tup + (t)
+			#for t in self.weights:
+			#	tup = tup + (t)
+
 			return tup
 
 		def __init__(self):
@@ -315,13 +320,127 @@ class DaeExporter:
 		return matid
 
 
-	def export_mesh(self,node,armature=None,shapename=None):
+	def export_mesh(self,node,armature=None,skeyindex=-1,skel_source=None):
 
 		mesh = node.data
-		if (node.data in self.mesh_cache) and shapename==None:
+
+
+		if (node.data in self.mesh_cache):
 			return self.mesh_cache[mesh]
 
-		if (len(node.modifiers) and self.config["use_mesh_modifiers"]) or shapename!=None:
+		if (skeyindex==-1 and mesh.shape_keys!=None and len(mesh.shape_keys.key_blocks)):
+			values=[]
+			morph_targets=[]
+			md=None
+			for k in range(0,len(mesh.shape_keys.key_blocks)):
+			    shape = node.data.shape_keys.key_blocks[k]
+			    values+=[shape.value] #save value
+			    shape.value=0
+
+			mid = self.new_id("morph")
+
+			for k in range(0,len(mesh.shape_keys.key_blocks)):
+
+				shape = node.data.shape_keys.key_blocks[k]
+				node.show_only_shape_key=True
+				node.active_shape_key_index = k
+				shape.value = 1.0
+				mesh.update()
+				"""
+				oldval = shape.value
+				shape.value = 1.0
+
+				"""
+				p = node.data
+				v = node.to_mesh(bpy.context.scene, True, "RENDER")
+				node.data = v
+#				self.export_node(node,il,shape.name)
+				node.data.update()
+				if (armature and k==0):
+					md=self.export_mesh(node,armature,k,mid)
+				else:
+					md=self.export_mesh(node,None,k)
+
+				node.data = p
+				node.data.update()
+				shape.value = 0.0
+				morph_targets.append(md)
+
+				"""
+				shape.value = oldval
+				"""
+			node.show_only_shape_key=False
+			node.active_shape_key_index = 0
+
+
+			self.writel(S_CONT,1,'<controller id="'+mid+'" name="">')
+			#if ("skin_id" in morph_targets[0]):
+			#	self.writel(S_CONT,2,'<morph source="#'+morph_targets[0]["skin_id"]+'" method="NORMALIZED">')
+			#else:
+			self.writel(S_CONT,2,'<morph source="#'+morph_targets[0]["id"]+'" method="NORMALIZED">')
+
+			self.writel(S_CONT,3,'<source id="'+mid+'-morph-targets">')
+			self.writel(S_CONT,4,'<IDREF_array id="'+mid+'-morph-targets-array" count="'+str(len(morph_targets)-1)+'">')
+			marr=""
+			warr=""
+			for i in range(len(morph_targets)):
+				if (i==0):
+				    continue
+				elif (i>1):
+					marr+=" "
+
+				if ("skin_id" in morph_targets[i]):
+					marr+=morph_targets[i]["skin_id"]
+				else:
+					marr+=morph_targets[i]["id"]
+
+				warr+=" 0"
+
+			self.writel(S_CONT,5,marr)
+			self.writel(S_CONT,4,'</IDREF_array>')
+			self.writel(S_CONT,4,'<technique_common>')
+			self.writel(S_CONT,5,'<accessor source="#'+mid+'-morph-targets-array" count="'+str(len(morph_targets)-1)+'" stride="1">')
+			self.writel(S_CONT,6,'<param name="MORPH_TARGET" type="IDREF"/>')
+			self.writel(S_CONT,5,'</accessor>')
+			self.writel(S_CONT,4,'</technique_common>')
+			self.writel(S_CONT,3,'</source>')
+
+			self.writel(S_CONT,3,'<source id="'+mid+'-morph-weights">')
+			self.writel(S_CONT,4,'<float_array id="'+mid+'-morph-weights-array" count="'+str(len(morph_targets)-1)+'" >')
+			self.writel(S_CONT,5,warr)
+			self.writel(S_CONT,4,'</float_array>')
+			self.writel(S_CONT,4,'<technique_common>')
+			self.writel(S_CONT,5,'<accessor source="#'+mid+'-morph-weights-array" count="'+str(len(morph_targets)-1)+'" stride="1">')
+			self.writel(S_CONT,6,'<param name="MORPH_WEIGHT" type="float"/>')
+			self.writel(S_CONT,5,'</accessor>')
+			self.writel(S_CONT,4,'</technique_common>')
+			self.writel(S_CONT,3,'</source>')
+
+			self.writel(S_CONT,3,'<targets>')
+			self.writel(S_CONT,4,'<input semantic="MORPH_TARGET" source="#'+mid+'-morph-targets"/>')
+			self.writel(S_CONT,4,'<input semantic="MORPH_WEIGHT" source="#'+mid+'-morph-weights"/>')
+			self.writel(S_CONT,3,'</targets>')
+			self.writel(S_CONT,2,'</morph>')
+			self.writel(S_CONT,1,'</controller>')
+			if (armature!=None):
+
+				self.armature_for_morph[node]=armature
+
+			meshdata={}
+			if (armature):
+				meshdata = morph_targets[0]
+				meshdata["morph_id"]=mid
+			else:
+				meshdata["id"]=morph_targets[0]["id"]
+				meshdata["morph_id"]=mid
+				meshdata["material_assign"]=morph_targets[0]["material_assign"]
+
+
+
+			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
@@ -349,7 +468,6 @@ class DaeExporter:
 		for fi in range(len(mesh.tessfaces)):
 			f=mesh.tessfaces[fi]
 
-
 			if (not (f.material_index in surface_indices)):
 				surface_indices[f.material_index]=[]
 				print("Type: "+str(type(f.material_index)))
@@ -419,7 +537,7 @@ class DaeExporter:
 
 				tup = v.get_tup()
 				idx = 0
-				if (tup in vertex_map):
+				if (skeyindex==-1 and tup in vertex_map): #do not optmize if using shapekeys
 					idx = vertex_map[tup]
 				else:
 					idx = len(vertices)
@@ -428,12 +546,9 @@ class DaeExporter:
 
 				indices.append(idx)
 
-		if shapename != None:
-			meshid = self.new_id("mesh_"+shapename)
-			self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'_'+shapename+'">')
-		else:
-			meshid = self.new_id("mesh")
-			self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'">')
+
+		meshid = self.new_id("mesh")
+		self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'">')
 
 		self.writel(S_GEOM,2,'<mesh>')
 
@@ -526,20 +641,26 @@ class DaeExporter:
 		self.writel(S_GEOM,2,'</mesh>')
 		self.writel(S_GEOM,1,'</geometry>')
 
+
 		meshdata={}
 		meshdata["id"]=meshid
 		meshdata["material_assign"]=mat_assign
-		self.mesh_cache[node.data]=meshdata
+		if (skeyindex==-1):
+			self.mesh_cache[node.data]=meshdata
 
 
 		# Export armature data (if armature exists)
 
-		if (armature!=None):
+		if (armature!=None and (skel_source!=None or skeyindex==-1)):
 
 			contid = self.new_id("controller")
 
 			self.writel(S_CONT,1,'<controller id="'+contid+'">')
-			self.writel(S_CONT,2,'<skin source="'+meshid+'">')
+			if (skel_source!=None):
+				self.writel(S_CONT,2,'<skin source="'+skel_source+'">')
+			else:
+				self.writel(S_CONT,2,'<skin source="'+meshid+'">')
+
 			self.writel(S_CONT,3,'<bind_shape_matrix>'+strmtx(node.matrix_world)+'</bind_shape_matrix>')
 			#Joint Names
 			self.writel(S_CONT,3,'<source id="'+contid+'-joints">')
@@ -614,7 +735,7 @@ class DaeExporter:
 		return meshdata
 
 
-	def export_mesh_node(self,node,il,shapename=None):
+	def export_mesh_node(self,node,il):
 
 		if (node.data==None):
 			return
@@ -624,14 +745,19 @@ class DaeExporter:
 			if (node.parent.type=="ARMATURE"):
 				armature=node.parent
 
-		meshdata = self.export_mesh(node,armature,shapename)
+		meshdata = self.export_mesh(node,armature)
+		close_controller=False
 
-		if (armature==None):
-			self.writel(S_NODES,il,'<instance_geometry url="#'+meshdata["id"]+'">')
-		else:
+		if ("skin_id" in meshdata):
+			close_controller=True
 			self.writel(S_NODES,il,'<instance_controller url="#'+meshdata["skin_id"]+'">')
 			for sn in self.skeleton_info[armature]["skeleton_nodes"]:
 				self.writel(S_NODES,il+1,'<skeleton>#'+sn+'</skeleton>')
+		elif ("morph_id" in meshdata):
+			self.writel(S_NODES,il,'<instance_controller url="#'+meshdata["morph_id"]+'">')
+			close_controller=True
+		elif (armature==None):
+			self.writel(S_NODES,il,'<instance_geometry url="#'+meshdata["id"]+'">')		
 
 
 		if (len(meshdata["material_assign"])>0):
@@ -644,17 +770,17 @@ class DaeExporter:
 			self.writel(S_NODES,il+2,'</technique_common>')
 			self.writel(S_NODES,il+1,'</bind_material>')
 
-		if (armature==None):
-			self.writel(S_NODES,il,'</instance_geometry>')
-		else:
+		if (close_controller):
 			self.writel(S_NODES,il,'</instance_controller>')
+		else:
+			self.writel(S_NODES,il,'</instance_geometry>')
 
 
 	def export_armature_bone(self,bone,il,si):
 		boneid = self.new_id("bone")
 		boneidx = si["bone_count"]
 		si["bone_count"]+=1
-		bonesid = si["name"]+"-"+str(boneidx)
+		bonesid = si["id"]+"-"+str(boneidx)
 		si["bone_index"][bone.name]=boneidx
 		si["bone_ids"][bone]=boneid
 		si["bone_names"].append(bonesid)
@@ -683,7 +809,7 @@ class DaeExporter:
 		self.skeletons.append(node)
 
 		armature = node.data
-		self.skeleton_info[node]={ "bone_count":0, "name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world }
+		self.skeleton_info[node]={ "bone_count":0, "id":self.new_id("skelbones"),"name":node.name, "bone_index":{},"bone_ids":{},"bone_names":[],"bone_bind_poses":[],"skeleton_nodes":[],"armature_xform":node.matrix_world }
 
 
 
@@ -912,21 +1038,18 @@ class DaeExporter:
 
 
 
-	def export_node(self,node,il,shapename=None):
+	def export_node(self,node,il):
 		if (not self.is_node_valid(node)):
 			return
 		bpy.context.scene.objects.active = node
 
-		if shapename != None:
-			self.writel(S_NODES,il,'<node id="'+self.validate_id(node.name + '_' + shapename)+'" name="'+node.name+'_'+shapename+'" type="NODE">')
-		else:
-			self.writel(S_NODES,il,'<node id="'+self.validate_id(node.name)+'" name="'+node.name+'" type="NODE">')
+		self.writel(S_NODES,il,'<node id="'+self.validate_id(node.name)+'" name="'+node.name+'" type="NODE">')
 		il+=1
 
 		self.writel(S_NODES,il,'<matrix sid="transform">'+strmtx(node.matrix_local)+'</matrix>')
 		print("NODE TYPE: "+node.type+" NAME: "+node.name)
 		if (node.type=="MESH"):
-			self.export_mesh_node(node,il,shapename)
+			self.export_mesh_node(node,il)
 		elif (node.type=="CURVE"):
 			self.export_curve_node(node,il)
 		elif (node.type=="ARMATURE"):
@@ -937,22 +1060,9 @@ class DaeExporter:
 			self.export_lamp_node(node,il)
 
 		self.valid_nodes.append(node)
-		if shapename==None:
-			for x in node.children:
-				self.export_node(x,il)
-			if node.type=="MESH" and self.config["export_shapekeys"]:
-				for k in range(0,len(node.data.shape_keys.key_blocks)):
-					shape = node.data.shape_keys.key_blocks[k]
-					oldval = shape.value
-					shape.value = 1.0
-					node.active_shape_key_index = k
-					p = node.data
-					v = node.to_mesh(bpy.context.scene, True, "RENDER")
-					node.data = v
-					self.export_node(node,il,shape.name)
-					node.data = p
-					node.data.update()
-					shape.value = oldval
+		for x in node.children:
+			self.export_node(x,il)
+
 		il-=1
 		self.writel(S_NODES,il,'</node>')
 
@@ -1003,18 +1113,22 @@ class DaeExporter:
 		self.writel(S_ASSET,0,'</asset>')
 
 
-	def export_animation_transform_channel(self,target,transform_keys):
+	def export_animation_transform_channel(self,target,keys,matrices=True):
 
-		frame_total=len(transform_keys)
+		frame_total=len(keys)
 		anim_id=self.new_id("anim")
 		self.writel(S_ANIM,1,'<animation id="'+anim_id+'">')
 		source_frames = ""
 		source_transforms = ""
 		source_interps = ""
 
-		for k in transform_keys:
+		for k in keys:
 			source_frames += " "+str(k[0])
-			source_transforms += " "+strmtx(k[1])
+			if (matrices):
+				source_transforms += " "+strmtx(k[1])
+			else:
+				source_transforms += " "+str(k[1])
+
 			source_interps +=" LINEAR"
 
 
@@ -1028,15 +1142,26 @@ class DaeExporter:
 		self.writel(S_ANIM,3,'</technique_common>')
 		self.writel(S_ANIM,2,'</source>')
 
-		# Transform Source
-		self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
-		self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total*16)+'">'+source_transforms+'</float_array>')
-		self.writel(S_ANIM,3,'<technique_common>')
-		self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="16">')
-		self.writel(S_ANIM,5,'<param name="TRANSFORM" type="float4x4"/>')
-		self.writel(S_ANIM,4,'</accessor>')
-		self.writel(S_ANIM,3,'</technique_common>')
-		self.writel(S_ANIM,2,'</source>')
+		if (matrices):
+			# Transform Source
+			self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
+			self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total*16)+'">'+source_transforms+'</float_array>')
+			self.writel(S_ANIM,3,'<technique_common>')
+			self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="16">')
+			self.writel(S_ANIM,5,'<param name="TRANSFORM" type="float4x4"/>')
+			self.writel(S_ANIM,4,'</accessor>')
+			self.writel(S_ANIM,3,'</technique_common>')
+			self.writel(S_ANIM,2,'</source>')
+		else:
+			# Value Source
+			self.writel(S_ANIM,2,'<source id="'+anim_id+'-transform-output">')
+			self.writel(S_ANIM,3,'<float_array id="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'">'+source_transforms+'</float_array>')
+			self.writel(S_ANIM,3,'<technique_common>')
+			self.writel(S_ANIM,4,'<accessor source="'+anim_id+'-transform-output-array" count="'+str(frame_total)+'" stride="1">')
+			self.writel(S_ANIM,5,'<param name="X" type="float"/>')
+			self.writel(S_ANIM,4,'</accessor>')
+			self.writel(S_ANIM,3,'</technique_common>')
+			self.writel(S_ANIM,2,'</source>')
 
 		# Interpolation Source
 		self.writel(S_ANIM,2,'<source id="'+anim_id+'-interpolation-output">')
@@ -1053,7 +1178,10 @@ class DaeExporter:
 		self.writel(S_ANIM,3,'<input semantic="OUTPUT" source="#'+anim_id+'-transform-output"/>')
 		self.writel(S_ANIM,3,'<input semantic="INTERPOLATION" source="#'+anim_id+'-interpolation-output"/>')
 		self.writel(S_ANIM,2,'</sampler>')
-		self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'/transform"/>')
+		if (matrices):
+			self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'/transform"/>')
+		else:
+			self.writel(S_ANIM,2,'<channel source="#'+anim_id+'-sampler" target="'+target+'"/>')
 		self.writel(S_ANIM,1,'</animation>')
 
 		return [anim_id]
@@ -1075,6 +1203,7 @@ class DaeExporter:
 
 		tcn = []
 		xform_cache={}
+		blend_cache={}
 		# Change frames first, export objects last
 		# This improves performance enormously
 
@@ -1089,9 +1218,26 @@ class DaeExporter:
 				if (not node in self.valid_nodes):
 					continue
 				if (allowed!=None and not (node in allowed)):
-					continue
+					if (node.type=="MESH" and node.data!=None and (node in self.armature_for_morph) and (self.armature_for_morph[node] in allowed)):
+						pass #all good you pass with flying colors for morphs inside of action
+					else:
+						continue
+				if (node.type=="MESH" and node.data!=None and node.data.shape_keys!=None and (node.data in self.mesh_cache) and len(node.data.shape_keys.key_blocks)):
+					target = self.mesh_cache[node.data]["morph_id"]
+					for i in range(len(node.data.shape_keys.key_blocks)):
+
+						if (i==0):
+							continue
+
+						name=target+"-morph-weights("+str(i-1)+")"
+						if (not (name in blend_cache)):
+							blend_cache[name]=[]
+
+						blend_cache[name].append( (key,node.data.shape_keys.key_blocks[i].value) )
+
 
 				if (node.type=="MESH" and node.parent and node.parent.type=="ARMATURE"):
+
 					continue #In Collada, nodes that have skin modifier must not export animation, animate the skin instead.
 
 				if (len(node.constraints)>0 or node.animation_data!=None):
@@ -1108,6 +1254,7 @@ class DaeExporter:
 
 				if (node.type=="ARMATURE"):
 					#All bones exported for now
+
 					for bone in node.data.bones:
 
 						bone_name=self.skeleton_info[node]["bone_ids"][bone]
@@ -1138,7 +1285,9 @@ class DaeExporter:
 
 		#export animation xml
 		for nid in xform_cache:
-			tcn+=self.export_animation_transform_channel(nid,xform_cache[nid])
+			tcn+=self.export_animation_transform_channel(nid,xform_cache[nid],True)
+		for nid in blend_cache:
+			tcn+=self.export_animation_transform_channel(nid,blend_cache[nid],False)
 
 		return tcn
 
@@ -1197,7 +1346,7 @@ class DaeExporter:
 				print("Export anim: "+x.name)
 				self.writel(S_ANIM_CLIPS,1,'<animation_clip name="'+x.name+'" start="'+str(start)+'" end="'+str(end)+'">')
 				for z in tcn:
-					self.writel(S_ANIM_CLIPS,2,'<instance_animation url="#'+z+'">')
+					self.writel(S_ANIM_CLIPS,2,'<instance_animation url="#'+z+'"/>')
 				self.writel(S_ANIM_CLIPS,1,'</animation_clip>')
 
 
@@ -1276,6 +1425,7 @@ class DaeExporter:
 		self.skeleton_info={}
 		self.config=kwargs
 		self.valid_nodes=[]
+		self.armature_for_morph={}