Przeglądaj źródła

Everything returning to normal in 3D, still a long way to go
-implemented the scene part of visual server and rasterizer, objects without lighting and material are rendererd only

Juan Linietsky 9 lat temu
rodzic
commit
4428115916

+ 4 - 1
bin/tests/test_render.cpp

@@ -173,7 +173,10 @@ public:
 // 		vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
 
 		viewport = vs->viewport_create();
-		vs->viewport_attach_to_screen(viewport,Rect2(Vector2(),OS::get_singleton()->get_window_size()));
+		Size2i screen_size = OS::get_singleton()->get_window_size();
+		vs->viewport_set_size(viewport,screen_size.x,screen_size.y);
+		vs->viewport_attach_to_screen(viewport,Rect2(Vector2(),screen_size));
+		vs->viewport_set_active(viewport,true);
 		vs->viewport_attach_camera( viewport, camera );
 		vs->viewport_set_scenario( viewport, scenario );
 		vs->camera_set_transform(camera, Transform( Matrix3(), Vector3(0,3,30 ) ) );

+ 102 - 0
core/math/math_funcs.h

@@ -175,6 +175,108 @@ public:
 	static double log(double x);
 	static double exp(double x);
 
+
+	static _FORCE_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h)
+	{
+	    uint16_t h_exp, h_sig;
+	    uint32_t f_sgn, f_exp, f_sig;
+
+	    h_exp = (h&0x7c00u);
+	    f_sgn = ((uint32_t)h&0x8000u) << 16;
+	    switch (h_exp) {
+		case 0x0000u: /* 0 or subnormal */
+		    h_sig = (h&0x03ffu);
+		    /* Signed zero */
+		    if (h_sig == 0) {
+			return f_sgn;
+		    }
+		    /* Subnormal */
+		    h_sig <<= 1;
+		    while ((h_sig&0x0400u) == 0) {
+			h_sig <<= 1;
+			h_exp++;
+		    }
+		    f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23;
+		    f_sig = ((uint32_t)(h_sig&0x03ffu)) << 13;
+		    return f_sgn + f_exp + f_sig;
+		case 0x7c00u: /* inf or NaN */
+		    /* All-ones exponent and a copy of the significand */
+		    return f_sgn + 0x7f800000u + (((uint32_t)(h&0x03ffu)) << 13);
+		default: /* normalized */
+		    /* Just need to adjust the exponent and shift */
+		    return f_sgn + (((uint32_t)(h&0x7fffu) + 0x1c000u) << 13);
+	    }
+	}
+
+	static _FORCE_INLINE_ float halfptr_to_float(uint16_t *h) {
+
+		union {
+			uint32_t u32;
+			float f32;
+		} u;
+
+		u.u32=halfbits_to_floatbits(*h);
+		return u.f32;
+	}
+
+	static _FORCE_INLINE_ uint16_t make_half_float(float f) {
+
+	    union {
+	       float fv;
+	       uint32_t ui;
+	    } ci;
+	    ci.fv=f;
+
+	    uint32_t    x = ci.ui;
+	    uint32_t    sign = (unsigned short)(x >> 31);
+	    uint32_t    mantissa;
+	    uint32_t    exp;
+	    uint16_t          hf;
+
+	    // get mantissa
+	    mantissa = x & ((1 << 23) - 1);
+	    // get exponent bits
+	    exp = x & (0xFF << 23);
+	    if (exp >= 0x47800000)
+	    {
+		// check if the original single precision float number is a NaN
+		if (mantissa && (exp == (0xFF << 23)))
+		{
+		    // we have a single precision NaN
+		    mantissa = (1 << 23) - 1;
+		}
+		else
+		{
+		    // 16-bit half-float representation stores number as Inf
+		    mantissa = 0;
+		}
+		hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) |
+		      (uint16_t)(mantissa >> 13);
+	    }
+	    // check if exponent is <= -15
+	    else if (exp <= 0x38000000)
+	    {
+
+		/*// store a denorm half-float value or zero
+		exp = (0x38000000 - exp) >> 23;
+		mantissa >>= (14 + exp);
+
+		hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
+		*/
+		hf=0; //denormals do not work for 3D, convert to zero
+	    }
+	    else
+	    {
+		hf = (((uint16_t)sign) << 15) |
+		      (uint16_t)((exp - 0x38000000) >> 13) |
+		      (uint16_t)(mantissa >> 13);
+	    }
+
+	    return hf;
+	}
+
+
+
 };
 
 

+ 8 - 0
core/rid.h

@@ -181,6 +181,14 @@ public:
 
 	}
 
+
+	_FORCE_INLINE_ T * getptr(const RID& p_rid) {
+
+		return static_cast<T*>(p_rid.get_data());
+
+	}
+
+
 	_FORCE_INLINE_ bool owns(const RID& p_rid) const {
 
 		if (p_rid.get_data()==NULL)

+ 1 - 0
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -117,6 +117,7 @@ void RasterizerCanvasGLES3::canvas_begin(){
 		glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a );
 		glClear(GL_COLOR_BUFFER_BIT);
 		storage->frame.clear_request=false;
+		print_line("canvas clear?");
 
 	}
 

+ 8 - 1
drivers/gles3/rasterizer_gles3.cpp

@@ -15,7 +15,7 @@ RasterizerCanvas *RasterizerGLES3::get_canvas() {
 
 RasterizerScene *RasterizerGLES3::get_scene() {
 
-	return NULL;
+	return scene;
 }
 
 
@@ -111,6 +111,7 @@ void RasterizerGLES3::initialize() {
 */
 	storage->initialize();
 	canvas->initialize();
+	scene->initialize();
 }
 
 void RasterizerGLES3::begin_frame(){
@@ -124,6 +125,7 @@ void RasterizerGLES3::begin_frame(){
 
 	storage->update_dirty_shaders();
 	storage->update_dirty_materials();
+
 }
 
 void RasterizerGLES3::set_current_render_target(RID p_render_target){
@@ -131,6 +133,7 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target){
 	if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) {
 		//handle pending clear request, if the framebuffer was not cleared
 		glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo);
+		print_line("unbind clear of: "+storage->frame.clear_request_color);
 		glClearColor(
 			storage->frame.clear_request_color.r,
 			storage->frame.clear_request_color.g,
@@ -265,8 +268,12 @@ RasterizerGLES3::RasterizerGLES3()
 
 	storage = memnew( RasterizerStorageGLES3 );
 	canvas = memnew( RasterizerCanvasGLES3 );
+	scene = memnew( RasterizerSceneGLES3 );
 	canvas->storage=storage;
 	storage->canvas=canvas;
+	scene->storage=storage;
+	storage->scene=scene;
+
 
 
 }

+ 3 - 0
drivers/gles3/rasterizer_gles3.h

@@ -4,6 +4,7 @@
 #include "servers/visual/rasterizer.h"
 #include "rasterizer_storage_gles3.h"
 #include "rasterizer_canvas_gles3.h"
+#include "rasterizer_scene_gles3.h"
 
 
 class RasterizerGLES3 : public Rasterizer {
@@ -12,6 +13,8 @@ class RasterizerGLES3 : public Rasterizer {
 
 	RasterizerStorageGLES3 *storage;
 	RasterizerCanvasGLES3 *canvas;
+	RasterizerSceneGLES3 *scene;
+
 public:
 
 	virtual RasterizerStorage *get_storage();

+ 808 - 0
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -0,0 +1,808 @@
+#include "rasterizer_scene_gles3.h"
+#include "globals.h"
+static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) {
+
+	p_array[ 0]=p_mtx.elements[0][0];
+	p_array[ 1]=p_mtx.elements[0][1];
+	p_array[ 2]=0;
+	p_array[ 3]=0;
+	p_array[ 4]=p_mtx.elements[1][0];
+	p_array[ 5]=p_mtx.elements[1][1];
+	p_array[ 6]=0;
+	p_array[ 7]=0;
+	p_array[ 8]=0;
+	p_array[ 9]=0;
+	p_array[10]=1;
+	p_array[11]=0;
+	p_array[12]=p_mtx.elements[2][0];
+	p_array[13]=p_mtx.elements[2][1];
+	p_array[14]=0;
+	p_array[15]=1;
+}
+
+
+static _FORCE_INLINE_ void store_transform(const Transform& p_mtx, float* p_array) {
+	p_array[ 0]=p_mtx.basis.elements[0][0];
+	p_array[ 1]=p_mtx.basis.elements[1][0];
+	p_array[ 2]=p_mtx.basis.elements[2][0];
+	p_array[ 3]=0;
+	p_array[ 4]=p_mtx.basis.elements[0][1];
+	p_array[ 5]=p_mtx.basis.elements[1][1];
+	p_array[ 6]=p_mtx.basis.elements[2][1];
+	p_array[ 7]=0;
+	p_array[ 8]=p_mtx.basis.elements[0][2];
+	p_array[ 9]=p_mtx.basis.elements[1][2];
+	p_array[10]=p_mtx.basis.elements[2][2];
+	p_array[11]=0;
+	p_array[12]=p_mtx.origin.x;
+	p_array[13]=p_mtx.origin.y;
+	p_array[14]=p_mtx.origin.z;
+	p_array[15]=1;
+}
+
+static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_array) {
+
+	for (int i=0;i<4;i++) {
+		for (int j=0;j<4;j++) {
+
+			p_array[i*4+j]=p_mtx.matrix[i][j];
+		}
+	}
+}
+
+
+
+RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
+
+
+	return RID();
+}
+
+void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){
+
+
+}
+
+
+bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass) {
+
+	if (p_material->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_DISABLED) {
+		glDisable(GL_CULL_FACE);
+	} else {
+		glEnable(GL_CULL_FACE);
+	}
+
+	//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+
+	/*
+	if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME])
+		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+	else
+		glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+	*/
+
+	//if (p_material->line_width)
+	//	glLineWidth(p_material->line_width);
+
+
+	//blend mode
+	if (state.current_blend_mode!=p_material->shader->spatial.blend_mode) {
+
+		switch(p_material->shader->spatial.blend_mode) {
+
+			 case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: {
+				glBlendEquation(GL_FUNC_ADD);
+				if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+					glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+				} else {
+					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				}
+
+			 } break;
+			 case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: {
+
+				glBlendEquation(GL_FUNC_ADD);
+				glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE);
+
+			 } break;
+			 case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: {
+
+				glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+				glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+			 } break;
+			case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: {
+				glBlendEquation(GL_FUNC_ADD);
+				if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+					glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+				} else {
+					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				}
+
+			} break;
+		}
+
+		state.current_blend_mode=p_material->shader->spatial.blend_mode;
+
+	}
+
+	//material parameters
+
+	state.scene_shader.set_custom_shader(p_material->shader->custom_code_id);
+	bool rebind = state.scene_shader.bind();
+
+
+	if (p_material->ubo_id) {
+		glBindBufferBase(GL_UNIFORM_BUFFER,1,p_material->ubo_id);
+	}
+
+
+
+	int tc = p_material->textures.size();
+	RID* textures = p_material->textures.ptr();
+
+	for(int i=0;i<tc;i++) {
+
+		glActiveTexture(GL_TEXTURE0+i);
+
+		RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull( textures[i] );
+		if (!t) {
+			//check hints
+			glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex);
+			continue;
+		}
+
+		glBindTexture(t->target,t->tex_id);
+	}
+
+
+	return rebind;
+
+}
+
+
+void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
+
+	switch(e->instance->base_type) {
+
+		case VS::INSTANCE_MESH: {
+
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+			glBindVertexArray(s->array_id); // everything is so easy nowadays
+		} break;
+	}
+
+}
+
+static const GLenum gl_primitive[]={
+	GL_POINTS,
+	GL_LINES,
+	GL_LINE_STRIP,
+	GL_LINE_LOOP,
+	GL_TRIANGLES,
+	GL_TRIANGLE_STRIP,
+	GL_TRIANGLE_FAN
+};
+
+
+
+void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
+
+	switch(e->instance->base_type) {
+
+		case VS::INSTANCE_MESH: {
+
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+
+			if (s->index_array_len>0) {
+
+				glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0);
+
+			} else {
+
+				glDrawArrays(gl_primitive[s->primitive],0,s->array_len);
+
+			}
+
+		} break;
+	}
+
+}
+
+void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,bool p_reverse_cull,bool p_alpha_pass) {
+
+	if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
+		//p_reverse_cull=!p_reverse_cull;
+		glFrontFace(GL_CCW);
+	} else {
+		glFrontFace(GL_CW);
+	}
+
+	glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo
+
+	state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false);
+
+	state.current_blend_mode=-1;
+
+	glDisable(GL_BLEND);
+
+	RasterizerStorageGLES3::Material* prev_material=NULL;
+	RasterizerStorageGLES3::Geometry* prev_geometry=NULL;
+	VS::InstanceType prev_base_type = VS::INSTANCE_MAX;
+
+	for (int i=0;i<p_element_count;i++) {
+
+		RenderList::Element *e = p_elements[i];
+		RasterizerStorageGLES3::Material* material= e->material;
+
+		bool rebind=i==0;
+
+		if (material!=prev_material || rebind) {
+
+			rebind = _setup_material(material,p_alpha_pass);
+//			_rinfo.mat_change_count++;
+		}
+
+
+		if (prev_base_type != e->instance->base_type || prev_geometry!=e->geometry) {
+
+			_setup_geometry(e);
+		}
+
+//		_set_cull(e->mirror,p_reverse_cull);
+
+		state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0);
+		state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform);
+
+
+//		_render(e->geometry, material, skeleton,e->owner,e->instance->transform);
+
+		_render_geometry(e);
+
+		prev_material=material;
+		prev_base_type=e->instance->base_type;
+		prev_geometry=e->geometry;
+	}
+
+	//print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count));
+
+
+	glFrontFace(GL_CW);
+	glBindVertexArray(0);
+
+}
+
+void RasterizerSceneGLES3::_add_geometry(  RasterizerStorageGLES3::Geometry* p_geometry,  InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material) {
+
+	RasterizerStorageGLES3::Material *m=NULL;
+	RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material);
+
+/*
+#ifdef DEBUG_ENABLED
+	if (current_debug==VS::SCENARIO_DEBUG_OVERDRAW) {
+		m_src=overdraw_material;
+	}
+
+#endif
+*/
+	if (m_src.is_valid()) {
+		m=storage->material_owner.getornull( m_src );
+		if (!m->shader) {
+			m=NULL;
+		}
+	}
+
+	if (!m) {
+		m=storage->material_owner.getptr( default_material );
+	}
+
+	ERR_FAIL_COND(!m);
+
+
+
+	//bool has_base_alpha=(m->shader_cache && m->shader_cache->has_alpha);
+	//bool has_blend_alpha=m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX || m->flags[VS::MATERIAL_FLAG_ONTOP];
+	bool has_alpha = false; //has_base_alpha || has_blend_alpha;
+
+#if 0
+	if (shadow) {
+
+		if (has_blend_alpha || (has_base_alpha && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA))
+			return; //bye
+
+		if (!m->shader_cache || (!m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) {
+			//shader does not use discard and does not write a vertex position, use generic material
+			if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)
+				m = shadow_mat_double_sided_ptr;
+			else
+				m = shadow_mat_ptr;
+			if (m->last_pass!=frame) {
+
+				if (m->shader.is_valid()) {
+
+					m->shader_cache=shader_owner.get(m->shader);
+					if (m->shader_cache) {
+
+
+						if (!m->shader_cache->valid)
+							m->shader_cache=NULL;
+					} else {
+						m->shader=RID();
+					}
+
+				} else {
+					m->shader_cache=NULL;
+				}
+
+				m->last_pass=frame;
+			}
+		}
+
+		render_list = &opaque_render_list;
+	/* notyet
+		if (!m->shader_cache || m->shader_cache->can_zpass)
+			render_list = &alpha_render_list;
+		} else {
+			render_list = &opaque_render_list;
+		}*/
+
+	} else {
+		if (has_alpha) {
+			render_list = &alpha_render_list;
+		} else {
+			render_list = &opaque_render_list;
+
+		}
+	}
+#endif
+
+	RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
+
+	if (!e)
+		return;
+
+	e->geometry=p_geometry;
+	e->material=m;
+	e->instance=p_instance;
+	e->owner=p_owner;
+	e->additive=false;
+	e->additive_ptr=&e->additive;
+	e->sort_key=0;
+
+	if (e->geometry->last_pass!=render_pass) {
+		e->geometry->last_pass=render_pass;
+		e->geometry->index=current_geometry_index++;
+	}
+
+	e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT;
+	e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT;
+
+	if (e->material->last_pass!=render_pass) {
+		e->material->last_pass=render_pass;
+		e->material->index=current_material_index++;
+	}
+
+	e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT;
+
+	e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT;
+
+	//if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)
+	//	e->sort_flags|=RenderList::SORT_FLAG_INSTANCING;
+
+	bool mirror = e->instance->mirror;
+
+//	if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES])
+//		e->mirror=!e->mirror;
+
+	if (mirror) {
+		e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG;
+	}
+
+	//e->light_type=0xFF; // no lights!
+	e->sort_key|=uint64_t(0xF)<<RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //light type 0xF is no light?
+	e->sort_key|=uint64_t(0xFFFF)<<RenderList::SORT_KEY_LIGHT_INDEX_SHIFT;
+/* prepass
+	if (!shadow && !has_blend_alpha && has_alpha && m->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA) {
+
+		//if nothing exists, add this element as opaque too
+		RenderList::Element *oe = opaque_render_list.add_element();
+
+		if (!oe)
+			return;
+
+		memcpy(oe,e,sizeof(RenderList::Element));
+		oe->additive_ptr=&oe->additive;
+	}
+*/
+
+#if 0
+	if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) {
+
+		e->light_type=0x7F; //unshaded is zero
+	} else {
+
+		bool duplicate=false;
+
+
+		for(int i=0;i<directional_light_count;i++) {
+			uint16_t sort_key = directional_lights[i]->sort_key;
+			uint8_t light_type = VS::LIGHT_DIRECTIONAL;
+			if (directional_lights[i]->base->shadow_enabled) {
+				light_type|=0x8;
+				if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS)
+					light_type|=0x10;
+				else if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS)
+					light_type|=0x30;
+
+			}
+
+			RenderList::Element *ec;
+			if (duplicate) {
+
+				ec = render_list->add_element();
+				memcpy(ec,e,sizeof(RenderList::Element));
+			} else {
+
+				ec=e;
+				duplicate=true;
+			}
+
+			ec->light_type=light_type;
+			ec->light=sort_key;
+			ec->additive_ptr=&e->additive;
+
+		}
+
+
+		const RID *liptr = p_instance->light_instances.ptr();
+		int ilc=p_instance->light_instances.size();
+
+
+
+		for(int i=0;i<ilc;i++) {
+
+			LightInstance *li=light_instance_owner.get( liptr[i] );
+			if (!li || li->last_pass!=scene_pass) //lit by light not in visible scene
+				continue;
+			uint8_t light_type=li->base->type|0x40; //penalty to ensure directionals always go first
+			if (li->base->shadow_enabled) {
+				light_type|=0x8;
+			}
+			uint16_t sort_key =li->sort_key;
+
+			RenderList::Element *ec;
+			if (duplicate) {
+
+				ec = render_list->add_element();
+				memcpy(ec,e,sizeof(RenderList::Element));
+			} else {
+
+				duplicate=true;
+				ec=e;
+			}
+
+			ec->light_type=light_type;
+			ec->light=sort_key;
+			ec->additive_ptr=&e->additive;
+
+		}
+
+
+
+	}
+
+#endif
+}
+
+void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){
+
+
+	//fill up ubo
+
+	store_camera(p_cam_projection,state.ubo_data.projection_matrix);
+	store_transform(p_cam_transform,state.ubo_data.camera_matrix);
+	store_transform(p_cam_transform.affine_inverse(),state.ubo_data.camera_inverse_matrix);
+	for(int i=0;i<4;i++) {
+		state.ubo_data.time[i]=storage->frame.time[i];
+	}
+
+
+	glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
+	glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data);
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+
+	render_list.clear();
+
+	render_pass++;
+	current_material_index=0;
+
+	//fill list
+
+	for(int i=0;i<p_cull_count;i++) {
+
+		InstanceBase *inst = p_cull_result[i];
+		switch(inst->base_type) {
+
+			case VS::INSTANCE_MESH: {
+
+				RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(inst->base);
+				ERR_CONTINUE(!mesh);
+
+				int ssize = mesh->surfaces.size();
+
+				for (int i=0;i<ssize;i++) {
+
+					int mat_idx = inst->materials[i].is_valid() ? i : -1;
+					RasterizerStorageGLES3::Surface *s = mesh->surfaces[i];
+					_add_geometry(s,inst,NULL,mat_idx);
+				}
+
+				//mesh->last_pass=frame;
+
+			} break;
+			case VS::INSTANCE_MULTIMESH: {
+
+			} break;
+			case VS::INSTANCE_IMMEDIATE: {
+
+			} break;
+
+		}
+	}
+
+	//
+
+
+	glEnable(GL_BLEND);
+	glDepthMask(GL_TRUE);
+	glEnable(GL_DEPTH_TEST);
+	glDisable(GL_SCISSOR_TEST);
+	glClearDepth(1.0);
+	glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo);
+
+
+	if (true) {
+
+		if (storage->frame.clear_request) {
+
+			glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a );
+			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+			storage->frame.clear_request=false;
+
+		}
+	}
+
+	state.current_depth_test=true;
+	state.current_depth_mask=true;
+	state.texscreen_copied=false;
+
+	glBlendEquation(GL_FUNC_ADD);
+
+	if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	} else {
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	}
+
+	glDisable(GL_BLEND);
+	//current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
+
+
+	render_list.sort_by_key(false);
+
+	//_render_list_forward(&opaque_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting);
+/*
+	if (draw_tex_background) {
+
+		//most 3D vendors recommend drawing a texture bg or skybox here,
+		//after opaque geometry has been drawn
+		//so the zbuffer can get rid of most pixels
+		_draw_tex_bg();
+	}
+*/
+	if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	} else {
+		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	}
+
+//	glDisable(GL_BLEND);
+//	current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;
+//	state.scene_shader.set_conditional(SceneShaderGLES3::USE_GLOW,false);
+//	if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+//		glColorMask(1,1,1,0); //don't touch alpha
+//	}
+
+
+	_render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,false,false);
+
+	//_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true);
+	//glColorMask(1,1,1,1);
+
+//	state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false);
+
+	glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+#if 0
+	if (use_fb) {
+
+
+
+		for(int i=0;i<VS::ARRAY_MAX;i++) {
+			glDisableVertexAttribArray(i);
+		}
+		glBindBuffer(GL_ARRAY_BUFFER,0);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
+		glDisable(GL_BLEND);
+		glDisable(GL_DEPTH_TEST);
+		glDisable(GL_CULL_FACE);
+		glDisable(GL_SCISSOR_TEST);
+		glDepthMask(false);
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) {
+
+			int hdr_tm = current_env->fx_param[VS::ENV_FX_PARAM_HDR_TONEMAPPER];
+			switch(hdr_tm) {
+				case VS::ENV_FX_HDR_TONE_MAPPER_LINEAR: {
+
+
+				} break;
+				case VS::ENV_FX_HDR_TONE_MAPPER_LOG: {
+					copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,true);
+
+				} break;
+				case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT: {
+					copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true);
+				} break;
+				case VS::ENV_FX_HDR_TONE_MAPPER_REINHARDT_AUTOWHITE: {
+
+					copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,true);
+					copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,true);
+				} break;
+			}
+
+
+			_process_hdr();
+		}
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+			_process_glow_bloom();
+			int glow_transfer_mode=current_env->fx_param[VS::ENV_FX_PARAM_GLOW_BLUR_BLEND_MODE];
+			if (glow_transfer_mode==1)
+				copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,true);
+			if (glow_transfer_mode==2)
+				copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,true);
+		}
+
+		glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer);
+
+		Size2 size;
+		if (current_rt) {
+			glBindFramebuffer(GL_FRAMEBUFFER, current_rt->fbo);
+			glViewport( 0,0,viewport.width,viewport.height);
+			size=Size2(viewport.width,viewport.height);
+		} else {
+			glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
+			glViewport( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height );
+			size=Size2(viewport.width,viewport.height);
+		}
+
+		//time to copy!!!
+		copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,current_env && current_env->fx_enabled[VS::ENV_FX_BCS]);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,current_env && current_env->fx_enabled[VS::ENV_FX_HDR]);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,true);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,current_env && current_env->fx_enabled[VS::ENV_FX_FXAA]);
+
+		copy_shader.bind();
+		//copy_shader.set_uniform(CopyShaderGLES2::SOURCE,0);
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) {
+
+			glActiveTexture(GL_TEXTURE1);
+			glBindTexture(GL_TEXTURE_2D, framebuffer.blur[0].color );
+			glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::GLOW_SOURCE),1);
+
+		}
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR]) {
+
+			glActiveTexture(GL_TEXTURE2);
+			glBindTexture(GL_TEXTURE_2D, current_vd->lum_color );
+			glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::HDR_SOURCE),2);
+			copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_EXPOSURE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_EXPOSURE]));
+			copy_shader.set_uniform(CopyShaderGLES2::TONEMAP_WHITE,float(current_env->fx_param[VS::ENV_FX_PARAM_HDR_WHITE]));
+
+		}
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_FXAA])
+			copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Size2(1.0/size.x,1.0/size.y));
+
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_BCS]) {
+
+			Vector3 bcs;
+			bcs.x=current_env->fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS];
+			bcs.y=current_env->fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST];
+			bcs.z=current_env->fx_param[VS::ENV_FX_PARAM_BCS_SATURATION];
+			copy_shader.set_uniform(CopyShaderGLES2::BCS,bcs);
+		}
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, framebuffer.color );
+		glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0);
+
+		_copy_screen_quad();
+
+		copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_FXAA,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_REINHARDT_TONEMAPPER,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_AUTOWHITE,false);
+		copy_shader.set_conditional(CopyShaderGLES2::USE_LOG_TONEMAPPER,false);
+
+		state.scene_shader.set_conditional(SceneShaderGLES3::USE_8BIT_HDR,false);
+
+
+		if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR] && GLOBAL_DEF("rasterizer/debug_hdr",false)) {
+			_debug_luminances();
+		}
+	}
+
+	current_env=NULL;
+	current_debug=VS::SCENARIO_DEBUG_DISABLED;
+	if (GLOBAL_DEF("rasterizer/debug_shadow_maps",false)) {
+		_debug_shadows();
+	}
+//	_debug_luminances();
+//	_debug_samplers();
+
+	if (using_canvas_bg) {
+		using_canvas_bg=false;
+		glColorMask(1,1,1,1); //don't touch alpha
+	}
+#endif
+}
+
+bool RasterizerSceneGLES3::free(RID p_rid) {
+
+	return false;
+
+}
+
+void RasterizerSceneGLES3::initialize() {
+
+	state.scene_shader.init();
+
+	default_shader = storage->shader_create(VS::SHADER_SPATIAL);
+	default_material = storage->material_create();
+	storage->material_set_shader(default_material,default_shader);
+
+	glGenBuffers(1, &state.scene_ubo);
+	glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW);
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+	render_list.max_elements=GLOBAL_DEF("rendering/gles3/max_renderable_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS);
+	if (render_list.max_elements>1000000)
+		render_list.max_elements=1000000;
+	if (render_list.max_elements<1024)
+		render_list.max_elements=1024;
+
+	render_list.init();
+}
+
+void RasterizerSceneGLES3::finalize(){
+
+
+}
+
+
+RasterizerSceneGLES3::RasterizerSceneGLES3()
+{
+
+}

