Răsfoiți Sursa

Blend shapes using transform feedback (GPU)

Juan Linietsky 8 ani în urmă
părinte
comite
a732708b9d

+ 10 - 1
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1111,7 +1111,16 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
 		case VS::INSTANCE_MESH: {
 
 			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
-			glBindVertexArray(s->array_id); // everything is so easy nowadays
+
+			if (s->morph_targets.size() && e->instance->morph_values.size()) {
+				//blend shapes, use transform feedback
+				storage->mesh_render_blend_shapes(s,e->instance->morph_values.ptr());
+				//rebind shader
+				state.scene_shader.bind();
+			} else {
+
+				glBindVertexArray(s->array_id); // everything is so easy nowadays
+			}
 
 		} break;
 

+ 307 - 94
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -2274,8 +2274,8 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
 			material->can_cast_shadow_cache=can_cast_shadow;
 			material->is_animated_cache=is_animated;
 
-			for(Map<Instantiable*,int>::Element *E=material->instantiable_owners.front();E;E=E->next()) {
-				E->key()->instance_material_change_notify();
+			for(Map<Geometry*,int>::Element *E=material->geometry_owners.front();E;E=E->next()) {
+				E->key()->material_changed_notify();
 			}
 
 			for(Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.front();E;E=E->next()) {
@@ -2379,32 +2379,32 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
 
 }
 
-void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) {
+void RasterizerStorageGLES3::_material_add_geometry(RID p_material,Geometry *p_geometry) {
 
 	Material * material = material_owner.getornull(p_material);
 	ERR_FAIL_COND(!material);
 
-	Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+	Map<Geometry*,int>::Element *I = material->geometry_owners.find(p_geometry);
 
 	if (I) {
 		I->get()++;
 	} else {
-		material->instantiable_owners[p_instantiable]=1;
+		material->geometry_owners[p_geometry]=1;
 	}
 
 }
 
-void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) {
+void RasterizerStorageGLES3::_material_remove_geometry(RID p_material,Geometry *p_geometry) {
 
 	Material * material = material_owner.getornull(p_material);
 	ERR_FAIL_COND(!material);
 
-	Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+	Map<Geometry*,int>::Element *I = material->geometry_owners.find(p_geometry);
 	ERR_FAIL_COND(!I);
 
 	I->get()--;
 	if (I->get()==0) {
-		material->instantiable_owners.erase(I);
+		material->geometry_owners.erase(I);
 	}
 }
 
@@ -2446,18 +2446,15 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 	bool has_morph = p_blend_shapes.size();
 
-	Surface::Attrib attribs[VS::ARRAY_MAX],morph_attribs[VS::ARRAY_MAX];
+	Surface::Attrib attribs[VS::ARRAY_MAX];
 
 	int stride=0;
-	int morph_stride=0;
 
 	for(int i=0;i<VS::ARRAY_MAX;i++) {
 
 		if (! (p_format&(1<<i) ) ) {
 			attribs[i].enabled=false;
-			morph_attribs[i].enabled=false;
 			attribs[i].integer=false;
-			morph_attribs[i].integer=false;
 			continue;
 		}
 
@@ -2466,14 +2463,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 		attribs[i].index=i;
 		attribs[i].integer=false;
 
-		if (has_morph) {
-			morph_attribs[i].enabled=true;
-			morph_attribs[i].offset=morph_stride;
-			morph_attribs[i].index=i+8;
-		} else {
-			morph_attribs[i].enabled=false;
-		}
-
 		switch(i) {
 
 			case VS::ARRAY_VERTEX: {
@@ -2494,13 +2483,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 				attribs[i].normalized=GL_FALSE;
 
-				if (has_morph) {
-					//morph
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=attribs[i].size*4;
-				}
 			} break;
 			case VS::ARRAY_NORMAL: {
 
@@ -2516,13 +2498,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 					attribs[i].normalized=GL_FALSE;
 				}
 
-				if (has_morph) {
-					//morph
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=12;
-				}
+
 
 			} break;
 			case VS::ARRAY_TANGENT: {
@@ -2539,12 +2515,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 					attribs[i].normalized=GL_FALSE;
 				}
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=16;
-				}
 
 			} break;
 			case VS::ARRAY_COLOR: {
@@ -2561,12 +2531,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 					attribs[i].normalized=GL_FALSE;
 				}
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=16;
-				}
 
 			} break;
 			case VS::ARRAY_TEX_UV: {
@@ -2583,12 +2547,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 				attribs[i].normalized=GL_FALSE;
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=8;
-				}
 
 			} break;
 			case VS::ARRAY_TEX_UV2: {
@@ -2604,12 +2562,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 				}
 				attribs[i].normalized=GL_FALSE;
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=8;
-				}
+
 
 			} break;
 			case VS::ARRAY_BONES: {
@@ -2627,12 +2580,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 				attribs[i].normalized=GL_FALSE;
 				attribs[i].integer=true;
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_UNSIGNED_SHORT;
-					morph_stride+=8;
-				}
+
 
 			} break;
 			case VS::ARRAY_WEIGHTS: {
@@ -2650,12 +2598,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 					attribs[i].normalized=GL_FALSE;
 				}
 
-				if (has_morph) {
-					morph_attribs[i].normalized=GL_FALSE;
-					morph_attribs[i].size=attribs[i].size;
-					morph_attribs[i].type=GL_FLOAT;
-					morph_stride+=8;
-				}
 			} break;
 			case VS::ARRAY_INDEX: {
 
@@ -2678,9 +2620,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 	for(int i=0;i<VS::ARRAY_MAX-1;i++) {
 		attribs[i].stride=stride;
-		if (has_morph) {
-			morph_attribs[i].stride=morph_stride;
-		}
 	}
 
 	//validate sizes
@@ -2731,7 +2670,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 	for(int i=0;i<VS::ARRAY_MAX;i++) {
 		surface->attribs[i]=attribs[i];
-		surface->morph_attribs[i]=morph_attribs[i];
 	}
 
 	{
@@ -2763,12 +2701,11 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 				glGenVertexArrays(1,&surface->array_id);
 				glBindVertexArray(surface->array_id);
 				glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
-			} else {
+			} else if (i==1) {
 				//for instancing draw (can be changed and no one cares)
 				glGenVertexArrays(1,&surface->instancing_array_id);
 				glBindVertexArray(surface->instancing_array_id);
 				glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
-
 			}
 
 
@@ -2816,17 +2753,17 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 			glBindVertexArray(mt.array_id);
 			glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id);
 