+ 178 - 0
drivers/gles3/rasterizer_scene_gles3.h

@@ -0,0 +1,178 @@
+#ifndef RASTERIZERSCENEGLES3_H
+#define RASTERIZERSCENEGLES3_H
+
+#include "rasterizer_storage_gles3.h"
+#include "drivers/gles3/shaders/scene.glsl.h"
+
+class RasterizerSceneGLES3 : public RasterizerScene {
+public:
+
+	uint64_t render_pass;
+	uint32_t current_material_index;
+	uint32_t current_geometry_index;
+
+	RID default_material;
+	RID default_shader;
+
+	RasterizerStorageGLES3 *storage;
+
+
+
+	struct State {
+
+		bool current_depth_test;
+		bool current_depth_mask;
+		bool texscreen_copied;
+		int current_blend_mode;
+
+		SceneShaderGLES3 scene_shader;
+
+
+		struct SceneDataUBO {
+
+			float projection_matrix[16];
+			float camera_inverse_matrix[16];
+			float camera_matrix[16];
+			float time[4];
+			float ambient_light[4];
+
+		} ubo_data;
+
+		GLuint scene_ubo;
+
+
+
+	} state;
+
+	struct RenderList {
+
+		enum {
+			DEFAULT_MAX_ELEMENTS=65536,
+			MAX_LIGHTS=4,
+			SORT_FLAG_SKELETON=1,
+			SORT_FLAG_INSTANCING=2,
+
+			SORT_KEY_DEPTH_LAYER_SHIFT=58,
+			SORT_KEY_LIGHT_TYPE_SHIFT=54, //type is most important
+			SORT_KEY_LIGHT_INDEX_SHIFT=38, //type is most important
+			SORT_KEY_MATERIAL_INDEX_SHIFT=22,
+			SORT_KEY_GEOMETRY_INDEX_SHIFT=6,
+			SORT_KEY_GEOMETRY_TYPE_SHIFT=2,
+			SORT_KEY_SKELETON_FLAG=2,
+			SORT_KEY_MIRROR_FLAG=1
+
+		};
+
+		int max_elements;
+
+		struct Element {
+
+			RasterizerScene::InstanceBase *instance;
+			RasterizerStorageGLES3::Geometry *geometry;
+			RasterizerStorageGLES3::Material *material;
+			RasterizerStorageGLES3::GeometryOwner *owner;
+			uint64_t sort_key;
+			bool *additive_ptr;
+			bool additive;
+
+		};
+
+
+		Element *_elements;
+		Element **elements;
+
+		int element_count;
+		int alpha_element_count;
+
+		void clear() {
+
+			element_count=0;
+			alpha_element_count=0;
+		}
+
+		//should eventually be replaced by radix
+
+		struct SortByKey {
+
+			_FORCE_INLINE_ bool operator()(const Element* A,  const Element* B ) const {
+				return A->sort_key < B->sort_key;
+			}
+		};
+
+		void sort_by_key(bool p_alpha) {
+
+			SortArray<Element*,SortByKey> sorter;
+			if (p_alpha) {
+				sorter.sort(&elements[max_elements-alpha_element_count-1],alpha_element_count);
+			} else {
+				sorter.sort(elements,element_count);
+			}
+		}
+
+
+		_FORCE_INLINE_ Element* add_element() {
+
+			if (element_count+alpha_element_count>=max_elements)
+				return NULL;
+			elements[element_count]=&_elements[element_count];
+			return elements[element_count++];
+		}
+
+		_FORCE_INLINE_ Element* add_alpha_element() {
+
+			if (element_count+alpha_element_count>=max_elements)
+				return NULL;
+			int idx = max_elements-alpha_element_count-1;
+			elements[idx]=&_elements[idx];
+			alpha_element_count++;
+			return elements[idx];
+		}
+
+		void init() {
+
+			element_count = 0;
+			alpha_element_count =0;
+			elements=memnew_arr(Element*,max_elements);
+			_elements=memnew_arr(Element,max_elements);
+			for (int i=0;i<max_elements;i++)
+				elements[i]=&_elements[i]; // assign elements
+
+		}
+
+		RenderList() {
+
+			max_elements=DEFAULT_MAX_ELEMENTS;
+		}
+
+		~RenderList() {
+			memdelete_arr(elements);
+			memdelete_arr(_elements);
+		}
+	};
+
+
+
+	RenderList render_list;
+
+	_FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass);
+	_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
+	_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
+
+
+	void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, bool p_reverse_cull, bool p_alpha_pass);
+
+	virtual RID light_instance_create(RID p_light);
+	virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
+
+	_FORCE_INLINE_ void _add_geometry(  RasterizerStorageGLES3::Geometry* p_geometry,  InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material);
+
+	virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment);
+
+	virtual bool free(RID p_rid);
+
+	void initialize();
+	void finalize();
+	RasterizerSceneGLES3();
+};
+
+#endif // RASTERIZERSCENEGLES3_H

+ 702 - 18
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1,5 +1,6 @@
 #include "rasterizer_storage_gles3.h"
 #include "rasterizer_canvas_gles3.h"
+#include "rasterizer_scene_gles3.h"
 #include "globals.h"
 
 /* TEXTURE API */
@@ -1039,7 +1040,7 @@ void RasterizerStorageGLES3::shader_set_mode(RID p_shader,VS::ShaderMode p_mode)
 
 	ShaderGLES3* shaders[VS::SHADER_MAX]={
 		&canvas->state.canvas_shader,
-		&canvas->state.canvas_shader,
+		&scene->state.scene_shader,
 		&canvas->state.canvas_shader,
 
 	};
@@ -1108,6 +1109,37 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 			actions->uniforms=&p_shader->uniforms;
 
 		} break;
+
+		case VS::SHADER_SPATIAL: {
+
+			p_shader->spatial.blend_mode=Shader::Spatial::BLEND_MODE_MIX;
+			p_shader->spatial.depth_draw_mode=Shader::Spatial::DEPTH_DRAW_OPAQUE;
+			p_shader->spatial.cull_mode=Shader::Spatial::CULL_MODE_BACK;
+			p_shader->spatial.uses_alpha=false;
+			p_shader->spatial.unshaded=false;
+			p_shader->spatial.ontop=false;
+
+			shaders.actions_scene.render_mode_values["blend_add"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD);
+			shaders.actions_scene.render_mode_values["blend_mix"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX);
+			shaders.actions_scene.render_mode_values["blend_sub"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_SUB);
+			shaders.actions_scene.render_mode_values["blend_mul"]=Pair<int*,int>(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MUL);
+
+			shaders.actions_scene.render_mode_values["depth_draw_opaque"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_OPAQUE);
+			shaders.actions_scene.render_mode_values["depth_draw_always"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALWAYS);
+			shaders.actions_scene.render_mode_values["depth_draw_never"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_NEVER);
+			shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"]=Pair<int*,int>(&p_shader->spatial.depth_draw_mode,Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS);
+
+			shaders.actions_scene.render_mode_values["cull_front"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT);
+			shaders.actions_scene.render_mode_values["cull_back"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK);
+			shaders.actions_scene.render_mode_values["cull_disable"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED);
+
+			shaders.actions_canvas.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded;
+			shaders.actions_canvas.render_mode_flags["ontop"]=&p_shader->spatial.ontop;
+
+			shaders.actions_canvas.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
+
+		}
+
 	}
 
 