-			for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+			for(int j=0;j<VS::ARRAY_MAX-1;j++) {
 
-				if (!attribs[i].enabled)
+				if (!attribs[j].enabled)
 					continue;
 
-				if (attribs[i].integer) {
-					glVertexAttribIPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+				if (attribs[j].integer) {
+					glVertexAttribIPointer(attribs[j].index,attribs[j].size,attribs[j].type,attribs[j].stride,((uint8_t*)0)+attribs[j].offset);
 				} else {
-					glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+					glVertexAttribPointer(attribs[j].index,attribs[j].size,attribs[j].type,attribs[j].normalized,attribs[j].stride,((uint8_t*)0)+attribs[j].offset);
 				}
-				glEnableVertexAttribArray(attribs[i].index);
+				glEnableVertexAttribArray(attribs[j].index);
 
 			}
 
@@ -2889,13 +2826,13 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface
 		return;
 
 	if (mesh->surfaces[p_surface]->material.is_valid()) {
-		_material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh);
+		_material_remove_geometry(mesh->surfaces[p_surface]->material,mesh->surfaces[p_surface]);
 	}
 
 	mesh->surfaces[p_surface]->material=p_material;
 
 	if (mesh->surfaces[p_surface]->material.is_valid()) {
-		_material_add_instantiable(mesh->surfaces[p_surface]->material,mesh);
+		_material_add_geometry(mesh->surfaces[p_surface]->material,mesh->surfaces[p_surface]);
 	}
 
 	mesh->instance_material_change_notify();
@@ -3067,7 +3004,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
 	Surface *surface = mesh->surfaces[p_surface];
 
 	if (surface->material.is_valid()) {
-		_material_remove_instantiable(surface->material,mesh);
+		_material_remove_geometry(surface->material,mesh->surfaces[p_surface]);
 	}
 
 	glDeleteBuffers(1,&surface->vertex_id);
@@ -3241,6 +3178,227 @@ void RasterizerStorageGLES3::mesh_clear(RID p_mesh){
 	}
 }
 
+void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, float *p_weights) {
+
+	glBindVertexArray(s->array_id);
+
+	BlendShapeShaderGLES3::Conditionals cond[VS::ARRAY_MAX-1]={
+		BlendShapeShaderGLES3::ENABLE_NORMAL, //will be ignored
+		BlendShapeShaderGLES3::ENABLE_NORMAL,
+		BlendShapeShaderGLES3::ENABLE_TANGENT,
+		BlendShapeShaderGLES3::ENABLE_COLOR,
+		BlendShapeShaderGLES3::ENABLE_UV,
+		BlendShapeShaderGLES3::ENABLE_UV2,
+		BlendShapeShaderGLES3::ENABLE_SKELETON,
+		BlendShapeShaderGLES3::ENABLE_SKELETON,
+	};
+
+	int stride=0;
+
+	if (s->format&VS::ARRAY_FLAG_USE_2D_VERTICES) {
+		stride=2*4;
+	} else {
+		stride=3*4;
+	}
+
+	static const int sizes[VS::ARRAY_MAX-1]={
+		3*4,
+		3*4,
+		4*4,
+		4*4,
+		2*4,
+		2*4,
+		4*4,
+		4*4
+	};
+
+	for(int i=1;i<VS::ARRAY_MAX-1;i++) {
+		shaders.blend_shapes.set_conditional(cond[i],s->format&(1<<i)); //enable conditional for format
+		if (s->format&(1<<i)) {
+			stride+=sizes[i];
+		}
+	}
+
+
+	//copy all first
+	float base_weight=1.0;
+
+	int mtc = s->morph_targets.size();
+
+	if (s->mesh->morph_target_mode==VS::MORPH_MODE_NORMALIZED) {
+
+		for(int i=0;i<mtc;i++) {
+			base_weight-=p_weights[i];
+		}
+	}
+
+
+
+	shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::ENABLE_BLEND,false); //first pass does not blend
+	shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::USE_2D_VERTEX,s->format&VS::ARRAY_FLAG_USE_2D_VERTICES); //use 2D vertices if needed
+
+	shaders.blend_shapes.bind();
+
+	shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT,base_weight);
+	glEnable(GL_RASTERIZER_DISCARD);
+
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[0]);
+	glBeginTransformFeedback(GL_POINTS);
+	glDrawArrays(GL_POINTS,0,s->array_len);
+	glEndTransformFeedback();
+
+
+	shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::ENABLE_BLEND,true); //first pass does not blend
+	shaders.blend_shapes.bind();
+
+	for(int ti=0;ti<mtc;ti++) {
+		float weight = p_weights[ti];
+
+		if (weight<0.001) //not bother with this one
+			continue;
+
+		glBindVertexArray(s->morph_targets[ti].array_id);
+		glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]);
+		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[1]);
+
+		shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT,weight);
+
+		int ofs=0;
+		for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+			if (s->format&(1<<i)) {
+				glEnableVertexAttribArray(i+8);
+				switch(i) {
+
+					case VS::ARRAY_VERTEX: {
+						if (s->format&VS::ARRAY_FLAG_USE_2D_VERTICES) {
+							glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+							ofs+=2*4;
+						} else {
+							glVertexAttribPointer(i+8,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+							ofs+=3*4;
+						}
+					} break;
+					case VS::ARRAY_NORMAL: {
+						glVertexAttribPointer(i+8,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=3*4;
+					} break;
+					case VS::ARRAY_TANGENT: {
+						glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=4*4;
+
+					} break;
+					case VS::ARRAY_COLOR: {
+						glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=4*4;
+
+					} break;
+					case VS::ARRAY_TEX_UV: {
+						glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=2*4;
+
+					} break;
+					case VS::ARRAY_TEX_UV2: {
+						glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=2*4;
+
+					} break;
+					case VS::ARRAY_BONES: {
+						glVertexAttribIPointer(i+8,4,GL_UNSIGNED_INT,stride,((uint8_t*)0)+ofs);
+						ofs+=4*4;
+
+					} break;
+					case VS::ARRAY_WEIGHTS: {
+						glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=4*4;
+
+					} break;
+				}
+
+			} else {
+				glDisableVertexAttribArray(i+8);
+			}
+		}
+
+		glBeginTransformFeedback(GL_POINTS);
+		glDrawArrays(GL_POINTS,0,s->array_len);
+		glEndTransformFeedback();
+
+
+		SWAP(resources.transform_feedback_buffers[0],resources.transform_feedback_buffers[1]);
+
+	}
+
+	glDisable(GL_RASTERIZER_DISCARD);
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+
+
+	glBindVertexArray(resources.transform_feedback_array);
+	glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]);
+
+	int ofs=0;
+	for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+		if (s->format&(1<<i)) {
+			glEnableVertexAttribArray(i);
+			switch(i) {
+
+				case VS::ARRAY_VERTEX: {
+					if (s->format&VS::ARRAY_FLAG_USE_2D_VERTICES) {
+						glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=2*4;
+					} else {
+						glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+						ofs+=3*4;
+					}
+				} break;
+				case VS::ARRAY_NORMAL: {
+					glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=3*4;
+				} break;
+				case VS::ARRAY_TANGENT: {
+					glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=4*4;
+
+				} break;
+				case VS::ARRAY_COLOR: {
+					glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=4*4;
+
+				} break;
+				case VS::ARRAY_TEX_UV: {
+					glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=2*4;
+
+				} break;
+				case VS::ARRAY_TEX_UV2: {
+					glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=2*4;
+
+				} break;
+				case VS::ARRAY_BONES: {
+					glVertexAttribIPointer(i,4,GL_UNSIGNED_INT,stride,((uint8_t*)0)+ofs);
+					ofs+=4*4;
+
+				} break;
+				case VS::ARRAY_WEIGHTS: {
+					glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs);
+					ofs+=4*4;
+
+				} break;
+			}
+
+		} else {
+			glDisableVertexAttribArray(i);
+		}
+	}
+
+	if (s->index_array_len) {
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id);
+	}
+
+}
+
 /* MULTIMESH API */
 
 
@@ -3896,7 +4054,6 @@ void RasterizerStorageGLES3::skeleton_allocate(RID p_skeleton,int p_bones,bool p
 		skeleton_update_list.add(&skeleton->update_list);
 	}
 
-	skeleton->instance_change_notify();
 
 
 }
@@ -4017,7 +4174,10 @@ void RasterizerStorageGLES3::update_dirty_skeletons() {
 			glBufferSubData(GL_UNIFORM_BUFFER,0,skeleton->bones.size()*sizeof(float),skeleton->bones.ptr());
 			glBindBuffer(GL_UNIFORM_BUFFER, 0);
 		}
-		skeleton->instance_change_notify();
+
+		for (Set<RasterizerScene::InstanceBase*>::Element *E=skeleton->instances.front();E;E=E->next()) {
+			E->get()->base_changed();
+		}
 
 		skeleton_update_list.remove(skeleton_update_list.first());
 	}
@@ -4505,6 +4665,23 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color
 
 }
 
+void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
+
+	Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+
+	skeleton->instances.insert(p_instance);
+}
+
+void RasterizerStorageGLES3::instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
+
+	Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+	ERR_FAIL_COND(!skeleton);
+
+	skeleton->instances.erase(p_instance);
+}
+
+
 void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance) {
 
 	Instantiable *inst=NULL;
@@ -4530,9 +4707,6 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene:
 			ERR_FAIL_COND(!inst);
 		} break;
 		default: {
-			if (skeleton_owner.owns(p_base)) {
-				inst=skeleton_owner.getornull(p_base);
-			}
 			if (!inst) {
 				ERR_FAIL();
 			}
@@ -4550,7 +4724,6 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
 		case VS::INSTANCE_MESH: {
 			inst = mesh_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
-
 		} break;
 		case VS::INSTANCE_MULTIMESH: {
 			inst = multimesh_owner.getornull(p_base);
@@ -4569,9 +4742,7 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
 			ERR_FAIL_COND(!inst);
 		} break;
 		default: {
-			if (skeleton_owner.owns(p_base)) {
-				inst=skeleton_owner.getornull(p_base);
-			}
+
 			if (!inst) {
 				ERR_FAIL();
 			}
@@ -5134,6 +5305,26 @@ bool RasterizerStorageGLES3::free(RID p_rid){
 			glDeleteBuffers(1,&material->ubo_id);
 		}
 
+		//remove from owners
+		for (Map<Geometry*,int>::Element *E=material->geometry_owners.front();E;E=E->next()) {
+
+			Geometry *g = E->key();
+			g->material=RID();
+		}
+		for (Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.front();E;E=E->next()) {
+			RasterizerScene::InstanceBase*ins=E->key();
+			if (ins->material_override==p_rid) {
+				ins->material_override=RID();
+			}
+
+			for(int i=0;i<ins->materials.size();i++) {
+				if (ins->materials[i]==p_rid) {
+					ins->materials[i]=RID();
+				}
+			}
+
+		}
+
 		material_owner.free(p_rid);
 		memdelete(material);
 
@@ -5144,6 +5335,11 @@ bool RasterizerStorageGLES3::free(RID p_rid){
 		if (skeleton->update_list.in_list()) {
 			skeleton_update_list.remove(&skeleton->update_list);
 		}
+
+		for (Set<RasterizerScene::InstanceBase*>::Element *E=skeleton->instances.front();E;E=E->next()) {
+			E->get()->skeleton=RID();
+		}
+
 		skeleton_allocate(p_rid,0,false);
 		skeleton_owner.free(p_rid);
 		memdelete(skeleton);
@@ -5370,6 +5566,23 @@ void RasterizerStorageGLES3::initialize() {
 		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
 	}
 
+
+	{
+		//transform feedback buffers
+		uint32_t xf_feedback_size = GLOBAL_DEF("rendering/gles3/blend_shape_max_buffer_size_kb",4096);
+		for(int i=0;i<2;i++) {
+
+			glGenBuffers(1,&resources.transform_feedback_buffers[i]);
+			glBindBuffer(GL_ARRAY_BUFFER,resources.transform_feedback_buffers[i]);
+			glBufferData(GL_ARRAY_BUFFER,xf_feedback_size*1024,NULL,GL_STREAM_DRAW);
+		}
+
+		shaders.blend_shapes.init();;
+
+		glGenVertexArrays(1,&resources.transform_feedback_array);
+
+	}
+
 	shaders.cubemap_filter.init();
 
 	glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS);

+ 45 - 27
drivers/gles3/rasterizer_storage_gles3.h

@@ -6,6 +6,7 @@
 #include "shader_gles3.h"
 #include "shaders/copy.glsl.h"
 #include "shaders/canvas.glsl.h"
+#include "shaders/blend_shape.glsl.h"
 #include "shaders/cubemap_filter.glsl.h"
 #include "self_list.h"
 #include "shader_compiler_gles3.h"
@@ -65,6 +66,8 @@ public:
 
 		CubemapFilterShaderGLES3 cubemap_filter;
 
+		BlendShapeShaderGLES3 blend_shapes;
+
 		ShaderCompilerGLES3::IdentifierActions actions_canvas;
 		ShaderCompilerGLES3::IdentifierActions actions_scene;
 	} shaders;
@@ -79,6 +82,9 @@ public:
 		GLuint quadie;
 		GLuint quadie_array;
 
+		GLuint transform_feedback_buffers[2];
+		GLuint transform_feedback_array;
+
 	} resources;
 
 	struct Info {
@@ -133,8 +139,33 @@ public:
 		}
 	};
 