@@ -1905,97 +1937,685 @@ void RasterizerStorageGLES3::update_dirty_materials() {
 
 RID RasterizerStorageGLES3::mesh_create(){
 
-	return RID();
+	Mesh * mesh = memnew( Mesh );
+
+	return mesh_owner.make_rid(mesh);
 }
 
-void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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 Vector<DVector<uint8_t> >& p_blend_shapes){
 
+void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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,const Vector<AABB>& p_bone_aabbs){
+
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+	ERR_FAIL_COND(!(p_format&VS::ARRAY_FORMAT_VERTEX));
+
+	//must have index and bones, both.
+	{
+		uint32_t bones_weight = VS::ARRAY_FORMAT_BONES|VS::ARRAY_FORMAT_WEIGHTS;
+		ERR_EXPLAIN("Array must have both bones and weights in format or none.");
+		ERR_FAIL_COND( (p_format&bones_weight) && (p_format&bones_weight)!=bones_weight );
+	}
+
+
+	bool has_morph = p_blend_shapes.size();
+
+	Surface::Attrib attribs[VS::ARRAY_MAX],morph_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;
+			continue;
+		}
+
+		attribs[i].enabled=true;
+		attribs[i].offset=stride;
+		attribs[i].index=i;
+
+		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: {
+
+				if (p_format&VS::ARRAY_FLAG_USE_2D_VERTICES) {
+					attribs[i].size=2;
+				} else {
+					attribs[i].size=3;
+				}
+
+				if (p_format&VS::ARRAY_COMPRESS_VERTEX) {
+					attribs[i].type=GL_HALF_FLOAT;
+					stride+=attribs[i].size*2;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=attribs[i].size*4;
+				}
+
+				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: {
+
+				attribs[i].size=3;
+
+				if (p_format&VS::ARRAY_COMPRESS_NORMAL) {
+					attribs[i].type=GL_BYTE;
+					stride+=4; //pad extra byte
+					attribs[i].normalized=GL_TRUE;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=12;
+					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: {
+
+				attribs[i].size=4;
+
+				if (p_format&VS::ARRAY_COMPRESS_TANGENT) {
+					attribs[i].type=GL_BYTE;
+					stride+=4;
+					attribs[i].normalized=GL_TRUE;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=16;
+					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: {
+
+				attribs[i].size=4;
+
+				if (p_format&VS::ARRAY_COMPRESS_COLOR) {
+					attribs[i].type=GL_UNSIGNED_BYTE;
+					stride+=4;
+					attribs[i].normalized=GL_TRUE;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=16;
+					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: {
+
+				attribs[i].size=2;
+
+				if (p_format&VS::ARRAY_COMPRESS_TEX_UV) {
+					attribs[i].type=GL_HALF_FLOAT;
+					stride+=4;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=8;
+				}
+
+				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: {
+
+				attribs[i].size=2;
+
+				if (p_format&VS::ARRAY_COMPRESS_TEX_UV2) {
+					attribs[i].type=GL_HALF_FLOAT;
+					stride+=4;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=8;
+				}
+				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: {
+
+				attribs[i].size=4;
+
+				if (p_format&VS::ARRAY_COMPRESS_BONES) {
+
+					if (p_format&VS::ARRAY_FLAG_USE_16_BIT_BONES) {
+						attribs[i].type=GL_UNSIGNED_SHORT;
+						stride+=8;
+					} else {
+						attribs[i].type=GL_UNSIGNED_BYTE;
+						stride+=4;
+					}
+				} else {
+					attribs[i].type=GL_UNSIGNED_SHORT;
+					stride+=8;
+				}
+
+				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_UNSIGNED_SHORT;
+					morph_stride+=8;
+				}
+
+			} break;
+			case VS::ARRAY_WEIGHTS: {
+
+				attribs[i].size=4;
+
+				if (p_format&VS::ARRAY_COMPRESS_WEIGHTS) {
+
+					attribs[i].type=GL_UNSIGNED_SHORT;
+					stride+=8;
+					attribs[i].normalized=GL_TRUE;
+				} else {
+					attribs[i].type=GL_FLOAT;
+					stride+=16;
+					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: {
+
+				attribs[i].size=1;
+
+				if (p_vertex_count>=(1<<16)) {
+					attribs[i].type=GL_UNSIGNED_INT;
+					attribs[i].stride=4;
+				} else {
+					attribs[i].type=GL_UNSIGNED_SHORT;
+					attribs[i].stride=2;
+				}
+
+				attribs[i].normalized=GL_FALSE;
+
+			} break;
+
+		}
+	}
+
+	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
+
+	int array_size = stride * p_vertex_count;
+	int index_array_size=0;
+
+	ERR_FAIL_COND(p_array.size()!=array_size);
+
+	if (p_format&VS::ARRAY_FORMAT_INDEX) {
+
+		index_array_size=attribs[VS::ARRAY_INDEX].stride*p_index_count;
+
+		print_line("index count: "+itos(p_index_count)+" stride: "+itos(attribs[VS::ARRAY_INDEX].stride) );
+	}
+
+
+	ERR_FAIL_COND(p_index_array.size()!=index_array_size);
+
+	ERR_FAIL_COND(p_blend_shapes.size()!=mesh->morph_target_count);
+
+	for(int i=0;i<p_blend_shapes.size();i++) {
+		ERR_FAIL_COND(p_blend_shapes[i].size()!=array_size);
+	}
+
+	//ok all valid, create stuff
+
+	Surface * surface = memnew( Surface );
+
+	surface->active=true;
+	surface->array_len=p_vertex_count;
+	surface->index_array_len=p_index_count;
+	surface->primitive=p_primitive;
+	surface->mesh=mesh;
+	surface->format=p_format;
+	surface->skeleton_bone_aabb=p_bone_aabbs;
+	surface->skeleton_bone_used.resize(surface->skeleton_bone_aabb.size());
+	surface->aabb=p_aabb;
+	surface->max_bone=p_bone_aabbs.size();
+
+	for(int i=0;i<surface->skeleton_bone_used.size();i++) {
+		if (surface->skeleton_bone_aabb[i].size.x<0 || surface->skeleton_bone_aabb[i].size.y<0 || surface->skeleton_bone_aabb[i].size.z<0) {
+			surface->skeleton_bone_used[i]=false;
+		} else {
+			surface->skeleton_bone_used[i]=true;
+		}
+	}
+
+	for(int i=0;i<VS::ARRAY_MAX;i++) {
+		surface->attribs[i]=attribs[i];
+		surface->morph_attribs[i]=morph_attribs[i];
+	}
+
+	{
+
+		DVector<uint8_t>::Read vr = p_array.read();
+
+		glGenBuffers(1,&surface->vertex_id);
+		glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+		glBufferData(GL_ARRAY_BUFFER,array_size,vr.ptr(),GL_STATIC_DRAW);
+		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+
+		if (p_format&VS::ARRAY_FORMAT_INDEX) {
+
+			DVector<uint8_t>::Read ir = p_index_array.read();
+
+			glGenBuffers(1,&surface->index_id);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+			glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_size,ir.ptr(),GL_STATIC_DRAW);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind
+		}
 
+		//generate arrays for faster state switching
+
+		glGenVertexArrays(1,&surface->array_id);
+		glBindVertexArray(surface->array_id);
+		glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+
+		for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+			if (!attribs[i].enabled)
+				continue;
+
+			glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+			glEnableVertexAttribArray(attribs[i].index);
+
+		}
+
+		if (surface->index_id) {
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+		}
+
+		glBindVertexArray(0);
+		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+	}
+
+	{
+
+		//blend shapes
+
+		for(int i=0;i<p_blend_shapes.size();i++) {
+
+			Surface::MorphTarget mt;
+
+			DVector<uint8_t>::Read vr = p_blend_shapes[i].read();
+
+			glGenBuffers(1,&mt.vertex_id);
+			glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id);
+			glBufferData(GL_ARRAY_BUFFER,array_size,vr.ptr(),GL_STATIC_DRAW);
+			glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+			glGenVertexArrays(1,&mt.array_id);
+			glBindVertexArray(mt.array_id);
+			glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id);
+
+			for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+				if (!attribs[i].enabled)
+					continue;
+
+				glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+				glEnableVertexAttribArray(attribs[i].index);
+
+			}
+
+			glBindVertexArray(0);
+			glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+
+			surface->morph_targets.push_back(mt);
+
+		}
+	}
+
+	mesh->surfaces.push_back(surface);
+	mesh->instance_change_notify();
 }
 
 void RasterizerStorageGLES3::mesh_set_morph_target_count(RID p_mesh,int p_amount){
 
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+
+	ERR_FAIL_COND(mesh->surfaces.size()!=0);
+	ERR_FAIL_COND(p_amount<0);
+
+	mesh->morph_target_count=p_amount;
 
 }
 int RasterizerStorageGLES3::mesh_get_morph_target_count(RID p_mesh) const{
 
-	return 0;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,0);
+
+	return mesh->morph_target_count;
 }
 
 
 void RasterizerStorageGLES3::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode){
 
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
+
+	mesh->morph_target_mode=p_mode;
 
 }
 VS::MorphTargetMode RasterizerStorageGLES3::mesh_get_morph_target_mode(RID p_mesh) const{
 
-	return VS::MORPH_MODE_NORMALIZED;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,VS::MORPH_MODE_NORMALIZED);
+
+	return mesh->morph_target_mode;
 }
 
 void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material){
 
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
+
+	mesh->surfaces[p_surface]->material=p_material;
 
 }
 RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{
 
-	return RID();
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,RID());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),RID());
+
+	return mesh->surfaces[p_surface]->material;
 }
 
 int RasterizerStorageGLES3::mesh_surface_get_array_len(RID p_mesh, int p_surface) const{
 
-	return 0;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,0);
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
+
+	return mesh->surfaces[p_surface]->array_len;
+
 }
 int RasterizerStorageGLES3::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const{
 
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,0);
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
 
-	return 0;
+	return mesh->surfaces[p_surface]->index_array_len;
 }
 
 DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int p_surface) const{
 
-	return DVector<uint8_t>();
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,DVector<uint8_t>());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector<uint8_t>());
+
+	Surface *surface = mesh->surfaces[p_surface];
+
+	glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+	void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_len,GL_MAP_READ_BIT);
+
+	ERR_FAIL_COND_V(!data,DVector<uint8_t>());
+
+	DVector<uint8_t> ret;
+	ret.resize(surface->array_len);
+
+	{
+
+		DVector<uint8_t>::Write w = ret.write();
+		copymem(w.ptr(),data,surface->array_len);
+	}
+	glUnmapBuffer(GL_ARRAY_BUFFER);
+
+
+	return ret;
 }
-DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const{
 
+DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const {
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,DVector<uint8_t>());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),DVector<uint8_t>());
+
+	Surface *surface = mesh->surfaces[p_surface];
+
+	ERR_FAIL_COND_V(surface->index_array_len==0,DVector<uint8_t>());
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->vertex_id);
+	void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_len,GL_MAP_READ_BIT);
+
+	ERR_FAIL_COND_V(!data,DVector<uint8_t>());
+
+	DVector<uint8_t> ret;
+	ret.resize(surface->index_array_len);
+
+	{
+
+		DVector<uint8_t>::Write w = ret.write();
+		copymem(w.ptr(),data,surface->index_array_len);
+	}
+
+	glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
 
-	return DVector<uint8_t>();
+	return ret;
 }
 
 
 uint32_t RasterizerStorageGLES3::mesh_surface_get_format(RID p_mesh, int p_surface) const{
 
-	return 0;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+
+	ERR_FAIL_COND_V(!mesh,0);
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),0);
+
+	return mesh->surfaces[p_surface]->format;
+
 }
+
 VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const{
 
-	return VS::PRIMITIVE_MAX;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,VS::PRIMITIVE_MAX);
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),VS::PRIMITIVE_MAX);
+
+	return mesh->surfaces[p_surface]->primitive;
 }
 
-void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh,int p_index){
+void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
+
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
+	ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
 
+	Surface *surface = mesh->surfaces[p_surface];
 
+	ERR_FAIL_COND(surface->index_array_len==0);
+
+	glDeleteBuffers(1,&surface->array_id);
+	if (surface->index_id) {
+		glDeleteBuffers(1,&surface->index_id);
+	}
+
+	glDeleteVertexArrays(1,&surface->array_id);
+
+	for(int i=0;i<surface->morph_targets.size();i++) {
+
+		glDeleteBuffers(1,&surface->morph_targets[i].vertex_id);
+		glDeleteVertexArrays(1,&surface->morph_targets[i].array_id);
+	}
+
+	memdelete(surface);
+
+	mesh->surfaces.remove(p_surface);
+
+	mesh->instance_change_notify();
 }
 int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const{
 
-	return 0;
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,0);
+	return mesh->surfaces.size();
+
 }
 
 void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb){
 
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
 
+	mesh->custom_aabb=p_aabb;
 }
 AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const{
 
-	return AABB();
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,AABB());
+
+	return mesh->custom_aabb;
+
 }
 
-AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh) const{
+AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
+
+	Mesh *mesh = mesh_owner.get( p_mesh );
+	ERR_FAIL_COND_V(!mesh,AABB());
+
+	if (mesh->custom_aabb!=AABB())
+		return mesh->custom_aabb;
+/*
+	Skeleton *sk=NULL;
+	if (p_skeleton.is_valid())
+		sk=skeleton_owner.get(p_skeleton);
+*/
+	AABB aabb;
+	/*
+	if (sk && sk->bones.size()!=0) {
+
+
+		for (int i=0;i<mesh->surfaces.size();i++) {
+
+			AABB laabb;
+			if (mesh->surfaces[i]->format&VS::ARRAY_FORMAT_BONES && mesh->surfaces[i]->skeleton_bone_aabb.size()) {
+
+
+				int bs = mesh->surfaces[i]->skeleton_bone_aabb.size();
+				const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr();
+				const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
+
+				int sbs = sk->bones.size();
+				ERR_CONTINUE(bs>sbs);
+				Skeleton::Bone *skb = sk->bones.ptr();
+
+				bool first=true;
+				for(int j=0;j<bs;j++) {
+
+					if (!skused[j])
+						continue;
+					AABB baabb = skb[ j ].transform_aabb ( skbones[j] );
+					if (first) {
+						laabb=baabb;
+						first=false;
+					} else {
+						laabb.merge_with(baabb);
+					}
+				}
+
+			} else {
+
+				laabb=mesh->surfaces[i]->aabb;
+			}
+
+			if (i==0)
+				aabb=laabb;
+			else
+				aabb.merge_with(laabb);
+		}
+	} else {
+*/
+		for (int i=0;i<mesh->surfaces.size();i++) {
+
+			if (i==0)
+				aabb=mesh->surfaces[i]->aabb;
+			else
+				aabb.merge_with(mesh->surfaces[i]->aabb);
+		}
+/*
+	}
+*/
+	return aabb;
 
-	return AABB();
 }
 void RasterizerStorageGLES3::mesh_clear(RID p_mesh){
 
+	Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND(!mesh);
 
+	while(mesh->surfaces.size()) {
+		mesh_remove_surface(p_mesh,0);
+	}
 }
 
 /* MULTIMESH API */
@@ -2206,6 +2826,16 @@ void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::L
 
 }
 
+VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
+
+	return VS::LIGHT_DIRECTIONAL;
+}
+
+AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const {
+
+	return AABB();
+}
+
 /* PROBE API */
 
 RID RasterizerStorageGLES3::reflection_probe_create(){
@@ -2292,6 +2922,42 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color
 
 }
 
+void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance) {
+
+	Instantiable *inst=NULL;
+	switch(p_instance->base_type) {
+		case VS::INSTANCE_MESH: {
+			inst = mesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
+		default: {
+			ERR_FAIL();
+		}
+	}
+
+	inst->instance_list.add( &p_instance->dependency_item );
+}
+
+void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance){
+
+	Instantiable *inst=NULL;
+
+	switch(p_instance->base_type) {
+		case VS::INSTANCE_MESH: {
+			inst = mesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+
+		} break;
+		default: {
+			ERR_FAIL();
+		}
+	}
+
+	ERR_FAIL_COND(!inst);
+
+	inst->instance_list.remove( &p_instance->dependency_item );
+}
+
 
 /* RENDER TARGET */
 
@@ -2773,6 +3439,15 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder,
 
 }
 
+VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
+
+	if (mesh_owner.owns(p_rid)) {
+		return VS::INSTANCE_MESH;
+	}
+
+	return VS::INSTANCE_NONE;
+}
+
 bool RasterizerStorageGLES3::free(RID p_rid){
 
 	if (render_target_owner.owns(p_rid)) {
@@ -2834,6 +3509,15 @@ bool RasterizerStorageGLES3::free(RID p_rid){
 		material_owner.free(p_rid);
 		memdelete(material);
 
+	} else if (mesh_owner.owns(p_rid)) {
+
+		// delete the texture
+		Mesh *mesh = mesh_owner.get(p_rid);
+
+		mesh_clear(p_rid);
+
+		mesh_owner.free(p_rid);
+		memdelete(mesh);
 
 	} else if (canvas_occluder_owner.owns(p_rid)) {
 

+ 197 - 3
drivers/gles3/rasterizer_storage_gles3.h

@@ -10,12 +10,14 @@
 #include "shader_compiler_gles3.h"
 
 class RasterizerCanvasGLES3;
+class RasterizerSceneGLES3;
 
 
 class RasterizerStorageGLES3 : public RasterizerStorage {
 public:
 
 	RasterizerCanvasGLES3 *canvas;
+	RasterizerSceneGLES3 *scene;
 
 	enum FBOFormat {
 		FBO_FORMAT_16_BITS,
@@ -59,6 +61,7 @@ public:
 		ShaderCompilerGLES3 compiler;
 
 		ShaderCompilerGLES3::IdentifierActions actions_canvas;
+		ShaderCompilerGLES3::IdentifierActions actions_scene;
 	} shaders;
 
 	struct Resources {
@@ -230,6 +233,40 @@ public:
 
 		} canvas_item;
 
+		struct Spatial {
+
+			enum BlendMode {
+				BLEND_MODE_MIX,
+				BLEND_MODE_ADD,
+				BLEND_MODE_SUB,
+				BLEND_MODE_MUL,
+			};
+
+			int blend_mode;
+
+			enum DepthDrawMode {
+				DEPTH_DRAW_OPAQUE,
+				DEPTH_DRAW_ALWAYS,
+				DEPTH_DRAW_NEVER,
+				DEPTH_DRAW_ALPHA_PREPASS,
+			};
+
+			int depth_draw_mode;
+
+			enum CullMode {
+				CULL_MODE_FRONT,
+				CULL_MODE_BACK,
+				CULL_MODE_DISABLED,
+			};
+
+			int cull_mode;
+
+			bool uses_alpha;
+			bool unshaded;
+			bool ontop;
+
+		} spatial;
+
 		Shader() : dirty_list(this) {
 
 			shader=NULL;
@@ -272,10 +309,14 @@ public:
 		SelfList<Material> dirty_list;
 		Vector<RID> textures;
 
+		uint32_t index;
+		uint64_t last_pass;
+
 		Material() : list(this), dirty_list(this) {
 			shader=NULL;
 			ubo_id=0;
 			ubo_size=0;
+			last_pass=0;
 		}
 
 	};
@@ -300,9 +341,155 @@ public:
 
 	/* MESH API */
 
+	struct Instantiable : public RID_Data {
+
+		enum Type {
+			GEOMETRY_INVALID,
+			GEOMETRY_SURFACE,
+			GEOMETRY_IMMEDIATE,
+			GEOMETRY_MULTISURFACE,
+		};
+
+		SelfList<RasterizerScene::InstanceBase>::List instance_list;
+
+		_FORCE_INLINE_ void instance_change_notify() {
+
+			SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+			while(instances) {
+
+				instances->self()->base_changed();
+				instances=instances->next();
+			}
+		}
+
+		Instantiable() {  }
+		virtual ~Instantiable() {
+
+			while(instance_list.first()) {
+				instance_list.first()->self()->base_removed();
+			}
+		}
+	};
+
+	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 {
+
+		struct Attrib {
+
+			bool enabled;
+			GLuint index;
+			GLint size;
+			GLenum type;
+			GLboolean normalized;
+			GLsizei stride;
+			uint32_t offset;
+		};
+
+		Attrib attribs[VS::ARRAY_MAX];
+		Attrib morph_attribs[VS::ARRAY_MAX];
+
+
+		Mesh *mesh;
+		uint32_t format;
+
+		GLuint array_id;
+		GLuint vertex_id;
+		GLuint index_id;
+
+		Vector<AABB> skeleton_bone_aabb;
+		Vector<bool> skeleton_bone_used;
+
+		//bool packed;
+
+		struct MorphTarget {
+			GLuint vertex_id;
+			GLuint array_id;
+		};
+
+		Vector<MorphTarget> morph_targets;
+
+		AABB aabb;
+
+		int array_len;
+		int index_array_len;
+		int max_bone;
+
+		int array_bytes;
+
+
+		VS::PrimitiveType primitive;
+
+		bool active;
+
+		Surface() {
+
+			array_bytes=0;
+			mesh=NULL;
+			format=0;
+			array_id=0;
+			vertex_id=0;
+			index_id=0;
+			array_len=0;
+			type=GEOMETRY_SURFACE;
+			primitive=VS::PRIMITIVE_POINTS;
+			index_array_len=0;
+			active=false;
+
+		}
+
+		~Surface() {
+
+		}
+	};
+
+
+	struct Mesh : public GeometryOwner {
+
+		bool active;
+		Vector<Surface*> surfaces;
+		int morph_target_count;
+		VS::MorphTargetMode morph_target_mode;
+		AABB custom_aabb;
+		mutable uint64_t last_pass;
+		Mesh() {
+			morph_target_mode=VS::MORPH_MODE_NORMALIZED;
+			morph_target_count=0;
+			last_pass=0;
+			active=false;
+		}
+	};
+
+	mutable RID_Owner<Mesh> mesh_owner;
+
 	virtual RID mesh_create();
 
-	virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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 Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >());
+	virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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>());
 
 	virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount);
 	virtual int mesh_get_morph_target_count(RID p_mesh) const;
@@ -324,13 +511,13 @@ public:
 	virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
 	virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
 
-	virtual void mesh_remove_surface(RID p_mesh,int p_index);
+	virtual void mesh_remove_surface(RID p_mesh, int p_surface);
 	virtual int mesh_get_surface_count(RID p_mesh) const;
 
 	virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
 	virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
 
-	virtual AABB mesh_get_aabb(RID p_mesh) const;
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const;
 	virtual void mesh_clear(RID p_mesh);
 
 	/* MULTIMESH API */
@@ -401,6 +588,8 @@ public:
 
 	virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode);
 
+	virtual VS::LightType light_get_type(RID p_light) const;
+	virtual AABB light_get_aabb(RID p_light) const;
 	/* PROBE API */
 
 	virtual RID reflection_probe_create();
@@ -434,6 +623,9 @@ public:
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color);
 
 
+	virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);
+	virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance);
+
 	/* RENDER TARGET */
 
 	struct RenderTarget : public RID_Data {
@@ -522,6 +714,8 @@ public:
 	virtual RID canvas_light_occluder_create();
 	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
 
+	virtual VS::InstanceType get_base_type(RID p_rid) const;
+
 	virtual bool free(RID p_rid);
 
 

+ 9 - 3
drivers/gles3/shader_gles3.cpp

@@ -662,8 +662,8 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
 			fragment_code0=code.ascii();
 		} else {
 			fragment_code0=code.substr(0,cpos).ascii();
-			code = code.substr(cpos+globals_tag.length(),code.length());
-
+			//print_line("CODE0:\n"+String(fragment_code0.get_data()));
+			code = code.substr(cpos+globals_tag.length(),code.length());			
 			cpos = code.find(material_tag);
 
 			if (cpos==-1) {
@@ -671,14 +671,18 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
 			} else {
 
 				fragment_code1=code.substr(0,cpos).ascii();
-				String code2 = code.substr(cpos+material_tag.length(),code.length());
+				//print_line("CODE1:\n"+String(fragment_code1.get_data()));
 
+				String code2 = code.substr(cpos+material_tag.length(),code.length());
 				cpos = code2.find(code_tag);
+
 				if (cpos==-1) {
 					fragment_code2=code2.ascii();
 				} else {
 
 					fragment_code2=code2.substr(0,cpos).ascii();
+					//print_line("CODE2:\n"+String(fragment_code2.get_data()));
+
 					String code3 = code2.substr(cpos+code_tag.length(),code2.length());
 
 					cpos = code3.find(light_code_tag);
@@ -687,7 +691,9 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
 					} else {
 
 						fragment_code3=code3.substr(0,cpos).ascii();
+					//	print_line("CODE3:\n"+String(fragment_code3.get_data()));
 						fragment_code4 = code3.substr(cpos+light_code_tag.length(),code3.length()).ascii();
+						//print_line("CODE4:\n"+String(fragment_code4.get_data()));
 					}
 				}
 			}