+	struct GeometryOwner : public Instantiable {
+
+		virtual ~GeometryOwner() {}
+	};
+	struct Geometry : Instantiable {
+
+		enum Type {
+			GEOMETRY_INVALID,
+			GEOMETRY_SURFACE,
+			GEOMETRY_IMMEDIATE,
+			GEOMETRY_MULTISURFACE,
+		};
+
+
+		Type type;
+		RID material;
+		uint64_t last_pass;
+		uint32_t index;
 
+		virtual void material_changed_notify() {}
 
+		Geometry() {
+			last_pass=0;
+			index=0;
+		}
+
+	};
 
 
 
@@ -384,7 +415,7 @@ public:
 		uint32_t index;
 		uint64_t last_pass;
 
-		Map<Instantiable*,int> instantiable_owners;
+		Map<Geometry*,int> geometry_owners;
 		Map<RasterizerScene::InstanceBase*,int> instance_owners;
 
 		bool can_cast_shadow_cache;
@@ -404,8 +435,8 @@ public:
 
 	mutable SelfList<Material>::List _material_dirty_list;
 	void _material_make_dirty(Material *p_material) const;
-	void _material_add_instantiable(RID p_material,Instantiable *p_instantiable);
-	void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable);
+	void _material_add_geometry(RID p_material,Geometry *p_instantiable);
+	void _material_remove_geometry(RID p_material, Geometry *p_instantiable);
 
 
 	mutable RID_Owner<Material> material_owner;
@@ -433,31 +464,9 @@ public:
 	/* MESH API */
 
 
-	struct Geometry : Instantiable {
-
-		enum Type {
-			GEOMETRY_INVALID,
-			GEOMETRY_SURFACE,
-			GEOMETRY_IMMEDIATE,
-			GEOMETRY_MULTISURFACE,
-		};
-
-		Type type;
-		RID material;
-		uint64_t last_pass;
-		uint32_t index;
 
-		Geometry() {
-			last_pass=0;
-			index=0;
-		}
 
-	};
 
-	struct GeometryOwner : public Instantiable {
-
-		virtual ~GeometryOwner() {}
-	};
 
 	struct Mesh;
 	struct Surface : public Geometry {
@@ -475,7 +484,7 @@ public:
 		};
 
 		Attrib attribs[VS::ARRAY_MAX];
-		Attrib morph_attribs[VS::ARRAY_MAX];
+
 
 
 		Mesh *mesh;
@@ -512,6 +521,10 @@ public:
 
 		bool active;
 
+		virtual void material_changed_notify() {
+			mesh->instance_material_change_notify();
+		}
+
 		Surface() {
 
 			array_byte_size=0;
@@ -590,6 +603,8 @@ public:
 	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const;
 	virtual void mesh_clear(RID p_mesh);
 
+	void mesh_render_blend_shapes(Surface *s, float *p_weights);
+
 	/* MULTIMESH API */
 
 	struct MultiMesh : public GeometryOwner {
@@ -699,12 +714,13 @@ public:
 
 	/* SKELETON API */
 
-	struct Skeleton : Instantiable {
+	struct Skeleton : RID_Data {
 		int size;
 		bool use_2d;
 		Vector<float> bones; //4x3 or 4x2 depending on what is needed
 		GLuint ubo;
 		SelfList<Skeleton> update_list;
+		Set<RasterizerScene::InstanceBase*> instances; //instances using skeleton
 
 		Skeleton() : update_list(this) {
 			size=0;
@@ -843,6 +859,8 @@ public:
 	virtual void portal_set_disable_distance(RID p_portal, float p_distance);
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color);
 
+	virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
+	virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
 
 	virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);
 	virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);

+ 22 - 1
drivers/gles3/shader_gles3.cpp

@@ -502,6 +502,25 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
 		glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name );
 	}
 
+	//if feedback exists, set it up
+
+	if (feedback_count) {
+		Vector<const char*> feedback;
+		for(int i=0;i<feedback_count;i++) {
+
+			if (feedbacks[i].conditional==-1 || (1<<feedbacks[i].conditional)&conditional_version.version) {
+				//conditional for this feedback is enabled
+				print_line("tf varying: "+itos(feedback.size())+" "+String(feedbacks[i].name));
+				feedback.push_back(feedbacks[i].name);
+			}
+		}
+
+		if (feedback.size()) {
+			glTransformFeedbackVaryings(v.id,feedback.size(),feedback.ptr(),GL_INTERLEAVED_ATTRIBS );
+		}
+
+	}
+
 	glLinkProgram(v.id);
 	
 	glGetProgramiv(v.id, GL_LINK_STATUS, &status);
@@ -604,7 +623,7 @@ GLint ShaderGLES3::get_uniform_location(const String& p_name) const {
 }
 
 