+ 1 - 0
drivers/gles3/shaders/SCsub

@@ -4,4 +4,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
 	env.GLES3_GLSL('copy.glsl');
 	env.GLES3_GLSL('canvas.glsl');
 	env.GLES3_GLSL('canvas_shadow.glsl');
+	env.GLES3_GLSL('scene.glsl');
 

+ 351 - 0
drivers/gles3/shaders/scene.glsl

@@ -0,0 +1,351 @@
+[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,
+*/
+
+//hack to use uv if no uv present so it works with lightmap
+
+
+/* INPUT ATTRIBS */
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=1) in vec3 normal_attrib;
+layout(location=2) in vec4 tangent_attrib;
+layout(location=3) in vec4 color_attrib;
+layout(location=4) in vec2 uv_attrib;
+layout(location=5) in vec2 uv2_attrib;
+
+uniform float normal_mult;
+
+#ifdef USE_SKELETON
+layout(location=6) mediump ivec4 bone_indices; // attrib:6
+layout(location=7) mediump vec4 bone_weights; // attrib:7
+uniform highp sampler2D skeleton_matrices;
+#endif
+
+#ifdef USE_ATTRIBUTE_INSTANCING
+
+layout(location=8) in highp vec4 instance_xform0;
+layout(location=9) in highp vec4 instance_xform1;
+layout(location=10) in highp vec4 instance_xform2;
+layout(location=11) in lowp vec4 instance_color;
+
+#endif
+
+layout(std140) uniform SceneData { //ubo:0
+
+	highp mat4 projection_matrix;
+	highp mat4 camera_inverse_matrix;
+	highp mat4 camera_matrix;
+	highp vec4 time;
+
+	highp vec4 ambient_light;
+};
+
+uniform highp mat4 world_transform;
+
+/* Varyings */
+
+out vec3 vertex_interp;
+out vec3 normal_interp;
+
+#if defined(ENABLE_COLOR_INTERP)
+out vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+out vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+out vec2 uv2_interp;
+#endif
+
+#if defined(ENABLE_VAR1_INTERP)
+out vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+out vec4 var2_interp;
+#endif
+
+#if defined(ENABLE_TANGENT_INTERP)
+out vec3 tangent_interp;
+out vec3 binormal_interp;
+#endif
+
+
+#if !defined(USE_DEPTH_SHADOWS) && defined(USE_SHADOW_PASS)
+
+varying vec4 position_interp;
+
+#endif
+
+#ifdef USE_SHADOW_PASS
+
+uniform highp float shadow_z_offset;
+uniform highp float shadow_z_slope_scale;
+
+#endif
+
+
+VERTEX_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData { //ubo:1
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+
+void main() {
+
+	highp vec4 vertex_in = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
+	highp mat4 modelview = camera_inverse_matrix * world_transform;
+	vec3 normal_in = normal_attrib;
+	normal_in*=normal_mult;
+#if defined(ENABLE_TANGENT_INTERP)
+	vec3 tangent_in = tangent_attrib.xyz;
+	tangent_in*=normal_mult;
+	float binormalf = tangent_attrib.a;
+#endif
+
+#ifdef USE_SKELETON
+
+	{
+		//skeleton transform
+		highp mat4 m=mat4(texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.x*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.x;
+		m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.y*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.y;
+		m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.z;
+		m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.w;
+
+		vertex_in = vertex_in * m;
+		normal_in = (vec4(normal_in,0.0) * m).xyz;
+#if defined(ENABLE_TANGENT_INTERP)
+		tangent_in = (vec4(tangent_in,0.0) * m).xyz;
+#endif
+	}
+
+#endif
+
+	vertex_interp = (modelview * vertex_in).xyz;
+	normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz);
+
+#if defined(ENABLE_TANGENT_INTERP)
+	tangent_interp=normalize((modelview * vec4(tangent_in,0.0)).xyz);
+	binormal_interp = normalize( cross(normal_interp,tangent_interp) * binormalf );
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+	color_interp = color_attrib;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+	uv_interp = uv_attrib;
+#endif
+#if defined(ENABLE_UV2_INTERP)
+	uv2_interp = uv2_attrib;
+#endif
+
+
+VERTEX_SHADER_CODE
+
+
+#ifdef USE_SHADOW_PASS
+
+	float z_ofs = shadow_z_offset;
+	z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
+	vertex_interp.z-=z_ofs;
+#endif
+
+
+#ifdef USE_FOG
+
+	fog_interp.a = pow( clamp( (length(vertex_interp)-fog_params.x)/(fog_params.y-fog_params.x), 0.0, 1.0 ), fog_params.z );
+	fog_interp.rgb = mix( fog_color_begin, fog_color_end, fog_interp.a );
+#endif
+
+#ifndef VERTEX_SHADER_WRITE_POSITION
+//vertex shader might write a position
+	gl_Position = projection_matrix * vec4(vertex_interp,1.0);
+#endif
+
+
+
+
+}
+
+
+[fragment]
+
+
+//hack to use uv if no uv present so it works with lightmap
+
+
+/* Varyings */
+
+#if defined(ENABLE_COLOR_INTERP)
+in vec4 color_interp;
+#endif
+
+#if defined(ENABLE_UV_INTERP)
+in vec2 uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+in vec2 uv2_interp;
+#endif
+
+#if defined(ENABLE_TANGENT_INTERP)
+in vec3 tangent_interp;
+in vec3 binormal_interp;
+#endif
+
+#if defined(ENABLE_VAR1_INTERP)
+in vec4 var1_interp;
+#endif
+
+#if defined(ENABLE_VAR2_INTERP)
+in vec4 var2_interp;
+#endif
+
+in vec3 vertex_interp;
+in vec3 normal_interp;
+
+
+/* Material Uniforms */
+
+
+FRAGMENT_SHADER_GLOBALS
+
+
+#if defined(USE_MATERIAL)
+
+layout(std140) uniform UniformData {
+
+MATERIAL_UNIFORMS
+
+};
+
+#endif
+
+
+layout(std140) uniform SceneData {
+
+	highp mat4 projection_matrix;
+	highp mat4 camera_inverse_matrix;
+	highp mat4 camera_matrix;
+	highp vec4 time;
+
+	highp vec4 ambient_light;
+};
+
+layout(location=0) out vec4 frag_color;
+
+void main() {
+
+	//lay out everything, whathever is unused is optimized away anyway
+	vec3 vertex = vertex_interp;
+	vec3 albedo = vec3(0.9,0.9,0.9);
+	vec3 metal = vec3(0.0,0.0,0.0);
+	float rough = 0.0;
+	float alpha = 1.0;
+
+#ifdef METERIAL_DOUBLESIDED
+	float side=float(gl_FrontFacing)*2.0-1.0;
+#else
+	float side=1.0;
+#endif
+
+
+#if defined(ENABLE_TANGENT_INTERP)
+	vec3 binormal = normalize(binormal_interp)*side;
+	vec3 tangent = normalize(tangent_interp)*side;
+#endif
+	vec3 normal = normalize(normal_interp)*side;
+
+#if defined(ENABLE_UV_INTERP)
+	vec2 uv = uv_interp;
+#endif
+
+#if defined(ENABLE_UV2_INTERP)
+	vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+	vec4 color = color_interp;
+#endif
+
+#if defined(ENABLE_NORMALMAP)
+
+	vec3 normalmap = vec3(0.0);
+#endif
+
+	float normaldepth=1.0;
+
+
+
+#if defined(ENABLE_DISCARD)
+	bool discard_=false;
+#endif
+
+{
+
+
+FRAGMENT_SHADER_CODE
+
+}
+
+#if defined(ENABLE_NORMALMAP)
+
+	normal = normalize( mix(normal_interp,tangent_interp * normalmap.x + binormal_interp * normalmap.y + normal_interp * normalmap.z,normaldepth) ) * side;
+
+#endif
+
+#if defined(ENABLE_DISCARD)
+	if (discard_) {
+	//easy to eliminate dead code
+		discard;
+	}
+#endif
+
+#ifdef ENABLE_CLIP_ALPHA
+	if (diffuse.a<0.99) {
+		//used for doublepass and shadowmapping
+		discard;
+	}
+#endif
+
+
+
+#if defined(USE_LIGHT_SHADER_CODE)
+//light is written by the light shader
+{
+
+LIGHT_SHADER_CODE
+
+}
+#endif
+
+	frag_color=vec4(albedo,alpha);
+}
+
+

+ 82 - 17
servers/visual/rasterizer.h

@@ -33,6 +33,75 @@
 #include "servers/visual_server.h"
 #include "camera_matrix.h"
 
+#include "self_list.h"
+
+
+class RasterizerScene {
+public:
+
+
+	struct InstanceBase : RID_Data {
+
+		VS::InstanceType base_type;
+		RID base;
+
+		RID skeleton;
+		RID material_override;
+
+		Transform transform;
+
+		int depth_layer;
+
+		//RID sampled_light;
+
+		Vector<RID> materials;
+		Vector<RID> light_instances;
+
+		Vector<float> morph_values;
+
+		//BakedLightData *baked_light;
+		VS::ShadowCastingSetting cast_shadows;
+		//Transform *baked_light_octree_xform;
+		//int baked_lightmap_id;
+
+		bool mirror :8;
+		bool depth_scale :8;
+		bool billboard :8;
+		bool billboard_y :8;
+		bool receive_shadows : 8;
+
+		SelfList<InstanceBase> dependency_item;
+
+		virtual void base_removed()=0;
+		virtual void base_changed()=0;
+
+		InstanceBase() : dependency_item(this) {
+
+			base_type=VS::INSTANCE_NONE;
+			cast_shadows=VS::SHADOW_CASTING_SETTING_ON;
+			receive_shadows=true;
+			depth_scale=false;
+			billboard=false;
+			billboard_y=false;
+			depth_layer=0;
+
+		}
+	};
+
+	virtual RID light_instance_create(RID p_light)=0;
+	virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform)=0;
+
+	virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment)=0;
+
+	virtual bool free(RID p_rid)=0;
+
+	virtual ~RasterizerScene() {}
+};
+
+
+
+
+
 
 
 class RasterizerStorage {
@@ -88,7 +157,7 @@ public:
 
 	virtual RID mesh_create()=0;
 
-	virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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 Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >())=0;
+	virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::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>())=0;
 
 	virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount)=0;
 	virtual int mesh_get_morph_target_count(RID p_mesh) const=0;
@@ -116,7 +185,7 @@ public:
 	virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb)=0;
 	virtual AABB mesh_get_custom_aabb(RID p_mesh) const=0;
 
-	virtual AABB mesh_get_aabb(RID p_mesh) const=0;
+	virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const=0;
 	virtual void mesh_clear(RID p_mesh)=0;
 
 	/* MULTIMESH API */
@@ -184,9 +253,11 @@ public:
 	virtual void light_set_cull_mask(RID p_light,uint32_t p_mask)=0;
 	virtual void light_set_shader(RID p_light,RID p_shader)=0;
 
-
 	virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode)=0;
 
+	virtual VS::LightType light_get_type(RID p_light) const=0;
+	virtual AABB light_get_aabb(RID p_light) const=0;
+
 	/* PROBE API */
 
 	virtual RID reflection_probe_create()=0;
@@ -220,6 +291,10 @@ public:
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=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;
+
 	/* RENDER TARGET */
 
 	enum RenderTargetFlags {
@@ -246,6 +321,8 @@ public:
 	virtual RID canvas_light_occluder_create()=0;
 	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0;
 
+
+	virtual VS::InstanceType get_base_type(RID p_rid) const=0;
 	virtual bool free(RID p_rid)=0;
 
 
@@ -257,6 +334,7 @@ public:
 
 
 
+
 class RasterizerCanvas {
 public:
 
@@ -563,7 +641,7 @@ public:
 					case Item::Command::TYPE_MESH: {
 
 						const Item::CommandMesh* mesh = static_cast< const Item::CommandMesh*>(c);
-						AABB aabb = RasterizerStorage::base_signleton->mesh_get_aabb(mesh->mesh);
+						AABB aabb = RasterizerStorage::base_signleton->mesh_get_aabb(mesh->mesh,mesh->skeleton);
 
 						r=Rect2(aabb.pos.x,aabb.pos.y,aabb.size.x,aabb.size.y);
 
@@ -654,17 +732,6 @@ public:
 };
 
 
-
-class RasterizerScene {
-public:
-
-
-
-	virtual ~RasterizerScene() {}
-};
-
-
-
 class Rasterizer {
 protected:
 	static Rasterizer* (*_create_func)();
@@ -689,8 +756,6 @@ public:
 };
 
 
-
-
 #if 0
 /**
 	@author Juan Linietsky <[email protected]>

+ 4 - 9
servers/visual/shader_types.cpp

@@ -58,8 +58,8 @@ ShaderTypes::ShaderTypes()
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALBEDO"]=ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALPHA"]=ShaderLanguage::TYPE_FLOAT;
-	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["METAL"]=ShaderLanguage::TYPE_FLOAT;
-	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ROUGH"]=ShaderLanguage::TYPE_FLOAT;
+	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECULAR"]=ShaderLanguage::TYPE_VEC3;
+	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ROUGHNESS"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;
 	shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["DISCARD"]=ShaderLanguage::TYPE_BOOL;
@@ -77,10 +77,6 @@ ShaderTypes::ShaderTypes()
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_sub");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mul");
 
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("special_glow");
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("special_subsurf");
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("special_specular");
-
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_opaque");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_always");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_never");
@@ -90,12 +86,10 @@ ShaderTypes::ShaderTypes()
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_back");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_disable");
 
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("lightmap_on_uv2");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop");
 
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_model_space");
-	shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_camera_space");
+	shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_transform");
 
 	/************ CANVAS ITEM **************************/
 
@@ -158,4 +152,5 @@ ShaderTypes::ShaderTypes()
 
 
 
+
 }

+ 7 - 172
servers/visual/visual_server_raster.cpp

@@ -34,183 +34,12 @@
 #include "io/marshalls.h"
 #include "visual_server_canvas.h"
 #include "visual_server_global.h"
+#include "visual_server_scene.h"
 
 // careful, these may run in different threads than the visual server
 
 
 
-/* CAMERA API */
-
-RID VisualServerRaster::camera_create() {
-
-	return RID();
-}
-void VisualServerRaster::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) {
-
-}
-void VisualServerRaster::camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far){
-
-}
-void VisualServerRaster::camera_set_transform(RID p_camera,const Transform& p_transform) {
-
-}
-void VisualServerRaster::camera_set_cull_mask(RID p_camera,uint32_t p_layers){
-
-}
-void VisualServerRaster::camera_set_environment(RID p_camera,RID p_env){
-
-}
-void VisualServerRaster::camera_set_use_vertical_aspect(RID p_camera,bool p_enable){
-
-}
-
-
-/* ENVIRONMENT API */
-
-RID VisualServerRaster::environment_create(){
-
-	return RID();
-}
-
-void VisualServerRaster::environment_set_background(RID p_env,EnvironmentBG p_bg){
-
-}
-void VisualServerRaster::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){
-
-}
-void VisualServerRaster::environment_set_bg_color(RID p_env,const Color& p_color){
-
-}
-void VisualServerRaster::environment_set_canvas_max_layer(RID p_env,int p_max_layer){
-
-}
-void VisualServerRaster::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){
-
-}
-
-void VisualServerRaster::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,EnvironmentGlowBlendMode p_blend_mode){
-
-}
-void VisualServerRaster::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){
-
-}
-
-void VisualServerRaster::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,EnvironmentToneMapper p_tone_mapper){
-
-}
-void VisualServerRaster::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){
-
-}
-void VisualServerRaster::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){
-
-}
-void VisualServerRaster::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){
-
-}
-void VisualServerRaster::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){
-
-}
-
-
-/* SCENARIO API */
-
-
-RID VisualServerRaster::scenario_create() {
-
-	return RID();
-}
-
-void VisualServerRaster::scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode){
-
-}
-void VisualServerRaster::scenario_set_environment(RID p_scenario, RID p_environment){
-
-}
-RID VisualServerRaster::scenario_get_environment(RID p_scenario, RID p_environment) const{
-
-	return RID();
-}
-void VisualServerRaster::scenario_set_fallback_environment(RID p_scenario, RID p_environment){
-
-}
-
-
-/* INSTANCING API */
-// from can be mesh, light,  area and portal so far.
-RID VisualServerRaster::instance_create(){
-
-	return RID();
-}
-
-void VisualServerRaster::instance_set_base(RID p_instance, RID p_base){
-
-}
-void VisualServerRaster::instance_set_scenario(RID p_instance, RID p_scenario){
-
-}
-void VisualServerRaster::instance_set_layer_mask(RID p_instance, uint32_t p_mask){
-
-}
-void VisualServerRaster::instance_set_transform(RID p_instance, const Transform& p_transform){
-
-}
-void VisualServerRaster::instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID){
-
-}
-void VisualServerRaster::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){
-
-}
-void VisualServerRaster::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){
-
-}
-
-void VisualServerRaster::instance_attach_skeleton(RID p_instance,RID p_skeleton){
-
-}
-void VisualServerRaster::instance_set_exterior( RID p_instance, bool p_enabled ){
-
-}
-void VisualServerRaster::instance_set_room( RID p_instance, RID p_room ){
-
-}
-
-void VisualServerRaster::instance_set_extra_visibility_margin( RID p_instance, real_t p_margin ){
-
-}
-
-// don't use these in a game!
-Vector<ObjectID> VisualServerRaster::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{
-
-	return Vector<ObjectID>();
-}
-
-Vector<ObjectID> VisualServerRaster::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{
-
-	return Vector<ObjectID>();
-}
-Vector<ObjectID> VisualServerRaster::instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario) const {
-
-	return Vector<ObjectID>();
-}
-
-
-void VisualServerRaster::instance_geometry_set_flag(RID p_instance,InstanceFlags p_flags,bool p_enabled){
-
-}
-void VisualServerRaster::instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) {
-
-}
-void VisualServerRaster::instance_geometry_set_material_override(RID p_instance, RID p_material){
-
-}
-
-
-void VisualServerRaster::instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin){
-
-}
-void VisualServerRaster::instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance){
-
-}
 
 /* CURSOR */
 void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor ){
@@ -247,6 +76,8 @@ void VisualServerRaster::free( RID p_rid ){
 		return;
 	if (VSG::viewport->free(p_rid))
 		return;
+	if (VSG::scene->free(p_rid))
+		return;
 
 }
 
@@ -258,6 +89,9 @@ void VisualServerRaster::draw(){
 	//	print_line("changes: "+itos(changes));
 
 	changes=0;
+
+	VSG::scene->update_dirty_instances(); //update scene stuff
+
 	VSG::rasterizer->begin_frame();
 	VSG::viewport->draw_viewports();
 	//_draw_cursors_and_margins();
@@ -322,6 +156,7 @@ VisualServerRaster::VisualServerRaster() {
 
 	VSG::canvas = memnew( VisualServerCanvas);
 	VSG::viewport = memnew( VisualServerViewport);
+	VSG::scene = memnew( VisualServerScene );
 	VSG::rasterizer = Rasterizer::create();
 	VSG::storage=VSG::rasterizer->get_storage();
 	VSG::canvas_render=VSG::rasterizer->get_canvas();

+ 57 - 46
servers/visual/visual_server_raster.h

@@ -37,6 +37,7 @@
 #include "visual_server_global.h"
 #include "visual_server_viewport.h"
 #include "visual_server_canvas.h"
+#include "visual_server_scene.h"
 /**
 	@author Juan Linietsky <[email protected]>
 */
@@ -600,6 +601,7 @@ public:
 #define BIND6(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6); }
 #define BIND7(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7); }
 #define BIND8(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); }
+#define BIND9(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8,m_type9) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8,m_type9 arg9) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9); }
 #define BIND10(m_name,m_type1,m_type2,m_type3,m_type4,m_type5,m_type6,m_type7,m_type8,m_type9,m_type10) void m_name(m_type1 arg1,m_type2 arg2,m_type3 arg3,m_type4 arg4,m_type5 arg5,m_type6 arg6,m_type7 arg7,m_type8 arg8,m_type9 arg9,m_type10 arg10) { DISPLAY_CHANGED BINDBASE->m_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10); }
 
 //from now on, calls forwarded to this singleton
@@ -659,7 +661,7 @@ public:
 
 	BIND0R(RID,mesh_create)
 
-	BIND8(mesh_add_surface,RID,uint32_t,PrimitiveType,const DVector<uint8_t>&,int ,const DVector<uint8_t>& ,int ,const Vector<DVector<uint8_t> >& )
+	BIND10(mesh_add_surface,RID,uint32_t,PrimitiveType,const DVector<uint8_t>&,int ,const DVector<uint8_t>& ,int ,const AABB&,const Vector<DVector<uint8_t> >&,const Vector<AABB>& )
 
 	BIND2(mesh_set_morph_target_count,RID,int)
 	BIND1RC(int,mesh_get_morph_target_count,RID)
@@ -788,13 +790,18 @@ public:
 
 	/* CAMERA API */
 
-	virtual RID camera_create();
-	virtual void camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far);
-	virtual void camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far);
-	virtual void camera_set_transform(RID p_camera,const Transform& p_transform);
-	virtual void camera_set_cull_mask(RID p_camera,uint32_t p_layers);
-	virtual void camera_set_environment(RID p_camera,RID p_env);
-	virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable);
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE VSG::scene
+
+
+	BIND0R(RID, camera_create)
+	BIND4(camera_set_perspective,RID,float, float , float )
+	BIND4(camera_set_orthogonal,RID,float , float , float )
+	BIND2(camera_set_transform,RID,const Transform&)
+	BIND2(camera_set_cull_mask,RID,uint32_t )
+	BIND2(camera_set_environment,RID ,RID )
+	BIND2(camera_set_use_vertical_aspect,RID,bool)
 
 #undef BINDBASE
 //from now on, calls forwarded to this singleton
@@ -839,66 +846,69 @@ public:
 
 	/* ENVIRONMENT API */
 
-	virtual RID environment_create();
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE VSG::scene
+
+	BIND0R(RID,environment_create)
 
-	virtual void environment_set_background(RID p_env,EnvironmentBG p_bg);
-	virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0);
-	virtual void environment_set_bg_color(RID p_env,const Color& p_color);
-	virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer);
-	virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0);
+	BIND2(environment_set_background,RID ,EnvironmentBG )
+	BIND3(environment_set_skybox,RID,RID ,float )
+	BIND2(environment_set_bg_color,RID,const Color& )
+	BIND2(environment_set_canvas_max_layer,RID,int )
+	BIND3(environment_set_ambient_light,RID,const Color& ,float )
 
-	virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,EnvironmentGlowBlendMode p_blend_mode);
-	virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture);
+	BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode )
+	BIND5(environment_set_fog,RID,bool ,float ,float ,RID )
 
-	virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,EnvironmentToneMapper p_tone_mapper);
-	virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness);
-	virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast);
-	virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation);
-	virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp);
+	BIND8(environment_set_tonemap,RID,bool ,float ,float ,float ,float ,float ,EnvironmentToneMapper )
+	BIND3(environment_set_brightness,RID,bool ,float )
+	BIND3(environment_set_contrast,RID,bool ,float )
+	BIND3(environment_set_saturation,RID,bool ,float )
+	BIND3(environment_set_color_correction,RID,bool ,RID )
 
 
 	/* SCENARIO API */
 
 
-	virtual RID scenario_create();
+	BIND0R(RID,scenario_create)
 
-	virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode);
-	virtual void scenario_set_environment(RID p_scenario, RID p_environment);
-	virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const;
-	virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+	BIND2(scenario_set_debug,RID,ScenarioDebugMode )
+	BIND2(scenario_set_environment,RID, RID )
+	BIND2(scenario_set_fallback_environment,RID, RID )
 
 
 	/* INSTANCING API */
  // from can be mesh, light,  area and portal so far.
-	virtual RID instance_create(); // from can be mesh, light, poly, area and portal so far.
+	BIND0R(RID,instance_create)
 
-	virtual void instance_set_base(RID p_instance, RID p_base); // from can be mesh, light, poly, area and portal so far.
-	virtual void instance_set_scenario(RID p_instance, RID p_scenario); // from can be mesh, light, poly, area and portal so far.
-	virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
-	virtual void instance_set_transform(RID p_instance, const Transform& p_transform);
-	virtual void instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID);
-	virtual void instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight);
-	virtual void instance_set_surface_material(RID p_instance,int p_surface, RID p_material);
+	BIND2(instance_set_base,RID, RID ) // from can be mesh, light, poly, area and portal so far.
+	BIND2(instance_set_scenario,RID, RID ) // from can be mesh, light, poly, area and portal so far.
+	BIND2(instance_set_layer_mask,RID, uint32_t )
+	BIND2(instance_set_transform,RID, const Transform& )
+	BIND2(instance_attach_object_instance_ID,RID,ObjectID )
+	BIND3(instance_set_morph_target_weight,RID,int , float )
+	BIND3(instance_set_surface_material,RID,int , RID )
 
-	virtual void instance_attach_skeleton(RID p_instance,RID p_skeleton);
-	virtual void instance_set_exterior( RID p_instance, bool p_enabled );
-	virtual void instance_set_room( RID p_instance, RID p_room );
+	BIND2(instance_attach_skeleton,RID,RID )
+	BIND2(instance_set_exterior, RID, bool  )
+	BIND2(instance_set_room, RID, RID  )
 
-	virtual void instance_set_extra_visibility_margin( RID p_instance, real_t p_margin );
+	BIND2(instance_set_extra_visibility_margin, RID, real_t  )
 
 	// don't use these in a game!
-	virtual Vector<ObjectID> instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const;
-	virtual Vector<ObjectID> instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const;
-	virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario=RID()) const;
+	BIND2RC(Vector<ObjectID>,instances_cull_aabb,const AABB& , RID)
+	BIND3RC(Vector<ObjectID>,instances_cull_ray,const Vector3& , const Vector3& , RID )
+	BIND2RC(Vector<ObjectID>,instances_cull_convex,const Vector<Plane>& , RID)
 
 
-	virtual void instance_geometry_set_flag(RID p_instance,InstanceFlags p_flags,bool p_enabled);
-	virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting);
-	virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
+	BIND3(instance_geometry_set_flag,RID,InstanceFlags ,bool )
+	BIND2(instance_geometry_set_cast_shadows_setting,RID, ShadowCastingSetting )
+	BIND2(instance_geometry_set_material_override,RID, RID )
 
 
-	virtual void instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin);
-	virtual void instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance);
+	BIND5(instance_geometry_set_draw_range,RID,float ,float ,float ,float )
+	BIND2(instance_geometry_set_as_instance_lod,RID,RID )
 
 
 #undef BINDBASE
@@ -1055,6 +1065,7 @@ public:
 #undef BIND6
 #undef BIND7
 #undef BIND8
+#undef BIND9
 #undef BIND10
 
 };

+ 1517 - 0
servers/visual/visual_server_scene.cpp