-void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start) {
+void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count, const Feedback* p_feedback, int p_feedback_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start) {
 
 	ERR_FAIL_COND(version);
 	conditional_version.key=0;
@@ -623,6 +642,8 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
 	attribute_pair_count=p_attribute_count;
 	ubo_pairs=p_ubo_pairs;
 	ubo_count=p_ubo_pair_count;
+	feedbacks=p_feedback;
+	feedback_count=p_feedback_count;
 
 	//split vertex and shader code (thank you, retarded shader compiler programmers from you know what company).
 	{

+ 9 - 1
drivers/gles3/shader_gles3.h

@@ -87,6 +87,12 @@ protected:
 		int index;
 	};
 
+	struct Feedback {
+
+		const char *name;
+		int conditional;
+	};
+
 	bool uniforms_dirty;
 private:	
 
@@ -95,6 +101,7 @@ private:
 	int texunit_pair_count;
 	int conditional_count;
 	int ubo_count;
+	int feedback_count;
 	int vertex_code_start;
 	int fragment_code_start;
 	int attribute_pair_count;
@@ -162,6 +169,7 @@ private:
 	const AttributePair *attribute_pairs;
 	const TexUnitPair *texunit_pairs;
 	const UBOPair *ubo_pairs;
+	const Feedback *feedbacks;
 	const char* vertex_code;
 	const char* fragment_code;
 	CharString fragment_code0;
@@ -293,7 +301,7 @@ protected:
 	_FORCE_INLINE_ int _get_uniform(int p_which) const;
 	_FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
 	
-	void setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start);
+	void setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs,int p_ubo_pair_count, const Feedback* p_feedback, int p_feedback_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start);
 	
 	ShaderGLES3();
 public:

+ 1 - 0
drivers/gles3/shaders/SCsub

@@ -7,4 +7,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
 	env.GLES3_GLSL('scene.glsl');
 	env.GLES3_GLSL('cubemap_filter.glsl');
 	env.GLES3_GLSL('cube_to_dp.glsl');
+	env.GLES3_GLSL('blend_shape.glsl');
 

+ 197 - 0
drivers/gles3/shaders/blend_shape.glsl

@@ -0,0 +1,197 @@
+[vertex]
+
+
+/*
+from VisualServer:
+
+ARRAY_VERTEX=0,
+ARRAY_NORMAL=1,
+ARRAY_TANGENT=2,
+ARRAY_COLOR=3,
+ARRAY_TEX_UV=4,
+ARRAY_TEX_UV2=5,
+ARRAY_BONES=6,
+ARRAY_WEIGHTS=7,
+ARRAY_INDEX=8,
+*/
+
+#ifdef USE_2D_VERTEX
+#define VFORMAT vec2
+#else
+#define VFORMAT vec3
+#endif
+
+/* INPUT ATTRIBS */
+
+layout(location=0) in highp VFORMAT vertex_attrib;
+layout(location=1) in vec3 normal_attrib;
+
+#ifdef ENABLE_TANGENT
+layout(location=2) in vec4 tangent_attrib;
+#endif
+
+#ifdef ENABLE_COLOR
+layout(location=3) in vec4 color_attrib;
+#endif
+
+#ifdef ENABLE_UV
+layout(location=4) in vec2 uv_attrib;
+#endif
+
+#ifdef ENABLE_UV2
+layout(location=5) in vec2 uv2_attrib;
+#endif
+
+#ifdef ENABLE_SKELETON
+layout(location=6) in ivec4 bone_attrib;
+layout(location=7) in vec4 weight_attrib;
+#endif
+
+/* BLEND ATTRIBS */
+
+#ifdef ENABLE_BLEND
+
+layout(location=8) in highp VFORMAT vertex_attrib_blend;
+layout(location=9) in vec3 normal_attrib_blend;
+
+#ifdef ENABLE_TANGENT
+layout(location=10) in vec4 tangent_attrib_blend;
+#endif
+
+#ifdef ENABLE_COLOR
+layout(location=11) in vec4 color_attrib_blend;
+#endif
+
+#ifdef ENABLE_UV
+layout(location=12) in vec2 uv_attrib_blend;
+#endif
+
+#ifdef ENABLE_UV2
+layout(location=13) in vec2 uv2_attrib_blend;
+#endif
+
+#ifdef ENABLE_SKELETON
+layout(location=14) in ivec4 bone_attrib_blend;
+layout(location=15) in vec4 weight_attrib_blend;
+#endif
+
+#endif
+
+/* OUTPUTS */
+
+out VFORMAT vertex_out; //tfb:
+
+#ifdef ENABLE_NORMAL
+out vec3 normal_out; //tfb:ENABLE_NORMAL
+#endif
+
+#ifdef ENABLE_TANGENT
+out vec4 tangent_out; //tfb:ENABLE_TANGENT
+#endif
+
+#ifdef ENABLE_COLOR
+out vec4 color_out; //tfb:ENABLE_COLOR
+#endif
+
+#ifdef ENABLE_UV
+out vec2 uv_out; //tfb:ENABLE_UV
+#endif
+
+#ifdef ENABLE_UV2
+out vec2 uv2_out; //tfb:ENABLE_UV2
+#endif
+
+#ifdef ENABLE_SKELETON
+out ivec4 bone_out; //tfb:ENABLE_SKELETON
+out vec4 weight_out; //tfb:ENABLE_SKELETON
+#endif
+
+uniform float blend_amount;
+
+void main() {
+
+
+#ifdef ENABLE_BLEND
+
+	vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount;
+
+#ifdef ENABLE_NORMAL
+	normal_out = normal_attrib_blend + normal_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_TANGENT
+
+	tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount;
+	tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his
+#endif
+
+#ifdef ENABLE_COLOR
+
+	color_out = color_attrib_blend + color_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV
+
+	uv_out = uv_attrib_blend + uv_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV2
+
+	uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount;
+#endif
+
+
+#ifdef ENABLE_SKELETON
+
+	bone_out = bone_attrib_blend;
+	weight_out = weight_attrib_blend + weight_attrib * blend_amount;
+#endif
+
+#else //ENABLE_BLEND
+
+
+	vertex_out = vertex_attrib * blend_amount;
+
+#ifdef ENABLE_NORMAL
+	normal_out = normal_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_TANGENT
+
+	tangent_out.xyz = tangent_attrib.xyz * blend_amount;
+	tangent_out.w = tangent_attrib.w; //just copy, no point in blending his
+#endif
+
+#ifdef ENABLE_COLOR
+
+	color_out = color_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV
+
+	uv_out = uv_attrib * blend_amount;
+#endif
+
+#ifdef ENABLE_UV2
+
+	uv2_out = uv2_attrib * blend_amount;
+#endif
+
+
+#ifdef ENABLE_SKELETON
+
+	bone_out = bone_attrib;
+	weight_out = weight_attrib * blend_amount;
+#endif
+
+#endif
+	gl_Position = vec4(0.0);
+}
+
+[fragment]
+
+
+void main() {
+
+}
+