@@ -0,0 +1,1517 @@
+#include "visual_server_scene.h"
+#include "visual_server_global.h"
+
+/* CAMERA API */
+
+
+RID VisualServerScene::camera_create() {
+
+	Camera * camera = memnew( Camera );
+	return camera_owner.make_rid( camera );
+
+}
+
+void VisualServerScene::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) {
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+	camera->type=Camera::PERSPECTIVE;
+	camera->fov=p_fovy_degrees;
+	camera->znear=p_z_near;
+	camera->zfar=p_z_far;
+
+}
+
+void VisualServerScene::camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far) {
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+	camera->type=Camera::ORTHOGONAL;
+	camera->size=p_size;
+	camera->znear=p_z_near;
+	camera->zfar=p_z_far;
+}
+
+void VisualServerScene::camera_set_transform(RID p_camera,const Transform& p_transform) {
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+	camera->transform=p_transform.orthonormalized();
+
+
+}
+
+void VisualServerScene::camera_set_cull_mask(RID p_camera,uint32_t p_layers) {
+
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+
+	camera->visible_layers=p_layers;
+
+}
+
+void VisualServerScene::camera_set_environment(RID p_camera,RID p_env) {
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+	camera->env=p_env;
+
+}
+
+
+void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera,bool p_enable) {
+
+	Camera *camera = camera_owner.get( p_camera );
+	ERR_FAIL_COND(!camera);
+	camera->vaspect=p_enable;
+
+}
+
+
+
+/* ENVIRONMENT API */
+
+RID VisualServerScene::environment_create(){
+
+	return RID();
+}
+
+void VisualServerScene::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){
+
+}
+void VisualServerScene::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){
+
+}
+void VisualServerScene::environment_set_bg_color(RID p_env,const Color& p_color){
+
+}
+void VisualServerScene::environment_set_canvas_max_layer(RID p_env,int p_max_layer){
+
+}
+void VisualServerScene::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){
+
+}
+
+void VisualServerScene::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){
+
+}
+void VisualServerScene::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){
+
+}
+
+void VisualServerScene::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){
+
+}
+void VisualServerScene::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){
+
+}
+void VisualServerScene::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){
+
+}
+void VisualServerScene::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){
+
+}
+void VisualServerScene::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){
+
+}
+
+
+/* SCENARIO API */
+
+
+
+void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int) {
+
+//	VisualServerScene *self = (VisualServerScene*)p_self;
+	Instance *A = p_A;
+	Instance *B = p_B;
+
+	//instance indices are designed so greater always contains lesser
+	if (A->base_type > B->base_type) {
+		SWAP(A,B); //lesser always first
+	}
+
+	if (B->base_type==VS::INSTANCE_LIGHT && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+		InstanceLightData * light = static_cast<InstanceLightData*>(B->base_data);
+		InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+
+		InstanceLightData::PairInfo pinfo;
+		pinfo.geometry=A;
+		pinfo.L = geom->lighting.push_back(B);
+
+		List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo);
+
+		light->shadow_sirty=true;
+		geom->lighting_dirty=true;
+
+		return E; //this element should make freeing faster
+	}
+
+#if 0
+	if (A->base_type==INSTANCE_PORTAL) {
+
+		ERR_FAIL_COND_V( B->base_type!=INSTANCE_PORTAL,NULL );
+
+		A->portal_info->candidate_set.insert(B);
+		B->portal_info->candidate_set.insert(A);
+
+		self->_portal_attempt_connect(A);
+		//attempt to conncet portal A (will go through B anyway)
+		//this is a little hackish, but works fine in practice
+
+	} else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+		if (B->base_type==INSTANCE_BAKED_LIGHT) {
+			SWAP(A,B);
+		}
+
+		ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL);
+		B->baked_light_sampler_info->baked_lights.insert(A);
+
+	} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
+
+		if (B->base_type==INSTANCE_ROOM)
+			SWAP(A,B);
+
+		ERR_FAIL_COND_V(! ((1<<B->base_type)&INSTANCE_GEOMETRY_MASK ),NULL);
+
+		B->auto_rooms.insert(A);
+		A->room_info->owned_autoroom_geometry.insert(B);
+
+		self->_instance_validate_autorooms(B);
+
+
+	} else {
+
+		if (B->base_type==INSTANCE_LIGHT) {
+
+			SWAP(A,B);
+		} else if (A->base_type!=INSTANCE_LIGHT) {
+			return NULL;
+		}
+
+
+		A->light_info->affected.insert(B);
+		B->lights.insert(A);
+		B->light_cache_dirty=true;
+
+
+	}
+#endif
+
+	return NULL;
+
+}
+void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void* udata) {
+
+//	VisualServerScene *self = (VisualServerScene*)p_self;
+	Instance *A = p_A;
+	Instance *B = p_B;
+
+	//instance indices are designed so greater always contains lesser
+	if (A->base_type > B->base_type) {
+		SWAP(A,B); //lesser always first
+	}
+
+
+
+	if (B->base_type==VS::INSTANCE_LIGHT && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+		InstanceLightData * light = static_cast<InstanceLightData*>(B->base_data);
+		InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+		List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element*>(udata);
+
+		geom->lighting.erase(E->get().L);
+		light->geometries.erase(E);
+
+		light->shadow_sirty=true;
+		geom->lighting_dirty=true;
+
+
+	}
+#if 0
+	if (A->base_type==INSTANCE_PORTAL) {
+
+		ERR_FAIL_COND( B->base_type!=INSTANCE_PORTAL );
+
+
+		A->portal_info->candidate_set.erase(B);
+		B->portal_info->candidate_set.erase(A);
+
+		//after disconnecting them, see if they can connect again
+		self->_portal_attempt_connect(A);
+		self->_portal_attempt_connect(B);
+
+	} else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+		if (B->base_type==INSTANCE_BAKED_LIGHT) {
+			SWAP(A,B);
+		}
+
+		ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER);
+		B->baked_light_sampler_info->baked_lights.erase(A);
+
+	} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
+
+		if (B->base_type==INSTANCE_ROOM)
+			SWAP(A,B);
+
+		ERR_FAIL_COND(! ((1<<B->base_type)&INSTANCE_GEOMETRY_MASK ));
+
+		B->auto_rooms.erase(A);
+		B->valid_auto_rooms.erase(A);
+		A->room_info->owned_autoroom_geometry.erase(B);
+
+	}else {
+
+
+
+	if (B->base_type==INSTANCE_LIGHT) {
+
+			SWAP(A,B);
+		} else if (A->base_type!=INSTANCE_LIGHT) {
+			return;
+		}
+
+
+		A->light_info->affected.erase(B);
+		B->lights.erase(A);
+		B->light_cache_dirty=true;
+
+	}
+#endif
+}
+
+RID VisualServerScene::scenario_create() {
+
+	Scenario *scenario = memnew( Scenario );
+	ERR_FAIL_COND_V(!scenario,RID());
+	RID scenario_rid = scenario_owner.make_rid( scenario );
+	scenario->self=scenario_rid;
+
+	scenario->octree.set_pair_callback(_instance_pair,this);
+	scenario->octree.set_unpair_callback(_instance_unpair,this);
+
+	return scenario_rid;
+}
+
+void VisualServerScene::scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode) {
+
+	Scenario *scenario = scenario_owner.get(p_scenario);
+	ERR_FAIL_COND(!scenario);
+	scenario->debug=p_debug_mode;
+}
+
+void VisualServerScene::scenario_set_environment(RID p_scenario, RID p_environment) {
+
+	Scenario *scenario = scenario_owner.get(p_scenario);
+	ERR_FAIL_COND(!scenario);
+	scenario->environment=p_environment;
+
+}
+
+void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
+
+
+	Scenario *scenario = scenario_owner.get(p_scenario);
+	ERR_FAIL_COND(!scenario);
+	scenario->fallback_environment=p_environment;
+
+
+}
+
+
+
+/* INSTANCING API */
+
+void VisualServerScene::_instance_queue_update(Instance *p_instance,bool p_update_aabb,bool p_update_materials) {
+
+	if (p_update_aabb)
+		p_instance->update_aabb=true;
+	if (p_update_materials)
+		p_instance->update_materials=true;
+
+	if (p_instance->update_item.in_list())
+		return;
+
+	_instance_update_list.add(&p_instance->update_item);
+
+
+}
+
+// from can be mesh, light,  area and portal so far.
+RID VisualServerScene::instance_create(){
+
+	Instance *instance = memnew( Instance );
+	ERR_FAIL_COND_V(!instance,RID());
+
+	RID instance_rid = instance_owner.make_rid(instance);
+	instance->self=instance_rid;
+
+
+	return instance_rid;
+
+
+}
+
+void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	Scenario *scenario = instance->scenario;
+
+	if (instance->base_type!=VS::INSTANCE_NONE) {
+		//free anything related to that base
+
+		VSG::storage->instance_remove_dependency(instance->base,instance);
+
+		if (scenario && instance->octree_id) {
+			scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+			instance->octree_id=0;
+		}
+
+		switch(instance->base_type) {
+			case VS::INSTANCE_LIGHT: {
+
+				InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+				if (instance->scenario && light->D) {
+					instance->scenario->directional_lights.erase( light->D );
+					light->D=NULL;
+				}
+				VSG::scene_render->free(light->instance);
+
+			}
+		}
+
+		if (instance->base_data) {
+			memdelete( instance->base_data );
+			instance->base_data=NULL;
+		}
+
+		instance->morph_values.clear();
+		instance->materials.clear();
+
+#if 0
+		if (instance->light_info) {
+
+			if (instance->scenario && instance->light_info->D)
+				instance->scenario->directional_lights.erase( instance->light_info->D );
+			rasterizer->free(instance->light_info->instance);
+			memdelete(instance->light_info);
+			instance->light_info=NULL;
+		}
+
+
+
+		if ( instance->room ) {
+
+			instance_set_room(p_instance,RID());
+			/*
+			if((1<<instance->base_type)&INSTANCE_GEOMETRY_MASK)
+				instance->room->room_info->owned_geometry_instances.erase(instance->RE);
+			else if (instance->base_type==INSTANCE_PORTAL) {
+				print_line("freeing portal, is it there? "+itos(instance->room->room_info->owned_portal_instances.(instance->RE)));
+				instance->room->room_info->owned_portal_instances.erase(instance->RE);
+			} else if (instance->base_type==INSTANCE_ROOM)
+				instance->room->room_info->owned_room_instances.erase(instance->RE);
+			else if (instance->base_type==INSTANCE_LIGHT)
+				instance->room->room_info->owned_light_instances.erase(instance->RE);
+
+			instance->RE=NULL;*/
+		}
+
+
+
+
+
+
+		if (instance->portal_info) {
+
+			_portal_disconnect(instance,true);
+			memdelete(instance->portal_info);
+			instance->portal_info=NULL;
+
+		}
+
+		if (instance->baked_light_info) {
+
+			while(instance->baked_light_info->owned_instances.size()) {
+
+				Instance *owned=instance->baked_light_info->owned_instances.front()->get();
+				owned->baked_light=NULL;
+				owned->data.baked_light=NULL;
+				owned->data.baked_light_octree_xform=NULL;
+				owned->BLE=NULL;
+				instance->baked_light_info->owned_instances.pop_front();
+			}
+
+			memdelete(instance->baked_light_info);
+			instance->baked_light_info=NULL;
+
+		}
+
+		if (instance->scenario && instance->octree_id) {
+			instance->scenario->octree.erase( instance->octree_id );
+			instance->octree_id=0;
+		}
+
+
+		if (instance->room_info) {
+
+			for(List<Instance*>::Element *E=instance->room_info->owned_geometry_instances.front();E;E=E->next()) {
+
+				Instance *owned = E->get();
+				owned->room=NULL;
+				owned->RE=NULL;
+			}
+			for(List<Instance*>::Element *E=instance->room_info->owned_portal_instances.front();E;E=E->next()) {
+
+				_portal_disconnect(E->get(),true);
+				Instance *owned = E->get();
+				owned->room=NULL;
+				owned->RE=NULL;
+			}
+
+			for(List<Instance*>::Element *E=instance->room_info->owned_room_instances.front();E;E=E->next()) {
+
+				Instance *owned = E->get();
+				owned->room=NULL;
+				owned->RE=NULL;
+			}
+
+			if (instance->room_info->disconnected_child_portals.size()) {
+				ERR_PRINT("BUG: Disconnected portals remain!");
+			}
+			memdelete(instance->room_info);
+			instance->room_info=NULL;
+
+		}
+
+		if (instance->particles_info) {
+
+			rasterizer->free( instance->particles_info->instance );
+			memdelete(instance->particles_info);
+			instance->particles_info=NULL;
+
+		}
+
+		if (instance->baked_light_sampler_info) {
+
+			while (instance->baked_light_sampler_info->owned_instances.size()) {
+
+				instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID());
+			}
+
+			if (instance->baked_light_sampler_info->sampled_light.is_valid()) {
+				rasterizer->free(instance->baked_light_sampler_info->sampled_light);
+			}
+			memdelete( instance->baked_light_sampler_info );
+			instance->baked_light_sampler_info=NULL;
+		}
+#endif
+
+	}
+
+
+	instance->base_type=VS::INSTANCE_NONE;
+	instance->base=RID();
+
+
+	if (p_base.is_valid()) {
+
+		instance->base_type=VSG::storage->get_base_type(p_base);
+		ERR_FAIL_COND(instance->base_type==VS::INSTANCE_NONE);
+
+		switch(instance->base_type) {
+			case VS::INSTANCE_LIGHT: {
+
+				InstanceLightData *light = memnew( InstanceLightData );
+
+				if (scenario && VSG::storage->light_get_type(p_base)==VS::LIGHT_DIRECTIONAL) {
+					light->D = scenario->directional_lights.push_back(instance);
+				}
+
+				light->instance = VSG::scene_render->light_instance_create(p_base);
+
+				instance->base_data=light;
+			}
+			case VS::INSTANCE_MESH: {
+
+				InstanceGeometryData *geom = memnew( InstanceGeometryData );
+				instance->base_data=geom;
+			}
+
+		}
+
+		VSG::storage->instance_add_dependency(p_base,instance);
+
+		instance->base=p_base;
+
+		if (scenario)
+			_instance_queue_update(instance,true,true);
+
+
+#if 0
+		if (rasterizer->is_mesh(p_base)) {
+			instance->base_type=INSTANCE_MESH;
+			instance->data.morph_values.resize( rasterizer->mesh_get_morph_target_count(p_base));
+			instance->data.materials.resize( rasterizer->mesh_get_surface_count(p_base));
+		} else if (rasterizer->is_multimesh(p_base)) {
+			instance->base_type=INSTANCE_MULTIMESH;
+		} else if (rasterizer->is_immediate(p_base)) {
+			instance->base_type=INSTANCE_IMMEDIATE;
+		} else if (rasterizer->is_particles(p_base)) {
+			instance->base_type=INSTANCE_PARTICLES;
+			instance->particles_info=memnew( Instance::ParticlesInfo );
+			instance->particles_info->instance = rasterizer->particles_instance_create( p_base );
+		} else if (rasterizer->is_light(p_base)) {
+
+			instance->base_type=INSTANCE_LIGHT;
+			instance->light_info = memnew( Instance::LightInfo );
+			instance->light_info->instance = rasterizer->light_instance_create(p_base);
+			if (instance->scenario && rasterizer->light_get_type(p_base)==LIGHT_DIRECTIONAL) {
+
+				instance->light_info->D = instance->scenario->directional_lights.push_back(instance->self);
+			}
+
+		} else if (room_owner.owns(p_base)) {
+			instance->base_type=INSTANCE_ROOM;
+			instance->room_info  = memnew( Instance::RoomInfo );
+			instance->room_info->room=room_owner.get(p_base);
+		} else if (portal_owner.owns(p_base)) {
+
+			instance->base_type=INSTANCE_PORTAL;
+			instance->portal_info = memnew(Instance::PortalInfo);
+			instance->portal_info->portal=portal_owner.get(p_base);
+		} else if (baked_light_owner.owns(p_base)) {
+
+			instance->base_type=INSTANCE_BAKED_LIGHT;
+			instance->baked_light_info=memnew(Instance::BakedLightInfo);
+			instance->baked_light_info->baked_light=baked_light_owner.get(p_base);
+
+			//instance->portal_info = memnew(Instance::PortalInfo);
+			//instance->portal_info->portal=portal_owner.get(p_base);
+		} else if (baked_light_sampler_owner.owns(p_base)) {
+
+
+			instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER;
+			instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo);
+			instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base);
+
+			//instance->portal_info = memnew(Instance::PortalInfo);
+			//instance->portal_info->portal=portal_owner.get(p_base);
+
+		} else {
+			ERR_EXPLAIN("Invalid base RID for instance!")
+			ERR_FAIL();
+		}
+
+		instance_dependency_map[ p_base ].insert( instance->self );
+#endif
+
+
+	}
+}
+void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	if (instance->scenario) {
+
+		instance->scenario->instances.remove( &instance->scenario_item );
+
+		if (instance->octree_id) {
+			instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+			instance->octree_id=0;
+		}
+
+
+		switch(instance->base_type) {
+
+			case VS::INSTANCE_LIGHT: {
+
+
+				InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+				if (light->D) {
+					instance->scenario->directional_lights.erase( light->D );
+					light->D=NULL;
+				}
+			}
+		}
+
+		instance->scenario=NULL;
+	}
+
+
+	if (p_scenario.is_valid()) {
+
+		Scenario *scenario = scenario_owner.get( p_scenario );
+		ERR_FAIL_COND(!scenario);
+
+		instance->scenario=scenario;
+
+		scenario->instances.add( &instance->scenario_item );
+
+
+		switch(instance->base_type) {
+
+			case VS::INSTANCE_LIGHT: {
+
+
+				InstanceLightData *light = static_cast<InstanceLightData*>(instance->base_data);
+
+				if (VSG::storage->light_get_type(instance->base)==VS::LIGHT_DIRECTIONAL) {
+					light->D = scenario->directional_lights.push_back(instance);
+				}
+			}
+		}
+
+		_instance_queue_update(instance,true,true);
+	}
+}
+void VisualServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask){
+
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	instance->layer_mask=p_mask;
+}
+void VisualServerScene::instance_set_transform(RID p_instance, const Transform& p_transform){
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	if (instance->transform==p_transform)
+		return; //must be checked to avoid worst evil
+
+	instance->transform=p_transform;
+	_instance_queue_update(instance,true);
+}
+void VisualServerScene::instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID){
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	instance->object_ID=p_ID;
+
+}
+void VisualServerScene::instance_set_morph_target_weight(RID p_instance,int p_shape, float 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);
+
+	ERR_FAIL_INDEX(p_surface,instance->materials.size());
+
+	instance->materials[p_surface]=p_material;
+
+}
+
+void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	instance->skeleton=p_skeleton;
+
+	_instance_queue_update(instance,true);
+}
+
+void VisualServerScene::instance_set_exterior( RID p_instance, bool p_enabled ){
+
+}
+void VisualServerScene::instance_set_room( RID p_instance, RID p_room ){
+
+}
+
+void VisualServerScene::instance_set_extra_visibility_margin( RID p_instance, real_t p_margin ){
+
+}
+
+// don't use these in a game!
+Vector<ObjectID> VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{
+
+	return Vector<ObjectID>();
+}
+
+Vector<ObjectID> VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{
+
+	return Vector<ObjectID>();
+}
+Vector<ObjectID> VisualServerScene::instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario) const {
+
+	return Vector<ObjectID>();
+}
+
+
+void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled){
+
+}
+void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) {
+
+}
+void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material){
+
+}
+
+
+void VisualServerScene::instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin){
+
+}
+void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance){
+
+}
+
+
+void VisualServerScene::_update_instance(Instance *p_instance) {
+
+	p_instance->version++;
+
+	if (p_instance->base_type == VS::INSTANCE_LIGHT) {
+
+		InstanceLightData *light = static_cast<InstanceLightData*>(p_instance->base_data);
+
+		VSG::scene_render->light_instance_set_transform( light->instance, p_instance->transform );
+
+	}
+
+
+	if (p_instance->aabb.has_no_surface())
+		return;
+
+#if 0
+	if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
+
+		rasterizer->particles_instance_set_transform( p_instance->particles_info->instance, p_instance->data.transform );
+	}
+
+#endif
+	if ((1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+		InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(p_instance->base_data);
+		//make sure lights are updated
+
+		for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+			InstanceLightData *light = static_cast<InstanceLightData*>(E->get()->base_data);
+			light->shadow_sirty=true;
+		}
+
+	}
+#if 0
+	else if (p_instance->base_type == INSTANCE_ROOM) {
+
+		p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse();
+	} else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) {
+
+		Transform scale;
+		scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size);
+		scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos;
+		//print_line("scale: "+scale);
+		p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse();
+	}
+
+
+#endif
+
+	p_instance->mirror = p_instance->transform.basis.determinant() < 0.0;
+
+	AABB new_aabb;
+#if 0
+	if (p_instance->base_type==INSTANCE_PORTAL) {
+
+		//portals need to be transformed in a special way, so they don't become too wide if they have scale..
+		Transform portal_xform = p_instance->data.transform;
+		portal_xform.basis.set_axis(2,portal_xform.basis.get_axis(2).normalized());
+
+		p_instance->portal_info->plane_cache=Plane( p_instance->data.transform.origin, portal_xform.basis.get_axis(2));
+		int point_count=p_instance->portal_info->portal->shape.size();
+		p_instance->portal_info->transformed_point_cache.resize(point_count);
+
+		AABB portal_aabb;
+
+		for(int i=0;i<point_count;i++) {
+
+			Point2 src = p_instance->portal_info->portal->shape[i];
+			Vector3 point = portal_xform.xform(Vector3(src.x,src.y,0));
+			p_instance->portal_info->transformed_point_cache[i]=point;
+			if (i==0)
+				portal_aabb.pos=point;
+			else
+				portal_aabb.expand_to(point);
+		}
+
+		portal_aabb.grow_by(p_instance->portal_info->portal->connect_range);
+
+		new_aabb = portal_aabb;
+
+	} else {
+#endif
+		new_aabb = p_instance->transform.xform(p_instance->aabb);
+#if 0
+	}
+#endif
+
+
+	p_instance->transformed_aabb=new_aabb;
+
+	if (!p_instance->scenario) {
+
+		return;
+	}
+
+
+
+	if (p_instance->octree_id==0) {
+
+		uint32_t base_type = 1<<p_instance->base_type;
+		uint32_t pairable_mask=0;
+		bool pairable=false;
+
+		if (p_instance->base_type == VS::INSTANCE_LIGHT) {
+
+			pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0;
+			pairable=true;
+		}
+#if 0
+
+		if (p_instance->base_type == VS::INSTANCE_PORTAL) {
+
+			pairable_mask=(1<<INSTANCE_PORTAL);
+			pairable=true;
+		}
+
+		if (p_instance->base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) {
+
+			pairable_mask=(1<<INSTANCE_BAKED_LIGHT);
+			pairable=true;
+		}
+
+
+		if (!p_instance->room && (1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+			base_type|=VS::INSTANCE_ROOMLESS_MASK;
+		}
+
+		if (p_instance->base_type == VS::INSTANCE_ROOM) {
+
+			pairable_mask=INSTANCE_ROOMLESS_MASK;
+			pairable=true;
+		}
+#endif
+
+		// not inside octree
+		p_instance->octree_id = p_instance->scenario->octree.create(p_instance,new_aabb,0,pairable,base_type,pairable_mask);
+
+	} else {
+
+	//	if (new_aabb==p_instance->data.transformed_aabb)
+	//		return;
+
+		p_instance->scenario->octree.move(p_instance->octree_id,new_aabb);
+	}
+#if 0
+	if (p_instance->base_type==INSTANCE_PORTAL) {
+
+		_portal_attempt_connect(p_instance);
+	}
+
+	if (!p_instance->room && (1<<p_instance->base_type)&INSTANCE_GEOMETRY_MASK) {
+
+		_instance_validate_autorooms(p_instance);
+	}
+
+	if (p_instance->base_type == INSTANCE_ROOM) {
+
+		for(Set<Instance*>::Element *E=p_instance->room_info->owned_autoroom_geometry.front();E;E=E->next())
+			_instance_validate_autorooms(E->get());
+	}
+#endif
+
+}
+
+void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
+
+	AABB new_aabb;
+
+	ERR_FAIL_COND(p_instance->base_type!=VS::INSTANCE_NONE && !p_instance->base.is_valid());
+
+	switch(p_instance->base_type) {
+		case VisualServer::INSTANCE_NONE: {
+
+			// do nothing
+		} break;
+		case VisualServer::INSTANCE_MESH: {
+
+			new_aabb = VSG::storage->mesh_get_aabb(p_instance->base,p_instance->skeleton);
+
+		} break;
+#if 0
+		case VisualServer::INSTANCE_MULTIMESH: {
+
+			new_aabb = rasterizer->multimesh_get_aabb(p_instance->base);
+
+		} break;
+		case VisualServer::INSTANCE_IMMEDIATE: {
+
+			new_aabb = rasterizer->immediate_get_aabb(p_instance->base);
+
+
+		} break;
+		case VisualServer::INSTANCE_PARTICLES: {
+
+			new_aabb = rasterizer->particles_get_aabb(p_instance->base);
+
+
+		} break;
+#endif
+		case VisualServer::INSTANCE_LIGHT: {
+
+			new_aabb = VSG::storage->light_get_aabb(p_instance->base);
+
+		} break;
+#if 0
+		case VisualServer::INSTANCE_ROOM: {
+
+			Room *room = room_owner.get( p_instance->base );
+			ERR_FAIL_COND(!room);
+			new_aabb=room->bounds.get_aabb();
+
+		} break;
+		case VisualServer::INSTANCE_PORTAL: {
+
+			Portal *portal = portal_owner.get( p_instance->base );
+			ERR_FAIL_COND(!portal);
+			for (int i=0;i<portal->shape.size();i++) {
+
+				Vector3 point( portal->shape[i].x, portal->shape[i].y, 0 );
+				if (i==0) {
+
+					new_aabb.pos=point;
+					new_aabb.size.z=0.01; // make it not flat for octree
+				} else {
+
+					new_aabb.expand_to(point);
+				}
+			}
+
+		} break;
+		case VisualServer::INSTANCE_BAKED_LIGHT: {
+
+			BakedLight *baked_light = baked_light_owner.get( p_instance->base );
+			ERR_FAIL_COND(!baked_light);
+			new_aabb=baked_light->octree_aabb;
+
+		} break;
+		case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: {
+
+			BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base );
+			ERR_FAIL_COND(!baked_light_sampler);
+			float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+
+			new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2));
+
+		} break;
+#endif
+		default: {}
+	}
+
+	if (p_instance->extra_margin)
+		new_aabb.grow_by(p_instance->extra_margin);
+
+	p_instance->aabb=new_aabb;
+
+}
+
+
+
+void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size) {
+
+
+
+	Camera *camera = camera_owner.getornull(p_camera);
+	ERR_FAIL_COND(!camera);
+
+	Scenario *scenario = scenario_owner.getornull(p_scenario);
+
+	render_pass++;
+	uint32_t camera_layer_mask=camera->visible_layers;
+
+
+	/* STEP 1 - SETUP CAMERA */
+	CameraMatrix camera_matrix;
+	bool ortho=false;
+
+	switch(camera->type) {
+		case Camera::ORTHOGONAL: {
+
+			camera_matrix.set_orthogonal(
+				camera->size,
+				p_viewport_size.width / (float)p_viewport_size.height,
+				camera->znear,
+				camera->zfar,
+				camera->vaspect
+
+			);
+			ortho=true;
+		} break;
+		case Camera::PERSPECTIVE: {
+
+			camera_matrix.set_perspective(
+				camera->fov,
+				p_viewport_size.width / (float)p_viewport_size.height,
+				camera->znear,
+				camera->zfar,
+				camera->vaspect
+
+			);
+			ortho=false;
+
+		} break;
+	}
+
+
+//	rasterizer->set_camera(camera->transform, camera_matrix,ortho);
+
+	Vector<Plane> planes = camera_matrix.get_projection_planes(camera->transform);
+
+	Plane near_plane(camera->transform.origin,-camera->transform.basis.get_axis(2).normalized());
+
+	/* STEP 2 - CULL */
+	int cull_count = scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL);
+	light_cull_count=0;
+//	light_samplers_culled=0;
+
+/*	print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
+	print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
+//	print_line("OTE: "+itos(p_scenario->octree.get_elem_count()));
+	print_line("OTP: "+itos(p_scenario->octree.get_pair_count()));
+*/
+
+	/* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
+
+
+	// compute portals
+#if 0
+	exterior_visited=false;
+	exterior_portal_cull_count=0;
+
+	if (room_cull_enabled) {
+		for(int i=0;i<cull_count;i++) {
+
+			Instance *ins = instance_cull_result[i];
+			ins->last_render_pass=render_pass;
+
+			if (ins->base_type!=INSTANCE_PORTAL)
+				continue;
+
+			if (ins->room)
+				continue;
+
+			ERR_CONTINUE(exterior_portal_cull_count>=MAX_EXTERIOR_PORTALS);
+			exterior_portal_cull_result[exterior_portal_cull_count++]=ins;
+
+		}
+
+		room_cull_count = p_scenario->octree.cull_point(camera->transform.origin,room_cull_result,MAX_ROOM_CULL,NULL,(1<<INSTANCE_ROOM)|(1<<INSTANCE_PORTAL));
+
+
+		Set<Instance*> current_rooms;
+		Set<Instance*> portal_rooms;
+		//add to set
+		for(int i=0;i<room_cull_count;i++) {
+
+			if (room_cull_result[i]->base_type==INSTANCE_ROOM) {
+				current_rooms.insert(room_cull_result[i]);
+			}
+			if (room_cull_result[i]->base_type==INSTANCE_PORTAL) {
+				//assume inside that room if also inside the portal..
+				if (room_cull_result[i]->room) {
+					portal_rooms.insert(room_cull_result[i]->room);
+				}
+
+				SWAP(room_cull_result[i],room_cull_result[room_cull_count-1]);
+				room_cull_count--;
+				i--;
+			}
+		}
+
+		//remove from set if it has a parent room or BSP doesn't contain
+		for(int i=0;i<room_cull_count;i++) {
+			Instance *r = room_cull_result[i];
+
+			//check inside BSP
+			Vector3 room_local_point = r->room_info->affine_inverse.xform( camera->transform.origin );
+
+			if (!portal_rooms.has(r) && !r->room_info->room->bounds.point_is_inside(room_local_point)) {
+
+				current_rooms.erase(r);
+				continue;
+			}
+
+			//check parent
+			while (r->room) {// has parent room
+
+				current_rooms.erase(r);
+				r=r->room;
+			}
+
+		}
+
+		if (current_rooms.size()) {
+			//camera is inside a room
+			// go through rooms
+			for(Set<Instance*>::Element *E=current_rooms.front();E;E=E->next()) {
+				_cull_room(camera,E->get());
+			}
+
+		} else {
+			//start from exterior
+			_cull_room(camera,NULL);
+
+		}
+	}
+
+#endif
+	/* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
+
+	for(int i=0;i<cull_count;i++) {
+
+		Instance *ins = instance_cull_result[i];
+
+		bool keep=false;
+
+
+		if ((camera_layer_mask&ins->layer_mask)==0) {
+
+			//failure
+		} else if (ins->base_type==VS::INSTANCE_LIGHT && ins->visible) {
+
+			if (light_cull_count<MAX_LIGHTS_CULLED) {
+
+				InstanceLightData * light = static_cast<InstanceLightData*>(ins->base_data);
+
+				if (!light->geometries.empty()) {
+					//do not add this light if no geometry is affected by it..
+					light_cull_result[light_cull_count]=ins;
+					light_instance_cull_result[light_cull_count]=light->instance;
+
+					light_cull_count++;
+				}
+
+//				rasterizer->light_instance_set_active_hint(ins->light_info->instance);
+			}
+
+		} else if ((1<<ins->base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
+
+			keep=true;
+#if 0
+			bool discarded=false;
+
+			if (ins->draw_range_end>0) {
+
+				float d = cull_range.nearp.distance_to(ins->data.transform.origin);
+				if (d<0)
+					d=0;
+				discarded=(d<ins->draw_range_begin || d>=ins->draw_range_end);
+
+
+			}
+
+			if (!discarded) {
+
+				// test if this geometry should be visible
+
+				if (room_cull_enabled) {
+
+
+					if (ins->visible_in_all_rooms) {
+						keep=true;
+					} else if (ins->room) {
+
+						if (ins->room->room_info->last_visited_pass==render_pass)
+							keep=true;
+					} else if (ins->auto_rooms.size()) {
+
+
+						for(Set<Instance*>::Element *E=ins->auto_rooms.front();E;E=E->next()) {
+
+							if (E->get()->room_info->last_visited_pass==render_pass) {
+								keep=true;
+								break;
+							}
+						}
+					} else if(exterior_visited)
+						keep=true;
+				} else {
+
+					keep=true;
+				}
+
+
+			}
+
+
+			if (keep) {
+				// update cull range
+				float min,max;
+				ins->transformed_aabb.project_range_in_plane(cull_range.nearp,min,max);
+
+				if (min<cull_range.min)
+					cull_range.min=min;
+				if (max>cull_range.max)
+					cull_range.max=max;
+
+				if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) {
+					if (light_samplers_culled<MAX_LIGHT_SAMPLERS) {
+						light_sampler_cull_result[light_samplers_culled++]=ins->sampled_light;
+						ins->sampled_light->baked_light_sampler_info->last_pass=render_pass;
+					}
+				}
+			}
+#endif
+
+
+			InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(ins->base_data);
+
+			if (geom->lighting_dirty) {
+				int l=0;
+				//only called when lights AABB enter/exit this geometry
+				ins->light_instances.resize(geom->lighting.size());
+
+				for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+
+					InstanceLightData * light = static_cast<InstanceLightData*>(E->get()->base_data);
+
+					ins->light_instances[l++]=light->instance;
+				}
+
+				geom->lighting_dirty=false;
+			}
+
+		}
+
+		if (!keep) {
+			// remove, no reason to keep
+			cull_count--;
+			SWAP( instance_cull_result[i], instance_cull_result[ cull_count ] );
+			i--;
+			ins->last_render_pass=0; // make invalid
+		} else {
+
+			ins->last_render_pass=render_pass;
+		}
+	}
+
+	/* STEP 5 - PROCESS LIGHTS */
+
+	RID *directional_light_ptr=&light_instance_cull_result[light_cull_count];
+	int directional_light_count=0;
+
+	// directional lights
+	{
+		for (List<Instance*>::Element *E=scenario->directional_lights.front();E;E=E->next()) {
+
+			if (light_cull_count+directional_light_count>=MAX_LIGHTS_CULLED) {
+				break;
+			}
+
+			if (!E->get()->visible)
+				continue;
+
+			InstanceLightData * light = static_cast<InstanceLightData*>(E->get()->base_data);
+
+
+			//check shadow..
+
+
+/*			if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) {
+				//rasterizer->light_instance_set_active_hint(light->light_info->instance);
+				_light_instance_update_shadow(light,p_scenario,camera,cull_range);
+			}
+*/
+
+			//add to list
+
+
+			directional_light_ptr[directional_light_count++]=light->instance;
+
+		}
+	}
+
+#if 0
+	{ //this should eventually change to
+		//assign shadows by distance to camera
+		SortArray<Instance*,_InstanceLightsort> sorter;
+		sorter.sort(light_cull_result,light_cull_count);
+		for (int i=0;i<light_cull_count;i++) {
+
+			Instance *ins = light_cull_result[i];
+
+			if (!rasterizer->light_has_shadow(ins->base_rid) || !shadows_enabled)
+				continue;
+
+			/* for far shadows?
+			if (ins->version == ins->light_info->last_version && rasterizer->light_instance_has_far_shadow(ins->light_info->instance))
+				continue; // didn't change
+			*/
+
+			_light_instance_update_shadow(ins,p_scenario,camera,cull_range);
+			ins->light_info->last_version=ins->version;
+		}
+	}
+#endif
+	/* ENVIRONMENT */
+
+	RID environment;
+	if (camera->env.is_valid()) //camera has more environment priority
+		environment=camera->env;
+	else if (scenario->environment.is_valid())
+		environment=scenario->environment;
+	else
+		environment=scenario->fallback_environment;
+
+#if 0
+	/* STEP 6 - SAMPLE BAKED LIGHT */
+
+	bool islinear =false;
+	if (environment.is_valid()) {
+		islinear = rasterizer->environment_is_fx_enabled(environment,VS::ENV_FX_SRGB);
+	}
+
+	for(int i=0;i<light_samplers_culled;i++) {
+
+		_process_sampled_light(camera->transform,light_sampler_cull_result[i],islinear);
+	}
+#endif
+	/* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/
+
+#if 0
+	// add lights
+
+	{
+		List<RID>::Element *E=p_scenario->directional_lights.front();
+
+
+		for(;E;E=E->next()) {
+			Instance  *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
+
+			ERR_CONTINUE(!light);
+			if (!light->light_info->enabled)
+				continue;
+
+			rasterizer->add_light(light->light_info->instance);
+			light->light_info->last_add_pass=render_pass;
+		}
+
+		for (int i=0;i<light_cull_count;i++) {
+
+			Instance *ins = light_cull_result[i];
+			rasterizer->add_light(ins->light_info->instance);
+			ins->light_info->last_add_pass=render_pass;
+		}
+	}
+		// add geometry
+#endif
+
+
+	VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count,directional_light_ptr,directional_light_count,environment);
+
+}
+
+
+
+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) {
+			p_instance->materials.resize(VSG::storage->mesh_get_surface_count(p_instance->base));
+		}
+	}
+
+	_update_instance(p_instance);
+
+	p_instance->update_aabb=false;
+	p_instance->update_materials=false;
+
+	_instance_update_list.remove( &p_instance->update_item );
+}
+
+
+void VisualServerScene::update_dirty_instances() {
+
+	while(_instance_update_list.first()) {
+
+		_update_dirty_instance( _instance_update_list.first()->self() );
+	}
+}
+
+bool VisualServerScene::free(RID p_rid) {
+
+	if (camera_owner.owns(p_rid)) {
+
+		Camera *camera = camera_owner.get( p_rid );
+
+		camera_owner.free(p_rid);
+		memdelete(camera);
+
+	} else if (scenario_owner.owns(p_rid)) {
+
+		Scenario *scenario = scenario_owner.get( p_rid );
+
+		while(scenario->instances.first()) {
+			instance_set_scenario(scenario->instances.first()->self()->self,RID());
+		}
+
+		scenario_owner.free(p_rid);
+		memdelete(scenario);
+
+	} else if (instance_owner.owns(p_rid)) {
+		// delete the instance
+
+		update_dirty_instances();
+
+		Instance *instance = instance_owner.get(p_rid);
+
+		instance_set_room(p_rid,RID());
+		instance_set_scenario(p_rid,RID());
+		instance_set_base(p_rid,RID());
+
+		if (instance->skeleton.is_valid())
+			instance_attach_skeleton(p_rid,RID());
+
+		instance_owner.free(p_rid);
+		memdelete(instance);
+	} else {
+		return false;
+	}
+
+
+	return true;
+}
+
+VisualServerScene *VisualServerScene::singleton=NULL;
+
+VisualServerScene::VisualServerScene() {
+
+
+	render_pass=1;
+	singleton=this;
+
+}

+ 390 - 0
servers/visual/visual_server_scene.h

@@ -0,0 +1,390 @@
+#ifndef VISUALSERVERSCENE_H
+#define VISUALSERVERSCENE_H
+
+#include "servers/visual/rasterizer.h"
+
+#include "geometry.h"
+#include "allocators.h"
+#include "octree.h"
+#include "self_list.h"
+
+class VisualServerScene {
+public:
+
+
+	enum {
+
+		MAX_INSTANCE_CULL=65536,
+		MAX_LIGHTS_CULLED=4096,
+		MAX_ROOM_CULL=32,
+		MAX_EXTERIOR_PORTALS=128,
+	};
+
+	uint64_t render_pass;
+
+
+	static VisualServerScene *singleton;
+#if 0
+	struct Portal {
+
+		bool enabled;
+		float disable_distance;
+		Color disable_color;
+		float connect_range;
+		Vector<Point2> shape;
+		Rect2 bounds;
+
+
+		Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; }
+	};
+
+	struct BakedLight {
+
+		Rasterizer::BakedLightData data;
+		DVector<int> sampler;
+		AABB octree_aabb;
+		Size2i octree_tex_size;
+		Size2i light_tex_size;
+
+	};
+
+	struct BakedLightSampler {
+
+		float params[BAKED_LIGHT_SAMPLER_MAX];
+		int resolution;
+		Vector<Vector3> dp_cache;
+
+		BakedLightSampler() {
+			params[BAKED_LIGHT_SAMPLER_STRENGTH]=1.0;
+			params[BAKED_LIGHT_SAMPLER_ATTENUATION]=1.0;
+			params[BAKED_LIGHT_SAMPLER_RADIUS]=1.0;
+			params[BAKED_LIGHT_SAMPLER_DETAIL_RATIO]=0.1;
+			resolution=16;
+		}
+	};
+
+	void _update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp);
+
+#endif
+
+
+	struct Camera  : public RID_Data {
+
+		enum Type {
+			PERSPECTIVE,
+			ORTHOGONAL
+		};
+		Type type;
+		float fov;
+		float znear,zfar;
+		float size;
+		uint32_t visible_layers;
+		bool vaspect;
+		RID env;
+
+		Transform transform;
+
+		Camera() {
+
+			visible_layers=0xFFFFFFFF;
+			fov=60;
+			type=PERSPECTIVE;
+			znear=0.1; zfar=100;
+			size=1.0;
+			vaspect=false;
+
+		}
+	};
+
+	mutable RID_Owner<Camera> camera_owner;
+
+	virtual RID camera_create();
+	virtual void camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far);
+	virtual void camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far);
+	virtual void camera_set_transform(RID p_camera,const Transform& p_transform);
+	virtual void camera_set_cull_mask(RID p_camera,uint32_t p_layers);
+	virtual void camera_set_environment(RID p_camera,RID p_env);
+	virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable);
+
+
+	/*
+
+	struct RoomInfo {
+
+		Transform affine_inverse;
+		Room *room;
+		List<Instance*> owned_geometry_instances;
+		List<Instance*> owned_portal_instances;
+		List<Instance*> owned_room_instances;
+		List<Instance*> owned_light_instances; //not used, but just for the sake of it
+		Set<Instance*> disconnected_child_portals;
+		Set<Instance*> owned_autoroom_geometry;
+		uint64_t last_visited_pass;
+		RoomInfo() { last_visited_pass=0; }
+
+	};
+
+	struct InstancePortal {
+
+		Portal *portal;
+		Set<Instance*> candidate_set;
+		Instance *connected;
+		uint64_t last_visited_pass;
+
+		Plane plane_cache;
+		Vector<Vector3> transformed_point_cache;
+
+
+		PortalInfo() { connected=NULL; last_visited_pass=0;}
+	};
+*/
+
+	/* ENVIRONMENT API */
+
+	virtual RID environment_create();
+
+	virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg);
+	virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0);
+	virtual void environment_set_bg_color(RID p_env,const Color& p_color);
+	virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer);
+	virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0);
+
+	virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode);
+	virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture);
+
+	virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper);
+	virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness);
+	virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast);
+	virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation);
+	virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp);
+
+
+	/* SCENARIO API */
+
+	struct Instance;
+
+	struct Scenario  : RID_Data {
+
+
+		VS::ScenarioDebugMode debug;
+		RID self;
+		// well wtf, balloon allocator is slower?
+
+		Octree<Instance,true> octree;
+
+		List<Instance*> directional_lights;
+		RID environment;
+		RID fallback_environment;
+
+		SelfList<Instance>::List instances;
+
+		Scenario() {  debug=VS::SCENARIO_DEBUG_DISABLED; }
+	};
+
+	RID_Owner<Scenario> scenario_owner;
+
+	static void* _instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int);
+	static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void*);
+
+	virtual RID scenario_create();
+
+	virtual void scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode);
+	virtual void scenario_set_environment(RID p_scenario, RID p_environment);
+	virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+
+
+	/* INSTANCING API */
+
+	struct InstanceBaseData {
+
+
+		virtual ~InstanceBaseData() {}
+	};
+
+
+
+	struct Instance : RasterizerScene::InstanceBase {
+
+		RID self;
+		//scenario stuff
+		OctreeElementID octree_id;
+		Scenario *scenario;
+		SelfList<Instance> scenario_item;
+
+		//aabb stuff
+		bool update_aabb;
+		bool update_materials;
+		SelfList<Instance> update_item;
+
+
+		AABB aabb;
+		AABB transformed_aabb;
+		float extra_margin;
+		uint32_t object_ID;
+		bool visible;
+		uint32_t layer_mask;
+
+		float lod_begin;
+		float lod_end;
+		float lod_begin_hysteresis;
+		float lod_end_hysteresis;
+		RID lod_instance;
+
+		Instance *room;
+		SelfList<Instance> room_item;
+		bool visible_in_all_rooms;
+
+		uint64_t last_render_pass;
+		uint64_t last_frame_pass;
+
+		uint64_t version; // changes to this, and changes to base increase version
+
+		InstanceBaseData *base_data;
+
+		virtual void base_removed() {
+
+			singleton->instance_set_base(self,RID());
+		}
+
+		virtual void base_changed() {
+
+			singleton->_instance_queue_update(this,true,true);
+		}
+
+
+		Instance() : scenario_item(this), update_item(this), room_item(this) {
+
+			octree_id=0;
+			scenario=NULL;
+
+
+			update_aabb=false;
+			update_materials=false;
+
+			extra_margin=0;
+
+
+			object_ID=0;
+			visible=true;
+			layer_mask=1;
+
+			lod_begin=0;
+			lod_end=0;
+			lod_begin_hysteresis=0;
+			lod_end_hysteresis=0;
+
+			room=NULL;
+			visible_in_all_rooms=false;
+
+
+
+			last_render_pass=0;
+			last_frame_pass=0;
+			version=1;
+			base_data=NULL;
+
+		}
+
+		~Instance() {
+
+			if (base_data)
+				memdelete(base_data);
+
+		}
+	};
+
+	SelfList<Instance>::List _instance_update_list;
+	void _instance_queue_update(Instance *p_instance,bool p_update_aabb,bool p_update_materials=false);
+
+
+	struct InstanceGeometryData : public InstanceBaseData {
+
+		List<Instance*> lighting;
+		bool lighting_dirty;
+
+		InstanceGeometryData() {
+
+			lighting_dirty=false;
+		}
+	};
+
+
+	struct InstanceLightData : public InstanceBaseData {
+
+		struct PairInfo {
+			List<Instance*>::Element *L; //light iterator in geometry
+			Instance *geometry;
+		};
+
+		RID instance;
+		uint64_t last_hash;
+		List<Instance*>::Element *D; // directional light in scenario
+
+		bool shadow_sirty;
+
+		List<PairInfo> geometries;
+
+		InstanceLightData() {
+
+			shadow_sirty=true;
+			D=NULL;
+			last_hash=0;
+		}
+	};
+
+
+	Instance *instance_cull_result[MAX_INSTANCE_CULL];
+	Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
+	Instance *light_cull_result[MAX_LIGHTS_CULLED];
+	RID light_instance_cull_result[MAX_LIGHTS_CULLED];
+	int light_cull_count;
+
+
+	RID_Owner<Instance> instance_owner;
+
+ // from can be mesh, light,  area and portal so far.
+	virtual RID instance_create(); // from can be mesh, light, poly, area and portal so far.
+
+	virtual void instance_set_base(RID p_instance, RID p_base); // from can be mesh, light, poly, area and portal so far.
+	virtual void instance_set_scenario(RID p_instance, RID p_scenario); // from can be mesh, light, poly, area and portal so far.
+	virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
+	virtual void instance_set_transform(RID p_instance, const Transform& p_transform);
+	virtual void instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID);
+	virtual void instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight);
+	virtual void instance_set_surface_material(RID p_instance,int p_surface, RID p_material);
+
+	virtual void instance_attach_skeleton(RID p_instance,RID p_skeleton);
+	virtual void instance_set_exterior( RID p_instance, bool p_enabled );
+	virtual void instance_set_room( RID p_instance, RID p_room );
+
+	virtual void instance_set_extra_visibility_margin( RID p_instance, real_t p_margin );
+
+
+	// don't use these in a game!
+	virtual Vector<ObjectID> instances_cull_aabb(const AABB& p_aabb, RID p_scenario=RID()) const;
+	virtual Vector<ObjectID> instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario=RID()) const;
+	virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane>& p_convex, RID p_scenario=RID()) const;
+
+
+	virtual void instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled);
+	virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting);
+	virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
+
+
+	virtual void instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin);
+	virtual void instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance);
+
+
+	_FORCE_INLINE_ void _update_instance(Instance *p_instance);
+	_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
+	_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
+
+
+	void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size);
+	void update_dirty_instances();
+	bool free(RID p_rid);
+
+	VisualServerScene();
+};
+
+#endif // VISUALSERVERSCENE_H

+ 14 - 0
servers/visual/visual_server_viewport.cpp

@@ -1,8 +1,11 @@
 #include "visual_server_viewport.h"
 #include "visual_server_global.h"
 #include "visual_server_canvas.h"
+#include "visual_server_scene.h"
 #include "globals.h"
 
+
+
 void VisualServerViewport::_draw_viewport(Viewport *p_viewport) {
 
 	/* Camera should always be BEFORE any other 3D */
@@ -58,6 +61,12 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) {
 		}
 	}
 
+
+	if (!p_viewport->disable_3d && p_viewport->camera.is_valid()) {
+
+		VSG::scene->render_camera(p_viewport->camera,p_viewport->scenario,p_viewport->size);
+	}
+
 	if (!p_viewport->hide_canvas) {
 		int i=0;
 
@@ -248,6 +257,11 @@ void VisualServerViewport::draw_viewports() {
 
 		ERR_CONTINUE( !vp->render_target.is_valid() );
 
+		bool visible = vp->viewport_to_screen_rect!=Rect2() || vp->update_mode==VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode==VS::VIEWPORT_UPDATE_ONCE;
+
+		if (!visible)
+			continue;
+
 		VSG::rasterizer->set_current_render_target(vp->render_target);
 		_draw_viewport(vp);
 

+ 746 - 0
servers/visual_server.cpp

@@ -345,8 +345,754 @@ RID VisualServer::get_white_texture() {
 }
 
 
+Error VisualServer::_surface_set_data(Array p_arrays,uint32_t p_format,uint32_t *p_offsets,uint32_t p_stride,DVector<uint8_t> &r_vertex_array,int p_vertex_array_len,DVector<uint8_t> &r_index_array,int p_index_array_len,AABB &r_aabb,Vector<AABB> r_bone_aabb) {
+
+	DVector<uint8_t>::Write vw = r_vertex_array.write();
+
+	DVector<uint8_t>::Write iw;
+	if (r_index_array.size()) {
+		iw=r_index_array.write();
+	}
+
+	int max_bone=0;
+
+
+	for(int ai=0;ai<VS::ARRAY_MAX;ai++) {
+
+		if (!(p_format&(1<<ai))) // no array
+			continue;
+
+
+		switch(ai) {
+
+			case VS::ARRAY_VERTEX: {
+
+				if (p_format& VS::ARRAY_FLAG_USE_2D_VERTICES) {
+
+					DVector<Vector2> array = p_arrays[ai];
+					ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+					DVector<Vector2>::Read read = array.read();
+					const Vector2* src=read.ptr();
+
+					// setting vertices means regenerating the AABB
+					Rect2 aabb;
+
+
+					if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+						for (int i=0;i<p_vertex_array_len;i++) {
+
+
+							uint16_t vector[2]={ Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
+
+							copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(uint16_t)*2);
+
+							if (i==0) {
+
+								aabb=Rect2(src[i],Vector2());
+							} else {
+
+								aabb.expand_to( src[i] );
+							}
+						}
+
+
+					} else {
+						for (int i=0;i<p_vertex_array_len;i++) {
+
+
+							float vector[2]={ src[i].x, src[i].y };
+
+							copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(float)*2);
+
+							if (i==0) {
+
+								aabb=Rect2(src[i],Vector2());
+							} else {
+
+								aabb.expand_to( src[i] );
+							}
+						}
+					}
+
+					r_aabb=AABB(Vector3(aabb.pos.x,aabb.pos.y,0),Vector3(aabb.size.x,aabb.size.y,0));
+
+
+				} else {
+					DVector<Vector3> array = p_arrays[ai];
+					ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+					DVector<Vector3>::Read read = array.read();
+					const Vector3* src=read.ptr();
+
+					// setting vertices means regenerating the AABB
+					AABB aabb;
+
+
+					if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+						for (int i=0;i<p_vertex_array_len;i++) {
+
+
+							uint16_t vector[3]={ Math::make_half_float(src[i].x), Math::make_half_float(src[i].y), Math::make_half_float(src[i].z) };
+
+							copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(uint16_t)*3);
+
+							if (i==0) {
+
+								aabb=AABB(src[i],Vector3());
+							} else {
+
+								aabb.expand_to( src[i] );
+							}
+						}
+
+
+					} else {
+						for (int i=0;i<p_vertex_array_len;i++) {
+
+
+							float vector[3]={ src[i].x, src[i].y, src[i].z };
+
+							copymem(&vw[p_offsets[ai]+i*p_stride], vector, sizeof(float)*3);
+
+							if (i==0) {
+
+								aabb=AABB(src[i],Vector3());
+							} else {
+
+								aabb.expand_to( src[i] );
+							}
+						}
+					}
+
+					r_aabb=aabb;
+
+				}
+
+
+			} break;
+			case VS::ARRAY_NORMAL: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<Vector3> array = p_arrays[ai];
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+				DVector<Vector3>::Read read = array.read();
+				const Vector3* src=read.ptr();
+
+				// setting vertices means regenerating the AABB
+
+				if (p_format&ARRAY_COMPRESS_NORMAL) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint8_t vector[4]={
+							CLAMP(src[i].x*127,-128,127),
+							CLAMP(src[i].y*127,-128,127),
+							CLAMP(src[i].z*127,-128,127),
+							0,
+						};
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], vector, 4);
+
+					}
+
+				} else {
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+
+						float vector[3]={ src[i].x, src[i].y, src[i].z };
+						copymem(&vw[p_offsets[ai]+i*p_stride], vector, 3*4);
+
+					}
+				}
+
+			} break;
+
+			case VS::ARRAY_TANGENT: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<real_t> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len*4, ERR_INVALID_PARAMETER );
+
+
+				DVector<real_t>::Read read = array.read();
+				const real_t* src = read.ptr();
+
+				if (p_format&ARRAY_COMPRESS_TANGENT) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint8_t xyzw[4]={
+							CLAMP(src[i*4+0]*127,-128,127),
+							CLAMP(src[i*4+1]*127,-128,127),
+							CLAMP(src[i*4+2]*127,-128,127),
+							CLAMP(src[i*4+3]*127,-128,127)
+						};
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], xyzw, 4);
+
+					}
+
+
+				} else {
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						float xyzw[4]={
+							src[i*4+0],
+							src[i*4+1],
+							src[i*4+2],
+							src[i*4+3]
+						};
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], xyzw, 4*4);
+
+					}
+				}
+
+			} break;
+			case VS::ARRAY_COLOR: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::COLOR_ARRAY, ERR_INVALID_PARAMETER );
+
+
+				DVector<Color> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER );
+
+
+				DVector<Color>::Read read = array.read();
+				const Color* src = read.ptr();
+
+				if (p_format&ARRAY_COMPRESS_COLOR) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+
+						uint8_t colors[4];
+
+						for(int j=0;j<4;j++) {
+
+							colors[j]=CLAMP( int((src[i][j])*255.0), 0,255 );
+						}
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], colors, 4);
+
+					}
+				} else {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], &src[i], 4*4);
+					}
+
+				}
+
+
+			} break;
+			case VS::ARRAY_TEX_UV: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<Vector2> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER);
+
+				DVector<Vector2>::Read read = array.read();
+
+				const Vector2 * src=read.ptr();
+
+
+
+				if (p_format&ARRAY_COMPRESS_TEX_UV) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint16_t uv[2]={ Math::make_half_float(src[i].x) , Math::make_half_float(src[i].y) };
+						copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*2);
+					}
+
+				} else {
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						float uv[2]={ src[i].x , src[i].y };
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*4);
+
+					}
+				}
+
+
+			} break;
+
+			case VS::ARRAY_TEX_UV2: {
+
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::VECTOR2_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<Vector2> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len , ERR_INVALID_PARAMETER);
+
+				DVector<Vector2>::Read read = array.read();
+
+				const Vector2 * src=read.ptr();
+
+
+
+				if (p_format&ARRAY_COMPRESS_TEX_UV2) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint16_t uv[2]={ Math::make_half_float(src[i].x) , Math::make_half_float(src[i].y) };
+						copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*2);
+					}
+
+				} else {
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						float uv[2]={ src[i].x , src[i].y };
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], uv, 2*4);
+
+					}
+				}
+			} break;
+			case VS::ARRAY_WEIGHTS: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<real_t> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
+
+
+				DVector<real_t>::Read read = array.read();
+
+				const real_t * src = read.ptr();
+
+				if (p_format&ARRAY_COMPRESS_WEIGHTS) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
+						for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+							data[j]=CLAMP(src[i*VS::ARRAY_WEIGHTS_SIZE+j]*65535,0,65535);
+						}
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], data, 2*4);
+					}
+				} else {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						float data[VS::ARRAY_WEIGHTS_SIZE];
+						for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+							data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
+						}
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], data, 4*4);
+
+
+					}
+				}
+
+			} break;
+			case VS::ARRAY_BONES: {
+
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<int> array = p_arrays[ai];
+
+				ERR_FAIL_COND_V( array.size() != p_vertex_array_len*VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER );
+
+
+				DVector<int>::Read read = array.read();
+
+				const int * src = read.ptr();
+
+
+				if (!(p_format&ARRAY_FLAG_USE_16_BIT_BONES)) {
+
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint8_t data[VS::ARRAY_WEIGHTS_SIZE];
+						for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+							data[j]=CLAMP(src[i*VS::ARRAY_WEIGHTS_SIZE+j],0,255);
+							max_bone=MAX(data[j],max_bone);
+
+						}
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], data, 4);
+
+
+					}
+
+				} else {
+					for (int i=0;i<p_vertex_array_len;i++) {
+
+						uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
+						for (int j=0;j<VS::ARRAY_WEIGHTS_SIZE;j++) {
+							data[j]=src[i*VS::ARRAY_WEIGHTS_SIZE+j];
+							max_bone=MAX(data[j],max_bone);
+
+						}
+
+						copymem(&vw[p_offsets[ai]+i*p_stride], data, 2*4);
+
+
+					}
+				}
+
+
+			} break;
+			case VS::ARRAY_INDEX: {
+
+
+				ERR_FAIL_COND_V( p_index_array_len<=0, ERR_INVALID_DATA );
+				ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER );
+
+				DVector<int> indices = p_arrays[ai];
+				ERR_FAIL_COND_V( indices.size() == 0, ERR_INVALID_PARAMETER );
+				ERR_FAIL_COND_V( indices.size() != p_index_array_len, ERR_INVALID_PARAMETER );
+
+				/* determine wether using 16 or 32 bits indices */
+
+				DVector<int>::Read read = indices.read();
+				const int *src=read.ptr();
+
+				for (int i=0;i<p_index_array_len;i++) {
+
+
+					if (p_vertex_array_len<(1<<16)) {
+						uint16_t v=src[i];
+
+						copymem(&iw[i*2], &v, 2);
+					} else {
+						uint32_t v=src[i];
+
+						copymem(&iw[i*4], &v, 4);
+					}
+				}
+			} break;
+			default: {
+				ERR_FAIL_V( ERR_INVALID_DATA );
+			}
+		}
+	}
+
+
+	if (p_format&VS::ARRAY_FORMAT_BONES) {
+		//create AABBs for each detected bone
+		int total_bones = max_bone+1;
+
+		bool first = r_bone_aabb.size()==0;
+
+		r_bone_aabb.resize(total_bones);
+
+		if (first) {
+			for(int i=0;i<total_bones;i++) {
+				r_bone_aabb[i].size==Vector3(-1,-1,-1); //negative means unused
+			}
+		}
+
+		DVector<Vector3> vertices = p_arrays[VS::ARRAY_VERTEX];
+		DVector<int> bones = p_arrays[VS::ARRAY_BONES];
+		DVector<float> weights = p_arrays[VS::ARRAY_WEIGHTS];
+
+		bool any_valid=false;
+
+		if (vertices.size() && bones.size()==vertices.size()*4 && weights.size()==bones.size()) {
+
+			int vs = vertices.size();
+			DVector<Vector3>::Read rv =vertices.read();
+			DVector<int>::Read rb=bones.read();
+			DVector<float>::Read rw=weights.read();
+
+			AABB *bptr = r_bone_aabb.ptr();
+
+			for(int i=0;i<vs;i++) {
+
+				Vector3 v = rv[i];
+				for(int j=0;j<4;j++) {
+
+					int idx = rb[i*4+j];
+					float w = rw[i*4+j];
+					if (w==0)
+						continue;//break;
+					ERR_FAIL_INDEX_V(idx,total_bones,ERR_INVALID_DATA);
+
+					if (bptr->size.x<0) {
+						//first
+						bptr[idx]=AABB();
+						bptr[idx].pos=v;
+						any_valid=true;
+					} else {
+						bptr[idx].expand_to(v);
+					}
+				}
+			}
+		}
+
+		if (!any_valid && first) {
+
+			r_bone_aabb.clear();
+		}
+	}
+	return OK;
+}
+
+
 void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,uint32_t p_compress_format) {
 
+	ERR_FAIL_INDEX( p_primitive, VS::PRIMITIVE_MAX );
+	ERR_FAIL_COND(p_arrays.size()!=VS::ARRAY_MAX);
+
+	uint32_t format=0;
+
+	// validation
+	int index_array_len=0;
+	int array_len=0;
+
+	for(int i=0;i<p_arrays.size();i++) {
+
+		if (p_arrays[i].get_type()==Variant::NIL)
+			continue;
+
+		format|=(1<<i);
+
+		if (i==VS::ARRAY_VERTEX) {
+
+			Variant var = p_arrays[i];
+			switch(var.get_type()) {
+				case Variant::VECTOR2_ARRAY: {
+					DVector<Vector2> v2 = var;
+					array_len=v2.size();
+				} break;
+				case Variant::VECTOR3_ARRAY: {
+					DVector<Vector3> v3 = var;
+					array_len=v3.size();
+				} break;
+				default: {
+					Array v = var;
+					array_len=v.size();
+				} break;
+			}
+
+			array_len=Vector3Array(p_arrays[i]).size();
+			ERR_FAIL_COND(array_len==0);
+		} else if (i==VS::ARRAY_INDEX) {
+
+			index_array_len=IntArray(p_arrays[i]).size();
+		}
+	}
+
+	ERR_FAIL_COND((format&VS::ARRAY_FORMAT_VERTEX)==0); // mandatory
+
+
+	if (p_blend_shapes.size()) {
+		//validate format for morphs
+		for(int i=0;i<p_blend_shapes.size();i++) {
+
+			uint32_t bsformat=0;
+			Array arr = p_blend_shapes[i];
+			for(int j=0;j<arr.size();j++) {
+
+
+				if (arr[j].get_type()!=Variant::NIL)
+					bsformat|=(1<<j);
+			}
+
+			ERR_FAIL_COND( (bsformat)!=(format&(VS::ARRAY_FORMAT_BONES-1)));
+		}
+	}
+
+	uint32_t offsets[VS::ARRAY_MAX];
+
+	int total_elem_size=0;
+
+	for (int i=0;i<VS::ARRAY_MAX;i++) {
+
+
+		offsets[i]=0; //reset
+
+		if (!(format&(1<<i))) // no array
+			continue;
+
+
+		int elem_size=0;
+
+		switch(i) {
+
+			case VS::ARRAY_VERTEX: {
+
+				Variant arr = p_arrays[0];
+				if (arr.get_type()==Variant::VECTOR2_ARRAY) {
+					elem_size=2;
+					p_compress_format|=ARRAY_FLAG_USE_2D_VERTICES;
+				} else if (arr.get_type()==Variant::VECTOR3_ARRAY) {
+					p_compress_format&=~ARRAY_FLAG_USE_2D_VERTICES;
+					elem_size=3;
+				} else {
+					elem_size=(p_compress_format&ARRAY_FLAG_USE_2D_VERTICES)?2:3;
+				}
+
+				if (p_compress_format&ARRAY_COMPRESS_VERTEX) {
+					elem_size*=sizeof(int16_t);
+				} else {
+					elem_size*=sizeof(float);
+				}
+
+			} break;
+			case VS::ARRAY_NORMAL: {
+
+				if (p_compress_format&ARRAY_COMPRESS_NORMAL) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*3;
+				}
+
+			} break;
+
+			case VS::ARRAY_TANGENT: {
+				if (p_compress_format&ARRAY_COMPRESS_TANGENT) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+
+			} break;
+			case VS::ARRAY_COLOR: {
+
+				if (p_compress_format&ARRAY_COMPRESS_COLOR) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+			} break;
+			case VS::ARRAY_TEX_UV: {
+				if (p_compress_format&ARRAY_COMPRESS_TEX_UV) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*2;
+				}
+
+			} break;
+
+			case VS::ARRAY_TEX_UV2: {
+				if (p_compress_format&ARRAY_COMPRESS_TEX_UV2) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*2;
+				}
+
+			} break;
+			case VS::ARRAY_WEIGHTS: {
+
+				if (p_compress_format&ARRAY_COMPRESS_WEIGHTS) {
+					elem_size=sizeof(uint16_t)*4;
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+
+			} break;
+			case VS::ARRAY_BONES: {
+
+				if (p_compress_format&ARRAY_FLAG_USE_16_BIT_BONES) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(uint16_t)*4;
+				}
+
+			} break;
+			case VS::ARRAY_INDEX: {
+
+				if (index_array_len<=0) {
+					ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+					break;
+				}
+				/* determine wether using 16 or 32 bits indices */
+				if (array_len>(1<<16)) {
+
+					elem_size=4;
+
+				} else {
+					elem_size=2;
+				}
+				offsets[i]=elem_size;
+				continue;
+			} break;
+			default: {
+				ERR_FAIL( );
+			}
+		}
+
+		print_line("type "+itos(i)+" size: "+itos(elem_size)+" offset "+itos(total_elem_size));
+		offsets[i]=total_elem_size;
+		total_elem_size+=elem_size;
+
+
+	}
+
+	print_line("total elemn size: "+itos(total_elem_size));
+
+	uint32_t mask = (1<<ARRAY_MAX)-1;
+	format|=~mask&p_compress_format; //make the full format
+
+
+	int array_size = total_elem_size * array_len;
+
+	print_line("array size: "+itos(array_size));
+
+	DVector<uint8_t> vertex_array;
+	vertex_array.resize(array_size);
+
+	int index_array_size = offsets[VS::ARRAY_INDEX]*index_array_len;
+
+	print_line("index array size: "+itos(index_array_size));
+
+	DVector<uint8_t> index_array;
+	index_array.resize(index_array_size);
+
+	AABB aabb;
+	Vector<AABB> bone_aabb;
+
+	Error err = _surface_set_data(p_arrays,format,offsets,total_elem_size,vertex_array,array_len,index_array,index_array_len,aabb,bone_aabb);
+
+	if (err) {
+		ERR_EXPLAIN("Invalid array format for surface");
+		ERR_FAIL_COND(err!=OK);
+	}
+
+	Vector<DVector<uint8_t> > blend_shape_data;
+
+	for(int i=0;i<p_blend_shapes.size();i++) {
+
+		DVector<uint8_t> vertex_array_shape;
+		vertex_array_shape.resize(array_size);
+		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);
+		aabb.merge_with(laabb);
+		if (err) {
+			ERR_EXPLAIN("Invalid blend shape array format for surface");
+			ERR_FAIL_COND(err!=OK);
+		}
+
+		blend_shape_data.push_back(vertex_array_shape);
+	}
+
+	mesh_add_surface(p_mesh,format,p_primitive,vertex_array,array_len,index_array,index_array_len,aabb,blend_shape_data,bone_aabb);
 
 }
 