+ 37 - 2
methods.py

@@ -671,6 +671,7 @@ class LegacyGLHeaderStruct:
 		self.fragment_lines=[]
 		self.uniforms=[]
 		self.attributes=[]
+		self.feedbacks=[]
 		self.fbos=[]
 		self.conditionals=[]
 		self.enums={}
@@ -823,6 +824,20 @@ def include_file_in_legacygl_header( filename, header_data, depth ):
 					bind=bind.replace("attrib:","").strip()
 					header_data.attributes+=[(name,bind)]
 
+		if ( line.strip().find("out ")==0 and line.find("tfb:")!=-1):
+			uline = line.replace("out ","");
+			uline = uline.replace("highp ","");
+			uline = uline.replace(";","");
+			uline = uline[ uline.find(" "): ].strip()
+
+
+			if (uline.find("//")!=-1):
+				name,bind = uline.split("//")
+				if (bind.find("tfb:")!=-1):
+					name=name.strip()
+					bind=bind.replace("tfb:","").strip()
+					header_data.feedbacks+=[(name,bind)]
+
 
 		line=line.replace("\r","")
 		line=line.replace("\n","")
@@ -1039,12 +1054,14 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
 		fd.write("\t\tstatic const Enum *_enums=NULL;\n")
 		fd.write("\t\tstatic const EnumValue *_enum_values=NULL;\n")
 
+	conditionals_found = []
 	if (len(header_data.conditionals)):
 
 		fd.write("\t\tstatic const char* _conditional_strings[]={\n")
 		if (len(header_data.conditionals)):
 			for x in header_data.conditionals:
 				fd.write("\t\t\t\"#define "+x+"\\n\",\n");
+				conditionals_found.append(x)
 		fd.write("\t\t};\n\n");
 	else:
 		fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
@@ -1070,6 +1087,24 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
 		else:
 			fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n")
 
+	feedback_count=0
+
+	if (len(header_data.feedbacks)):
+
+		fd.write("\t\tstatic const Feedback _feedbacks[]={\n")
+		for x in header_data.feedbacks:
+			name = x[0]
+			cond = x[1]
+			if (cond in conditionals_found):
+				fd.write("\t\t\t{\""+name+"\","+str(conditionals_found.index(cond))+"},\n");
+			else:
+				fd.write("\t\t\t{\""+name+"\",-1},\n");
+
+			feedback_count+=1
+
+		fd.write("\t\t};\n\n");
+	else:
+		fd.write("\t\tstatic const Feedback* _feedbacks=NULL;\n")
 
 	if (len(header_data.texunits)):
 		fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
@@ -1109,9 +1144,9 @@ def build_legacygl_header( filename, include, class_suffix, output_attribs ):
 	fd.write("\t\tstatic const int _fragment_code_start="+str(header_data.fragment_offset)+";\n")
 
 	if output_attribs:
-		fd.write("\t\tsetup(_conditional_strings,"+str(len(header_data.conditionals))+",_uniform_strings,"+str(len(header_data.uniforms))+",_attribute_pairs,"+str(len(header_data.attributes))+", _texunit_pairs,"+str(len(header_data.texunits))+",_ubo_pairs,"+str(len(header_data.ubos))+",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+		fd.write("\t\tsetup(_conditional_strings,"+str(len(header_data.conditionals))+",_uniform_strings,"+str(len(header_data.uniforms))+",_attribute_pairs,"+str(len(header_data.attributes))+", _texunit_pairs,"+str(len(header_data.texunits))+",_ubo_pairs,"+str(len(header_data.ubos))+",_feedbacks,"+str(feedback_count)+",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
 	else:
-		fd.write("\t\tsetup(_conditional_strings,"+str(len(header_data.conditionals))+",_uniform_strings,"+str(len(header_data.uniforms))+",_texunit_pairs,"+str(len(header_data.texunits))+",_enums,"+str(len(header_data.enums))+",_enum_values,"+str(enum_value_count)+",_ubo_pairs,"+str(len(header_data.ubos))+",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+		fd.write("\t\tsetup(_conditional_strings,"+str(len(header_data.conditionals))+",_uniform_strings,"+str(len(header_data.uniforms))+",_texunit_pairs,"+str(len(header_data.texunits))+",_enums,"+str(len(header_data.enums))+",_enum_values,"+str(enum_value_count)+",_ubo_pairs,"+str(len(header_data.ubos))+",_feedbacks,"+str(feedback_count)+",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
 
 	fd.write("\t};\n\n")
 

+ 3 - 3
scene/resources/mesh.cpp

@@ -316,14 +316,14 @@ void Mesh::add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector
 
 }
 
-void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) {
+void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,uint32_t p_flags) {
 
 
 	ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX);
 
 	Surface s;
 
-	VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes);
+	VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes,p_flags);
 	surfaces.push_back(s);
 
 
@@ -1024,7 +1024,7 @@ void Mesh::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode);
 	ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode);
 
-	ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes"),&Mesh::add_surface_from_arrays,DEFVAL(Array()));
+	ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes","compress_flags"),&Mesh::add_surface_from_arrays,DEFVAL(Array()),DEFVAL(ARRAY_COMPRESS_DEFAULT));
 	ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count);
 	ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove);
 	ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len);

+ 17 - 1
scene/resources/mesh.h

@@ -77,6 +77,22 @@ public:
 		ARRAY_FORMAT_WEIGHTS=1<<ARRAY_WEIGHTS,
 		ARRAY_FORMAT_INDEX=1<<ARRAY_INDEX,
 
+		ARRAY_COMPRESS_BASE=(ARRAY_INDEX+1),
+		ARRAY_COMPRESS_VERTEX=1<<(ARRAY_VERTEX+ARRAY_COMPRESS_BASE), // mandatory
+		ARRAY_COMPRESS_NORMAL=1<<(ARRAY_NORMAL+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_TANGENT=1<<(ARRAY_TANGENT+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_COLOR=1<<(ARRAY_COLOR+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_TEX_UV=1<<(ARRAY_TEX_UV+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_TEX_UV2=1<<(ARRAY_TEX_UV2+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_BONES=1<<(ARRAY_BONES+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_WEIGHTS=1<<(ARRAY_WEIGHTS+ARRAY_COMPRESS_BASE),
+		ARRAY_COMPRESS_INDEX=1<<(ARRAY_INDEX+ARRAY_COMPRESS_BASE),
+
+		ARRAY_FLAG_USE_2D_VERTICES=ARRAY_COMPRESS_INDEX<<1,
+		ARRAY_FLAG_USE_16_BIT_BONES=ARRAY_COMPRESS_INDEX<<2,
+
+		ARRAY_COMPRESS_DEFAULT=ARRAY_COMPRESS_VERTEX|ARRAY_COMPRESS_NORMAL|ARRAY_COMPRESS_TANGENT|ARRAY_COMPRESS_COLOR|ARRAY_COMPRESS_TEX_UV|ARRAY_COMPRESS_TEX_UV2|ARRAY_COMPRESS_WEIGHTS
+
 	};
 
 	enum PrimitiveType {
@@ -122,7 +138,7 @@ protected:
 
 public:
 
-	void add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array());
+	void add_surface_from_arrays(PrimitiveType p_primitive, const Array& p_arrays, const Array& p_blend_shapes=Array(), uint32_t p_flags=ARRAY_COMPRESS_DEFAULT);
 	void add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>());
 
 	Array surface_get_arrays(int p_surface) const;

+ 27 - 11
scene/resources/surface_tool.cpp

@@ -355,7 +355,30 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
 				w=DVector<Color>::Write();
 				a[i]=array;
 			} break;
-			case Mesh::ARRAY_FORMAT_BONES:
+			case Mesh::ARRAY_FORMAT_BONES: {
+
+
+				DVector<int> array;
+				array.resize(varr_len*4);
+				DVector<int>::Write w = array.write();
+
+				int idx=0;
+				for(List< Vertex >::Element *E=vertex_array.front();E;E=E->next(),idx+=4) {
+
+					const Vertex &v=E->get();
+
+					ERR_CONTINUE( v.bones.size()!=4 );
+
+					for(int j=0;j<4;j++) {
+						w[idx+j]=v.bones[j];
+					}
+
+				}
+
+				w=DVector<int>::Write();
+				a[i]=array;
+
+			} break;
 			case Mesh::ARRAY_FORMAT_WEIGHTS: {
 
 
@@ -367,18 +390,11 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
 				for(List< Vertex >::Element *E=vertex_array.front();E;E=E->next(),idx+=4) {
 
 					const Vertex &v=E->get();
+					ERR_CONTINUE( v.weights.size()!=4 );
 
 					for(int j=0;j<4;j++) {
-						switch(i) {
-							case Mesh::ARRAY_WEIGHTS: {
-								ERR_CONTINUE( v.weights.size()!=4 );
-								w[idx+j]=v.weights[j];
-							} break;
-							case Mesh::ARRAY_BONES: {
-								ERR_CONTINUE( v.bones.size()!=4 );
-								w[idx+j]=v.bones[j];
-							} break;
-						}
+
+						w[idx+j]=v.weights[j];
 					}
 
 				}

+ 2 - 1
servers/visual/rasterizer.h

@@ -380,7 +380,8 @@ public:
 	virtual void portal_set_disable_distance(RID p_portal, float p_distance)=0;
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0;
 
-
+	virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance)=0;
+	virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance)=0;
 
 	virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
 	virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;

+ 24 - 3
servers/visual/visual_server_scene.cpp

@@ -738,13 +738,25 @@ void VisualServerScene::instance_attach_object_instance_ID(RID p_instance,Object
 }
 void VisualServerScene::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){
 
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	if (instance->update_item.in_list()) {
+		_update_dirty_instance(instance);
+	}
+
+	ERR_FAIL_INDEX(p_shape,instance->morph_values.size());
+	instance->morph_values[p_shape]=p_weight;
 }
+
 void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){
 
 	Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND( !instance );
 
-	_update_dirty_instance(instance);
+	if (instance->update_item.in_list()) {
+		_update_dirty_instance(instance);
+	}
 
 	ERR_FAIL_INDEX(p_surface,instance->materials.size());
 
@@ -770,13 +782,13 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){
 		return;
 
 	if (instance->skeleton.is_valid()) {
-		VSG::storage->instance_remove_dependency(p_skeleton,instance);
+		VSG::storage->instance_remove_skeleton(p_skeleton,instance);
 	}
 
 	instance->skeleton=p_skeleton;
 
 	if (instance->skeleton.is_valid()) {
-		VSG::storage->instance_add_dependency(p_skeleton,instance);
+		VSG::storage->instance_add_skeleton(p_skeleton,instance);
 	}
 
 	_instance_queue_update(instance,true);
@@ -2227,6 +2239,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 	if (p_instance->update_aabb)
 		_update_instance_aabb(p_instance);
 
+
 	if (p_instance->update_materials) {
 
 		if (p_instance->base_type==VS::INSTANCE_MESH) {
@@ -2239,6 +2252,14 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 				}
 			}
 			p_instance->materials.resize(new_mat_count);
+
+			int new_morph_count = VSG::storage->mesh_get_morph_target_count(p_instance->base);
+			if (new_morph_count!=p_instance->morph_values.size()) {
+				p_instance->morph_values.resize(new_morph_count);
+				for(int i=0;i<new_morph_count;i++) {
+					p_instance->morph_values[i]=0;
+				}
+			}
 		}
 
 		if ((1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {

+ 6 - 6
servers/visual_server.cpp

@@ -709,7 +709,7 @@ Error VisualServer::_surface_set_data(Array p_arrays,uint32_t p_format,uint32_t
 			} break;
 			case VS::ARRAY_BONES: {
 
-				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER );
 
 				DVector<int> array = p_arrays[ai];
 
@@ -912,7 +912,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi
 					bsformat|=(1<<j);
 			}
 
-			ERR_FAIL_COND( (bsformat)!=(format&(VS::ARRAY_FORMAT_BONES-1)));
+			ERR_FAIL_COND( (bsformat)!=(format&(VS::ARRAY_FORMAT_INDEX-1)));
 		}
 	}
 
@@ -1089,7 +1089,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi
 		DVector<uint8_t> noindex;
 
 		AABB laabb;