+ 6 - 2
servers/visual_server.h

@@ -59,6 +59,9 @@ protected:
 	RID test_material;
 	RID material_2d[16];
 
+
+	Error _surface_set_data(Array p_arrays,uint32_t p_format,uint32_t *p_offsets,uint32_t p_stride,DVector<uint8_t> &r_vertex_array,int p_vertex_array_len,DVector<uint8_t> &r_index_array,int p_index_array_len,AABB &r_aabb,Vector<AABB> r_bone_aabb);
+
 	static VisualServer* (*create_func)();
 	static void _bind_methods();
 public:
@@ -207,6 +210,7 @@ public:
 		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_BONES|ARRAY_COMPRESS_WEIGHTS|ARRAY_COMPRESS_INDEX
 
@@ -228,7 +232,7 @@ public:
 
 
 	virtual void mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array(),uint32_t p_compress_format=ARRAY_COMPRESS_DEFAULT);
-	virtual void mesh_add_surface(RID p_mesh,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 Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >())=0;
+	virtual void mesh_add_surface(RID p_mesh,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>())=0;
 
 	virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount)=0;
 	virtual int mesh_get_morph_target_count(RID p_mesh) const=0;
@@ -530,7 +534,6 @@ public:
 
 	virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode)=0;
 	virtual void scenario_set_environment(RID p_scenario, RID p_environment)=0;
-	virtual RID scenario_get_environment(RID p_scenario, RID p_environment) const=0;
 	virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment)=0;
 
 
@@ -546,6 +549,7 @@ public:
 		INSTANCE_REFLECTION_PROBE,
 		INSTANCE_ROOM,
 		INSTANCE_PORTAL,
+		INSTANCE_MAX,
 		/*INSTANCE_BAKED_LIGHT,
 		INSTANCE_BAKED_LIGHT_SAMPLER,*/
 

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

@@ -2349,6 +2349,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 
 	spatial_editor=p_spatial_editor;
 	ViewportContainer *c=memnew(ViewportContainer);
+	c->set_stretch(true);
 	add_child(c);
 	c->set_area_as_parent_rect();
 	viewport = memnew( Viewport );