-		Error err = _surface_set_data(p_blend_shapes[i],format&~ARRAY_FORMAT_INDEX,offsets,total_elem_size,vertex_array,array_len,noindex,0,laabb,bone_aabb);
+		Error err = _surface_set_data(p_blend_shapes[i],format&~ARRAY_FORMAT_INDEX,offsets,total_elem_size,vertex_array_shape,array_len,noindex,0,laabb,bone_aabb);
 		aabb.merge_with(laabb);
 		if (err) {
 			ERR_EXPLAIN("Invalid blend shape array format for surface");
@@ -1194,9 +1194,9 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector<uint8_t> p
 			case VS::ARRAY_BONES: {
 
 				if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) {
-					elem_size=sizeof(uint32_t);
-				} else {
 					elem_size=sizeof(uint16_t)*4;
+				} else {
+					elem_size=sizeof(uint32_t);
 				}
 
 			} break;
@@ -1487,7 +1487,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector<uint8_t> p
 					DVector<int>::Write w = arr.write();
 
 					for(int j=0;j<p_vertex_len;j++) {
-						const int *v = (const int*)&r[j*total_elem_size+offsets[i]];
+						const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]];
 						for(int k=0;k<4;k++) {
 							w[j*4+k]=v[k];
 						}

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

@@ -85,7 +85,7 @@ struct ColladaImport {
 	Error _create_scene(Collada::Node *p_node, Spatial *p_parent);
 	Error _create_resources(Collada::Node *p_node);
 	Error _create_material(const String& p_material);
-	Error _create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data,Vector<Ref<Mesh> > p_morph_meshes=Vector<Ref<Mesh> >());
+	Error _create_mesh_surfaces(bool p_optimize, Ref<Mesh>& p_mesh, const Map<String,Collada::NodeGeometry::Material>& p_material_map, const Collada::MeshData &meshdata, const Transform& p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data, Vector<Ref<Mesh> > p_morph_meshes=Vector<Ref<Mesh> >(), bool p_for_morph=false);
 	Error load(const String& p_path, int p_flags, bool p_force_make_tangents=false);
 	void _fix_param_animation_tracks();
 	void create_animation(int p_clip,bool p_make_tracks_in_all_bones);
@@ -597,7 +597,7 @@ static void _generate_tangents_and_binormals(const DVector<int>& p_indices,const
 	}
 }
 
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data,Vector<Ref<Mesh> > p_morph_meshes) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,const Map<String,Collada::NodeGeometry::Material>& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector<int> &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data,Vector<Ref<Mesh> > p_morph_meshes,bool p_for_morph) {
 
 
 	bool local_xform_mirror=p_local_xform.basis.determinant() < 0;
@@ -1072,7 +1072,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 			DVector<Color> final_color_array;
 			DVector<Vector3> final_uv_array;
 			DVector<Vector3> final_uv2_array;
-			DVector<float> final_bone_array;
+			DVector<int> final_bone_array;
 			DVector<float> final_weight_array;
 
 			uint32_t final_format=0;
@@ -1223,12 +1223,12 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 
 			if (has_weights) {
 				DVector<float> weightarray;
-				DVector<float> bonearray;
+				DVector<int> bonearray;
 
 				weightarray.resize(vertex_array.size()*4);
 				DVector<float>::Write weightarrayw = weightarray.write();
 				bonearray.resize(vertex_array.size()*4);
-				DVector<float>::Write bonearrayw = bonearray.write();
+				DVector<int>::Write bonearrayw = bonearray.write();
 
 				for(int k=0;k<vlen;k++) {
 					float sum=0;
@@ -1237,7 +1237,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 						if (l<vertex_array[k].weights.size()) {
 							weightarrayw[k*VS::ARRAY_WEIGHTS_SIZE+l]=vertex_array[k].weights[l].weight;
 							sum+=weightarrayw[k*VS::ARRAY_WEIGHTS_SIZE+l];
-							bonearrayw[k*VS::ARRAY_WEIGHTS_SIZE+l]=vertex_array[k].weights[l].bone_idx;
+							bonearrayw[k*VS::ARRAY_WEIGHTS_SIZE+l]=int(vertex_array[k].weights[l].bone_idx);
 							//COLLADA_PRINT(itos(k)+": "+rtos(bonearrayw[k*VS::ARRAY_WEIGHTS_SIZE+l])+":"+rtos(weightarray[k*VS::ARRAY_WEIGHTS_SIZE+l]));
 						} else {
 
@@ -1254,7 +1254,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 				}
 
 				weightarrayw = DVector<float>::Write();
-				bonearrayw = DVector<float>::Write();
+				bonearrayw = DVector<int>::Write();
 
 				final_weight_array = weightarray;
 				final_bone_array = bonearray;
@@ -1461,14 +1461,20 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 
 			//	print_line("want surface "+itos(mi)+" has "+itos(p_morph_meshes[mi]->get_surface_count()));
 				Array a = p_morph_meshes[mi]->surface_get_arrays(surface);
-				a[Mesh::ARRAY_BONES]=Variant();
-				a[Mesh::ARRAY_WEIGHTS]=Variant();
+				//add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not)
+
+				if (final_weight_array.size())
+					a[Mesh::ARRAY_WEIGHTS]=final_weight_array;
+				if (final_bone_array.size())
+					a[Mesh::ARRAY_BONES]=final_bone_array;
+
 				a[Mesh::ARRAY_INDEX]=Variant();
 				//a.resize(Mesh::ARRAY_MAX); //no need for index
 				mr.push_back(a);
 			}
 
-			p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr);
+
+			p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr,p_for_morph?0:Mesh::ARRAY_COMPRESS_DEFAULT);
 
 			if (material.is_valid()) {
 				p_mesh->surface_set_material(surface, material);
@@ -1692,7 +1698,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) {
 							if (collada.state.mesh_data_map.has(meshid)) {
 								Ref<Mesh> mesh=Ref<Mesh>(memnew( Mesh ));
 								const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
-								Error err = _create_mesh_surfaces(false,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,NULL);
+								Error err = _create_mesh_surfaces(false,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,NULL,Vector<Ref<Mesh> >(),true);
 								ERR_FAIL_COND_V(err,err);
 
 								morphs.push_back(mesh);

+ 2 - 0
tools/editor/plugins/script_editor_plugin.cpp

@@ -1840,6 +1840,8 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
 
 void ScriptEditor::_help_class_open(const String& p_class) {
 
+	if (p_class=="")
+		return;
 
 	for(int i=0;i<tab_container->get_child_count();i++) {