Browse Source

all light types and shadows are working, pending a lot of clean-up

Juan Linietsky 8 years ago
parent
commit
cacf9ebb7f
38 changed files with 2846 additions and 410 deletions
  1. 22 0
      core/math/camera_matrix.cpp
  2. 2 0
      core/math/camera_matrix.h
  3. 1 1
      core/math/math_funcs.h
  4. 0 2
      drivers/gles3/rasterizer_canvas_gles3.cpp
  5. 457 195
      drivers/gles3/rasterizer_scene_gles3.cpp
  6. 58 16
      drivers/gles3/rasterizer_scene_gles3.h
  7. 310 14
      drivers/gles3/rasterizer_storage_gles3.cpp
  8. 77 24
      drivers/gles3/rasterizer_storage_gles3.h
  9. 14 1
      drivers/gles3/shader_compiler_gles3.cpp
  10. 7 0
      drivers/gles3/shader_compiler_gles3.h
  11. 1 0
      drivers/gles3/shaders/SCsub
  12. 79 0
      drivers/gles3/shaders/cube_to_dp.glsl
  13. 286 55
      drivers/gles3/shaders/scene.glsl
  14. 22 1
      main/main.cpp
  15. 80 11
      scene/3d/light.cpp
  16. 54 17
      scene/3d/light.h
  17. 1 1
      scene/3d/navigation_mesh.cpp
  18. 1 1
      scene/main/scene_main_loop.cpp
  19. 61 0
      scene/main/viewport.cpp
  20. 22 2
      scene/main/viewport.h
  21. 1 1
      scene/resources/material.cpp
  22. 92 10
      scene/resources/mesh.cpp
  23. 3 1
      scene/resources/mesh.h
  24. 1 1
      scene/resources/mesh_data_tool.cpp
  25. 1 1
      scene/resources/shape.cpp
  26. 1 1
      scene/resources/surface_tool.cpp
  27. 35 2
      servers/visual/rasterizer.h
  28. 1 1
      servers/visual/shader_types.cpp
  29. 9 1
      servers/visual/visual_server_raster.h
  30. 605 33
      servers/visual/visual_server_scene.cpp
  31. 14 5
      servers/visual/visual_server_scene.h
  32. 25 2
      servers/visual/visual_server_viewport.cpp
  33. 7 0
      servers/visual/visual_server_viewport.h
  34. 449 1
      servers/visual_server.cpp
  35. 26 2
      servers/visual_server.h
  36. 1 1
      tools/editor/io_plugins/editor_import_collada.cpp
  37. 14 0
      tools/editor/plugins/spatial_editor_plugin.cpp
  38. 6 6
      tools/editor/spatial_editor_gizmos.cpp

+ 22 - 0
core/math/camera_matrix.cpp

@@ -495,6 +495,28 @@ void CameraMatrix::set_light_bias() {
 
 }
 
+void CameraMatrix::set_light_atlas_rect(const Rect2& p_rect) {
+
+	float *m=&matrix[0][0];
+
+	m[0]=p_rect.size.width,
+	m[1]=0.0,
+	m[2]=0.0,
+	m[3]=0.0,
+	m[4]=0.0,
+	m[5]=p_rect.size.height,
+	m[6]=0.0,
+	m[7]=0.0,
+	m[8]=0.0,
+	m[9]=0.0,
+	m[10]=1.0,
+	m[11]=0.0,
+	m[12]=p_rect.pos.x,
+	m[13]=p_rect.pos.y,
+	m[14]=0.0,
+	m[15]=1.0;
+}
+
 CameraMatrix::operator String() const {
 
 	String str;

+ 2 - 0
core/math/camera_matrix.h

@@ -30,6 +30,7 @@
 #define CAMERA_MATRIX_H
 
 #include "transform.h"
+#include "math_2d.h"
 /**
 	@author Juan Linietsky <[email protected]>
 */
@@ -53,6 +54,7 @@ struct CameraMatrix {
 	void set_identity();
 	void set_zero();
 	void set_light_bias();
+	void set_light_atlas_rect(const Rect2& p_rect);
 	void set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov=false);
 	void set_orthogonal(float p_left, float p_right, float p_bottom, float p_top,  float p_znear, float p_zfar);
 	void set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov=false);

+ 1 - 1
core/math/math_funcs.h

@@ -208,7 +208,7 @@ public:
 	    }
 	}
 
-	static _FORCE_INLINE_ float halfptr_to_float(uint16_t *h) {
+	static _FORCE_INLINE_ float halfptr_to_float(const uint16_t *h) {
 
 		union {
 			uint32_t u32;

+ 0 - 2
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -824,8 +824,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
 
 	bool prev_distance_field=false;
 
-
-
 	while(p_item_list) {
 
 		Item *ci=p_item_list;

File diff suppressed because it is too large
+ 457 - 195
drivers/gles3/rasterizer_scene_gles3.cpp


+ 58 - 16
drivers/gles3/rasterizer_scene_gles3.h

@@ -3,6 +3,7 @@
 
 #include "rasterizer_storage_gles3.h"
 #include "drivers/gles3/shaders/scene.glsl.h"
+#include "drivers/gles3/shaders/cube_to_dp.glsl.h"
 
 class RasterizerSceneGLES3 : public RasterizerScene {
 public:
@@ -16,10 +17,13 @@ public:
 	uint32_t current_geometry_index;
 
 	RID default_material;
+	RID default_material_twosided;
 	RID default_shader;
+	RID default_shader_twosided;
 
 	RasterizerStorageGLES3 *storage;
 
+
 	struct State {
 
 
@@ -29,6 +33,7 @@ public:
 		int current_depth_draw;
 
 		SceneShaderGLES3 scene_shader;
+		CubeToDpShaderGLES3 cube_to_dp_shader;
 
 
 		struct SceneDataUBO {
@@ -41,6 +46,12 @@ public:
 			float bg_color[4];
 			float ambient_energy;
 			float bg_energy;
+			float shadow_z_offset;
+			float shadow_slope_scale;
+			float shadow_dual_paraboloid_render_zfar;
+			float shadow_dual_paraboloid_render_side;
+			float shadow_atlas_pixel_size[2];
+			float shadow_directional_pixel_size[2];
 
 		} ubo_data;
 
@@ -62,7 +73,7 @@ public:
 		GLuint skybox_verts;
 		GLuint skybox_array;
 
-
+		bool cull_front;
 
 	} state;
 
@@ -71,7 +82,6 @@ public:
 	struct ShadowAtlas : public RID_Data {
 
 		enum {
-			SHADOW_INDEX_DIRTY_BIT=(1<<31),
 			QUADRANT_SHIFT=27,
 			SHADOW_INDEX_MASK=(1<<QUADRANT_SHIFT)-1,
 			SHADOW_INVALID=0xFFFFFFFF
@@ -111,13 +121,35 @@ public:
 		Map<RID,uint32_t> shadow_owners;
 	};
 
+	struct ShadowCubeMap {
+
+		GLuint fbo_id[6];
+		GLuint cubemap;
+		int size;
+	};
+
+	Vector<ShadowCubeMap> shadow_cubemaps;
+
 	RID_Owner<ShadowAtlas> shadow_atlas_owner;
 
 	RID shadow_atlas_create();
 	void shadow_atlas_set_size(RID p_atlas,int p_size);
 	void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision);
 	bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
-	uint32_t shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version);
+	bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version);
+
+
+	struct DirectionalShadow {
+		GLuint fbo;
+		GLuint depth;
+		int light_count;
+		int size;
+		int current_light;
+	} directional_shadow;
+
+	virtual int get_directional_light_shadow_size(RID p_light_intance);
+	virtual void set_directional_shadow_count(int p_count);
+
 
 	/* ENVIRONMENT API */
 
@@ -174,12 +206,12 @@ public:
 
 	struct LightInstance : public RID_Data {
 
-		struct SplitInfo {
+		struct ShadowTransform {
 
 			CameraMatrix camera;
 			Transform transform;
-			float near;
 			float far;
+			float split;
 		};
 
 		struct LightDataUBO {
@@ -188,6 +220,7 @@ public:
 			float light_direction_attenuation[4];
 			float light_color_energy[4];
 			float light_params[4]; //cone attenuation, specular, shadow darkening,
+			float light_clamp[4]; //cone attenuation, specular, shadow darkening,
 			float shadow_split_offsets[4];
 			float shadow_matrix1[16];
 			float shadow_matrix2[16];
@@ -197,13 +230,11 @@ public:
 		} light_ubo_data;
 
 
-		SplitInfo split_info[4];
+		ShadowTransform shadow_transform[4];
 
+		RID self;
 		RID light;
 		RasterizerStorageGLES3::Light *light_ptr;
-
-		CameraMatrix shadow_matrix[4];
-
 		Transform transform;
 
 		Vector3 light_vector;
@@ -214,12 +245,17 @@ public:
 
 		uint64_t shadow_pass;
 		uint64_t last_scene_pass;
+		uint64_t last_scene_shadow_pass;
 		uint64_t last_pass;
 		uint16_t light_index;
+		uint16_t light_directional_index;
+
+		uint32_t current_shadow_atlas_key;
 
 		Vector2 dp;
 
-		CameraMatrix shadow_projection[4];
+		Rect2 directional_rect;
+
 
 		Set<RID> shadow_atlases; //shadow atlases where this light is registered
 
@@ -231,6 +267,7 @@ public:
 
 	virtual RID light_instance_create(RID p_light);
 	virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
+	virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass);
 	virtual void light_instance_mark_visible(RID p_light_instance);
 
 	/* RENDER LIST */
@@ -371,26 +408,31 @@ public:
 
 	RenderList render_list;
 
+	_FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull);
+
 	_FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass);
 	_FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection);
 	_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
 	_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
 	_FORCE_INLINE_ void _setup_light(LightInstance *p_light);
 
-	void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass);
+	void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow);
 
 
-	_FORCE_INLINE_ void _add_geometry(  RasterizerStorageGLES3::Geometry* p_geometry,  InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material);
+	_FORCE_INLINE_ void _add_geometry(  RasterizerStorageGLES3::Geometry* p_geometry,  InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow);
 
-	void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale);
+	void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale);
 
-	void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform);
-	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform,const CameraMatrix& p_camera_projection);
+	void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform);
+	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas);
 	void _copy_screen();
 	void _copy_to_front_buffer(Environment *env);
+	void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug
 
-	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);
+	void _fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow);
 
+	virtual void render_scene(const Transform& p_cam_transform,const 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_environment,RID p_shadow_atlas);
+	virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count);
 	virtual bool free(RID p_rid);
 
 	void _generate_brdf();

+ 310 - 14
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1290,12 +1290,13 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 
 			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_scene.render_mode_values["cull_disabled"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED);
 
 			shaders.actions_scene.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded;
 			shaders.actions_scene.render_mode_flags["ontop"]=&p_shader->spatial.ontop;
 
 			shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
+			shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex;
 
 			actions=&shaders.actions_scene;
 			actions->uniforms=&p_shader->uniforms;
@@ -1318,6 +1319,9 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 	p_shader->texture_count=gen_code.texture_uniforms.size();
 	p_shader->texture_hints=gen_code.texture_hints;
 
+	p_shader->uses_vertex_time=gen_code.uses_vertex_time;
+	p_shader->uses_fragment_time=gen_code.uses_fragment_time;
+
 	//all materials using this shader will have to be invalidated, unfortunately
 
 	for (SelfList<Material>* E = p_shader->materials.first();E;E=E->next() ) {
@@ -1535,6 +1539,57 @@ void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_wid
 
 }
 
+bool RasterizerStorageGLES3::material_is_animated(RID p_material)  {
+
+	Material *material = material_owner.get(  p_material );
+	ERR_FAIL_COND_V(!material,false);
+	if (material->dirty_list.in_list()) {
+		_update_material(material);
+	}
+
+	return material->is_animated_cache;
+
+}
+bool RasterizerStorageGLES3::material_casts_shadows(RID p_material)  {
+
+	Material *material = material_owner.get(  p_material );
+	ERR_FAIL_COND_V(!material,false);
+	if (material->dirty_list.in_list()) {
+		_update_material(material);
+	}
+
+	return material->can_cast_shadow_cache;
+}
+
+void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+	Material *material = material_owner.get(  p_material );
+	ERR_FAIL_COND(!material);
+
+	Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance);
+	if (E) {
+		E->get()++;
+	} else {
+		material->instance_owners[p_instance]=1;
+	}
+}
+
+void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+	Material *material = material_owner.get(  p_material );
+	ERR_FAIL_COND(!material);
+
+	Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance);
+	ERR_FAIL_COND(!E);
+	E->get()--;
+
+	if (E->get()==0) {
+		material->instance_owners.erase(E);
+	}
+}
+
+
+
 _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data,bool p_linear_color) {
 	switch(type) {
 		case ShaderLanguage::TYPE_BOOL: {
@@ -2011,6 +2066,48 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
 	if (material->dirty_list.in_list())
 		_material_dirty_list.remove( &material->dirty_list );
 
+
+	if (material->shader && material->shader->dirty_list.in_list()) {
+		_update_shader(material->shader);
+	}
+	//update caches
+
+	{
+		bool can_cast_shadow = false;
+		bool is_animated = false;
+
+		if (material->shader && material->shader->mode==VS::SHADER_SPATIAL) {
+			if (!material->shader->spatial.uses_alpha && material->shader->spatial.blend_mode==Shader::Spatial::BLEND_MODE_MIX) {
+				can_cast_shadow=true;
+			}
+
+			if (material->shader->spatial.uses_discard && material->shader->uses_fragment_time) {
+				is_animated=true;
+			}
+
+			if (material->shader->spatial.uses_vertex && material->shader->uses_vertex_time) {
+				is_animated=true;
+			}
+
+		}
+
+		if (can_cast_shadow!=material->can_cast_shadow_cache || is_animated!=material->is_animated_cache) {
+			material->can_cast_shadow_cache=can_cast_shadow;
+			material->is_animated_cache=is_animated;
+
+			for(Map<Instantiable*,int>::Element *E=material->instantiable_owners.front();E;E=E->next()) {
+				E->key()->instance_material_change_notify();
+			}
+
+			for(Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.front();E;E=E->next()) {
+				E->key()->base_material_changed();
+			}
+
+		}
+
+	}
+
+
 	//clear ubo if it needs to be cleared
 	if (material->ubo_size) {
 
@@ -2102,6 +2199,36 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
 
 }
 
+void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) {
+
+	Material * material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+
+	Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+
+	if (I) {
+		I->get()++;
+	} else {
+		material->instantiable_owners[p_instantiable]=1;
+	}
+
+}
+
+void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) {
+
+	Material * material = material_owner.getornull(p_material);
+	ERR_FAIL_COND(!material);
+
+	Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+	ERR_FAIL_COND(!I);
+
+	I->get()--;
+	if (I->get()==0) {
+		material->instantiable_owners.erase(I);
+	}
+}
+
+
 void RasterizerStorageGLES3::update_dirty_materials() {
 
 	while( _material_dirty_list.first() ) {
@@ -2406,6 +2533,8 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 	surface->active=true;
 	surface->array_len=p_vertex_count;
 	surface->index_array_len=p_index_count;
+	surface->array_byte_size=p_array.size();
+	surface->index_array_byte_size=p_index_array.size();
 	surface->primitive=p_primitive;
 	surface->mesh=mesh;
 	surface->format=p_format;
@@ -2556,8 +2685,22 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface
 	ERR_FAIL_COND(!mesh);
 	ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
 
+	if (mesh->surfaces[p_surface]->material==p_material)
+		return;
+
+	if (mesh->surfaces[p_surface]->material.is_valid()) {
+		_material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh);
+	}
+
 	mesh->surfaces[p_surface]->material=p_material;
 
+	if (mesh->surfaces[p_surface]->material.is_valid()) {
+		_material_add_instantiable(mesh->surfaces[p_surface]->material,mesh);
+	}
+
+	mesh->instance_material_change_notify();
+
+
 }
 RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{
 
@@ -2595,17 +2738,17 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int
 	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);
+	void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_byte_size,GL_MAP_READ_BIT);
 
 	ERR_FAIL_COND_V(!data,DVector<uint8_t>());
 
 	DVector<uint8_t> ret;
-	ret.resize(surface->array_len);
+	ret.resize(surface->array_byte_size);
 
 	{
 
 		DVector<uint8_t>::Write w = ret.write();
-		copymem(w.ptr(),data,surface->array_len);
+		copymem(w.ptr(),data,surface->array_byte_size);
 	}
 	glUnmapBuffer(GL_ARRAY_BUFFER);
 
@@ -2622,18 +2765,18 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh
 
 	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);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+	void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_byte_size,GL_MAP_READ_BIT);
 
 	ERR_FAIL_COND_V(!data,DVector<uint8_t>());
 
 	DVector<uint8_t> ret;
-	ret.resize(surface->index_array_len);
+	ret.resize(surface->index_array_byte_size);
 
 	{
 
 		DVector<uint8_t>::Write w = ret.write();
-		copymem(w.ptr(),data,surface->index_array_len);
+		copymem(w.ptr(),data,surface->index_array_byte_size);
 	}
 
 	glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
@@ -2662,6 +2805,59 @@ VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_
 	return mesh->surfaces[p_surface]->primitive;
 }
 
+AABB RasterizerStorageGLES3::mesh_surface_get_aabb(RID p_mesh, int p_surface) const {
+
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,AABB());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),AABB());
+
+	return mesh->surfaces[p_surface]->aabb;
+
+
+}
+Vector<DVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const{
+
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,Vector<DVector<uint8_t> >());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<DVector<uint8_t> >());
+
+	Vector<DVector<uint8_t> > bsarr;
+
+	for(int i=0;i<mesh->surfaces[p_surface]->morph_targets.size();i++) {
+
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh->surfaces[p_surface]->morph_targets[i].vertex_id);
+		void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,mesh->surfaces[p_surface]->array_byte_size,GL_MAP_READ_BIT);
+
+		ERR_FAIL_COND_V(!data,Vector<DVector<uint8_t> >());
+
+		DVector<uint8_t> ret;
+		ret.resize(mesh->surfaces[p_surface]->array_byte_size);
+
+		{
+
+			DVector<uint8_t>::Write w = ret.write();
+			copymem(w.ptr(),data,mesh->surfaces[p_surface]->array_byte_size);
+		}
+
+		bsarr.push_back(ret);
+
+		glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+	}
+
+	return bsarr;
+
+}
+Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const{
+
+	const Mesh *mesh = mesh_owner.getornull(p_mesh);
+	ERR_FAIL_COND_V(!mesh,Vector<AABB >());
+	ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<AABB >());
+
+	return mesh->surfaces[p_surface]->skeleton_bone_aabb;
+
+}
+
+
 void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
 
 	Mesh *mesh = mesh_owner.getornull(p_mesh);
@@ -2670,6 +2866,10 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
 
 	Surface *surface = mesh->surfaces[p_surface];
 
+	if (surface->material.is_valid()) {
+		_material_remove_instantiable(surface->material,mesh);
+	}
+
 	glDeleteBuffers(1,&surface->vertex_id);
 	if (surface->index_id) {
 		glDeleteBuffers(1,&surface->index_id);
@@ -2683,6 +2883,8 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
 		glDeleteVertexArrays(1,&surface->morph_targets[i].array_id);
 	}
 
+	mesh->instance_material_change_notify();
+
 	memdelete(surface);
 
 	mesh->surfaces.remove(p_surface);
@@ -2971,7 +3173,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){
 	light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1;
 	light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3;
 	light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6;
-	light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET]=1.0;
 	light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]=0.1;
 	light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]=0.1;
 
@@ -2981,6 +3182,10 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){
 	light->negative=false;
 	light->cull_mask=0xFFFFFFFF;
 	light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+	light->omni_shadow_mode=VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+	light->omni_shadow_detail=VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
+
+	light->version=0;
 
 	return light_owner.make_rid(light);
 }
@@ -2998,9 +3203,23 @@ void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param,
 	ERR_FAIL_COND(!light);
 	ERR_FAIL_INDEX(p_param,VS::LIGHT_PARAM_MAX);
 
-	if (p_param==VS::LIGHT_PARAM_RANGE || p_param==VS::LIGHT_PARAM_SPOT_ANGLE) {
-		light->instance_change_notify();
+	switch(p_param) {
+		case VS::LIGHT_PARAM_RANGE:
+		case VS::LIGHT_PARAM_SPOT_ANGLE:
+		case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
+		case VS::LIGHT_PARAM_SHADOW_DARKNESS:
+		case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
+		case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
+		case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
+		case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
+		case VS::LIGHT_PARAM_SHADOW_BIAS:
+		case VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE: {
+
+			light->version++;
+			light->instance_change_notify();
+		} break;
 	}
+
 	light->param[p_param]=p_value;
 }
 void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){
@@ -3009,6 +3228,10 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){
 	ERR_FAIL_COND(!light);
 	light->shadow=p_enabled;
 
+	light->version++;
+	light->instance_change_notify();
+
+
 }
 void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){
 
@@ -3021,9 +3244,8 @@ void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_text
 
 	Light * light = light_owner.getornull(p_light);
 	ERR_FAIL_COND(!light);
-
-
 }
+
 void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){
 
 	Light * light = light_owner.getornull(p_light);
@@ -3037,6 +3259,10 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){
 	ERR_FAIL_COND(!light);
 
 	light->cull_mask=p_mask;
+
+	light->version++;
+	light->instance_change_notify();
+
 }
 void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){
 
@@ -3045,22 +3271,92 @@ void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){
 
 }
 
+void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) {
+
+	Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND(!light);
+
+	light->omni_shadow_mode=p_mode;
+
+	light->version++;
+	light->instance_change_notify();
+
+
+}
+
+VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI_SHADOW_CUBE);
+
+	return light->omni_shadow_mode;
+}
+
+
+void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail) {
+
+	Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND(!light);
+
+	light->omni_shadow_detail=p_detail;
+	light->version++;
+	light->instance_change_notify();
+}
+
 
 void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){
 
 	Light * light = light_owner.getornull(p_light);
 	ERR_FAIL_COND(!light);
 
+	light->directional_shadow_mode=p_mode;
+	light->version++;
+	light->instance_change_notify();
+
+}
+
+VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+
+	return light->directional_shadow_mode;
 }
 
+
 VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
 
 	const Light * light = light_owner.getornull(p_light);
 	ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
 
-	return VS::LIGHT_DIRECTIONAL;
+	return light->type;
 }
 
+float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param) {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
+
+	return light->param[p_param];
+}
+
+bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
+
+	return light->shadow;
+}
+
+uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,0);
+
+	return light->version;
+}
+
+
 AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const {
 
 	const Light * light = light_owner.getornull(p_light);

+ 77 - 24
drivers/gles3/rasterizer_storage_gles3.h

@@ -99,6 +99,38 @@ public:
 
 
 
+	struct Instantiable : public RID_Data {
+
+		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();
+			}
+		}
+
+		_FORCE_INLINE_ void instance_material_change_notify() {
+
+			SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+			while(instances) {
+
+				instances->self()->base_material_changed();
+				instances=instances->next();
+			}
+		}
+
+		Instantiable() {  }
+		virtual ~Instantiable() {
+
+			while(instance_list.first()) {
+				instance_list.first()->self()->base_removed();
+			}
+		}
+	};
 
 
 
@@ -282,9 +314,14 @@ public:
 			bool uses_alpha;
 			bool unshaded;
 			bool ontop;
+			bool uses_vertex;
+			bool uses_discard;
 
 		} spatial;
 
+		bool uses_vertex_time;
+		bool uses_fragment_time;
+
 		Shader() : dirty_list(this) {
 
 			shader=NULL;
@@ -315,6 +352,8 @@ public:
 
 	void update_dirty_shaders();
 
+
+
 	/* COMMON MATERIAL API */
 
 	struct Material : public RID_Data {
@@ -331,7 +370,15 @@ public:
 		uint32_t index;
 		uint64_t last_pass;
 
+		Map<Instantiable*,int> instantiable_owners;
+		Map<RasterizerScene::InstanceBase*,int> instance_owners;
+
+		bool can_cast_shadow_cache;
+		bool is_animated_cache;
+
 		Material() : list(this), dirty_list(this) {
+			can_cast_shadow_cache=false;
+			is_animated_cache=false;
 			shader=NULL;
 			line_width=1.0;
 			ubo_id=0;
@@ -343,6 +390,8 @@ public:
 
 	mutable SelfList<Material>::List _material_dirty_list;
 	void _material_make_dirty(Material *p_material) const;
+	void _material_add_instantiable(RID p_material,Instantiable *p_instantiable);
+	void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable);
 
 
 	mutable RID_Owner<Material> material_owner;
@@ -357,34 +406,18 @@ public:
 
 	virtual void material_set_line_width(RID p_material, float p_width);
 
+	virtual bool material_is_animated(RID p_material);
+	virtual bool material_casts_shadows(RID p_material);
+
+	virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
+	virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
+
 	void _update_material(Material* material);
 
 	void update_dirty_materials();
 
 	/* MESH API */
 
-	struct Instantiable : public RID_Data {
-
-		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 {
 
@@ -455,7 +488,8 @@ public:
 		int index_array_len;
 		int max_bone;
 
-		int array_bytes;
+		int array_byte_size;
+		int index_array_byte_size;
 
 
 		VS::PrimitiveType primitive;
@@ -464,7 +498,8 @@ public:
 
 		Surface() {
 
-			array_bytes=0;
+			array_byte_size=0;
+			index_array_byte_size=0;
 			mesh=NULL;
 			format=0;
 			array_id=0;
@@ -526,6 +561,10 @@ 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 AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const;
+	virtual Vector<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const;
+	virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const;
+
 	virtual void mesh_remove_surface(RID p_mesh, int p_surface);
 	virtual int mesh_get_surface_count(RID p_mesh) const;
 
@@ -598,7 +637,10 @@ public:
 		bool shadow;
 		bool negative;
 		uint32_t cull_mask;
+		VS::LightOmniShadowMode omni_shadow_mode;
+		VS::LightOmniShadowDetail omni_shadow_detail;
 		VS::LightDirectionalShadowMode directional_shadow_mode;
+		uint64_t version;
 	};
 
 	mutable RID_Owner<Light> light_owner;
@@ -614,11 +656,22 @@ public:
 	virtual void light_set_cull_mask(RID p_light,uint32_t p_mask);
 	virtual void light_set_shader(RID p_light,RID p_shader);
 
+	virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode);
+
+	virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail);
 
 	virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode);
+	virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
+	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
+
+	virtual bool light_has_shadow(RID p_light) const;
 
 	virtual VS::LightType light_get_type(RID p_light) const;
+	virtual float light_get_param(RID p_light,VS::LightParam p_param);
+
 	virtual AABB light_get_aabb(RID p_light) const;
+	virtual uint64_t light_get_version(RID p_light) const;
+
 	/* PROBE API */
 
 	virtual RID reflection_probe_create();

+ 14 - 1
drivers/gles3/shader_compiler_gles3.cpp

@@ -330,6 +330,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 
 				SL::FunctionNode *fnode=pnode->functions[i].function;
 
+				current_func_name=fnode->name;
 
 				if (fnode->name=="vertex") {
 
@@ -401,6 +402,14 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
 			else
 				code=_mkid(vnode->name);
 
+			if (vnode->name==time_name) {
+				if (current_func_name==vertex_name) {
+					r_gen_code.uses_vertex_time=true;
+				}
+				if (current_func_name==fragment_name) {
+					r_gen_code.uses_fragment_time=true;
+				}
+			}
 
 		} break;
 		case SL::Node::TYPE_CONSTANT: {
@@ -536,6 +545,8 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code,
 	r_gen_code.fragment=String();
 	r_gen_code.fragment_global=String();
 	r_gen_code.light=String();
+	r_gen_code.uses_fragment_time=false;
+	r_gen_code.uses_vertex_time=false;
 
 
 
@@ -645,7 +656,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
 
 
 
-
+	vertex_name="vertex";
+	fragment_name="fragment";
+	time_name="TIME";
 
 
 

+ 7 - 0
drivers/gles3/shader_compiler_gles3.h

@@ -32,6 +32,9 @@ public:
 		String fragment;
 		String light;
 
+		bool uses_fragment_time;
+		bool uses_vertex_time;
+
 	};
 
 private:
@@ -49,6 +52,10 @@ private:
 	String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions& p_actions, const DefaultIdentifierActions& p_default_actions);
 
 
+	StringName current_func_name;
+	StringName vertex_name;
+	StringName fragment_name;
+	StringName time_name;
 
 	Set<StringName> used_name_defines;
 	Set<StringName> used_rmode_defines;

+ 1 - 0
drivers/gles3/shaders/SCsub

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

+ 79 - 0
drivers/gles3/shaders/cube_to_dp.glsl

@@ -0,0 +1,79 @@
+[vertex]
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+void main() {
+
+	uv_interp = uv_in;
+	gl_Position = vertex_attrib;
+}
+
+[fragment]
+
+
+uniform highp samplerCube source_cube; //texunit:0
+in vec2 uv_interp;
+
+uniform bool z_flip;
+uniform highp float z_far;
+uniform highp float z_near;
+uniform highp float bias;
+
+void main() {
+
+	highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
+/*
+	if(z_flip) {
+		normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+	} else {
+		normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+	}
+*/
+
+	//normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
+	//normal.xy*=1.0+normal.z;
+
+	normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+	normal = normalize(normal);
+
+/*
+	normal.z=0.5;
+	normal=normalize(normal);
+*/
+	if (!z_flip) {
+		normal.z=-normal.z;
+	}
+
+	//normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
+	float depth = texture(source_cube,normal).r;
+
+	// absolute values for direction cosines, bigger value equals closer to basis axis
+	vec3 unorm = abs(normal);
+
+	if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
+	    // x code
+	    unorm = normal.x > 0.0 ?  vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
+	} else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
+	    // y code
+	    unorm = normal.y > 0.0 ?  vec3( 0.0, 1.0, 0.0 ) :  vec3( 0.0, -1.0, 0.0 ) ;
+	} else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
+	    // z code
+	    unorm = normal.z > 0.0 ?  vec3( 0.0, 0.0, 1.0 ) :  vec3( 0.0, 0.0, -1.0 ) ;
+	} else {
+	    // oh-no we messed up code
+	    // has to be
+	    unorm = vec3( 1.0, 0.0, 0.0 );
+	}
+
+	float depth_fix = 1.0 / dot(normal,unorm);
+
+
+	depth = 2.0 * depth - 1.0;
+	float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
+	gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
+}
+

+ 286 - 55
drivers/gles3/shaders/scene.glsl

@@ -1,7 +1,6 @@
 [vertex]
 
 
-#define ENABLE_UV_INTERP
 /*
 from VisualServer:
 
@@ -56,6 +55,15 @@ layout(std140) uniform SceneData { //ubo:0
 	highp vec4 bg_color;
 	float ambient_energy;
 	float bg_energy;
+
+	float shadow_z_offset;
+	float shadow_z_slope_scale;
+	float shadow_dual_paraboloid_render_zfar;
+	float shadow_dual_paraboloid_render_side;
+
+	vec2 shadow_atlas_pixel_size;
+	vec2 directional_shadow_pixel_size;
+
 };
 
 uniform highp mat4 world_transform;
@@ -68,6 +76,7 @@ layout(std140) uniform LightData { //ubo:3
 	mediump vec4 light_direction_attenuation;
 	mediump vec4 light_color_energy;
 	mediump vec4 light_params; //cone attenuation, specular, shadow darkening,
+	mediump vec4 light_clamp;
 	mediump vec4 shadow_split_offsets;
 	highp mat4 shadow_matrix1;
 	highp mat4 shadow_matrix2;
@@ -75,19 +84,6 @@ layout(std140) uniform LightData { //ubo:3
 	highp mat4 shadow_matrix4;
 };
 
-#ifdef USE_FORWARD_1_SHADOW_MAP
-out mediump vec4 forward_shadow_pos1;
-#endif
-
-#ifdef USE_FORWARD_2_SHADOW_MAP
-out mediump vec4 forward_shadow_pos2;
-#endif
-
-#ifdef USE_FORWARD_4_SHADOW_MAP
-out mediump vec4 forward_shadow_pos3;
-out mediump vec4 forward_shadow_pos4;
-#endif
-
 #endif
 
 /* Varyings */
@@ -120,13 +116,6 @@ 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
 
@@ -141,6 +130,11 @@ MATERIAL_UNIFORMS
 
 #endif
 
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+out highp float dp_clip;
+
+#endif
 
 void main() {
 
@@ -206,24 +200,49 @@ VERTEX_SHADER_CODE
 
 }
 
+	vertex_interp = vertex.xyz;
+	normal_interp = normal;
+
+#if defined(ENABLE_TANGENT_INTERP)
+	tangent_interp = tangent;
+	binormal_interp = binormal;
+#endif
+
+#ifdef RENDER_SHADOW
+
+
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+	vertex_interp.z*= shadow_dual_paraboloid_render_side;
+	normal_interp.z*= shadow_dual_paraboloid_render_side;
 
-#ifdef USE_SHADOW_PASS
+	dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+
+	//for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
+
+	highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset;
+	highp float distance = length(vtx);
+	vtx = normalize(vtx);
+	vtx.xy/=1.0-vtx.z;
+	vtx.z=(distance/shadow_dual_paraboloid_render_zfar);
+	vtx.z=vtx.z * 2.0 - 1.0;
+
+	vertex.xyz=vtx;
+	vertex.w=1.0;
+
+
+#else
 
 	float z_ofs = shadow_z_offset;
 	z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
 	vertex_interp.z-=z_ofs;
-#endif
 
+#endif //RENDER_SHADOW_DUAL_PARABOLOID
 
-	vertex_interp = vertex.xyz;
-	normal_interp = normal;
+#endif //RENDER_SHADOW
 
-#if defined(ENABLE_TANGENT_INTERP)
-	tangent_interp = tangent;
-	binormal_interp = binormal;
-#endif
 
-#if !defined(SKIP_TRANSFORM_USED)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_SHADOW_DUAL_PARABOLOID)
 	gl_Position = projection_matrix * vec4(vertex_interp,1.0);
 #else
 	gl_Position = vertex;
@@ -239,11 +258,6 @@ VERTEX_SHADER_CODE
 
 #define M_PI 3.14159265359
 
-
-#define ENABLE_UV_INTERP
-//hack to use uv if no uv present so it works with lightmap
-
-
 /* Varyings */
 
 #if defined(ENABLE_COLOR_INTERP)
@@ -318,6 +332,15 @@ layout(std140) uniform SceneData {
 	highp vec4 bg_color;
 	float ambient_energy;
 	float bg_energy;
+
+	float shadow_z_offset;
+	float shadow_z_slope_scale;
+	float shadow_dual_paraboloid_render_zfar;
+	float shadow_dual_paraboloid_render_side;
+
+	vec2 shadow_atlas_pixel_size;
+	vec2 directional_shadow_pixel_size;
+
 };
 
 
@@ -328,7 +351,8 @@ layout(std140) uniform LightData {
 	highp vec4 light_pos_inv_radius;
 	mediump vec4 light_direction_attenuation;
 	mediump vec4 light_color_energy;
-	mediump vec4 light_params; //cone attenuation, specular, shadow darkening,
+	mediump vec4 light_params; //cone attenuation, specular, shadow darkening, shadow enabled
+	mediump vec4 light_clamp;
 	mediump vec4 shadow_split_offsets;
 	highp mat4 shadow_matrix1;
 	highp mat4 shadow_matrix2;
@@ -336,20 +360,12 @@ layout(std140) uniform LightData {
 	highp mat4 shadow_matrix4;
 };
 
-#ifdef USE_FORWARD_1_SHADOW_MAP
-in mediump vec4 forward_shadow_pos1;
 #endif
 
-#ifdef USE_FORWARD_2_SHADOW_MAP
-in mediump vec4 forward_shadow_pos2;
-#endif
 
-#ifdef USE_FORWARD_4_SHADOW_MAP
-in mediump vec4 forward_shadow_pos3;
-in mediump vec4 forward_shadow_pos4;
-#endif
+uniform highp sampler2DShadow directional_shadow; //texunit:-4
+uniform highp sampler2DShadow shadow_atlas; //texunit:-3
 
-#endif
 
 #ifdef USE_MULTIPLE_RENDER_TARGETS
 
@@ -408,10 +424,27 @@ void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color,
 }
 
 
+float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) {
+
+	return textureProj(shadow,vec4(pos,depth,1.0));
+}
+
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+in highp float dp_clip;
+
+#endif
+
 void main() {
 
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+	if (dp_clip>0.0)
+		discard;
+#endif
+
 	//lay out everything, whathever is unused is optimized away anyway
-	vec3 vertex = vertex_interp;
+	highp vec3 vertex = vertex_interp;
 	vec3 albedo = vec3(0.8,0.8,0.8);
 	vec3 specular = vec3(0.2,0.2,0.2);
 	float roughness = 1.0;
@@ -528,27 +561,216 @@ FRAGMENT_SHADER_CODE
 #endif
 
 
-#ifdef USE_FORWARD_LIGHTING
-
 #ifdef USE_FORWARD_DIRECTIONAL
 
-	light_compute(normal,light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,1.0,diffuse_light,specular_light);
+	float light_attenuation=1.0;
+
+#ifdef LIGHT_DIRECTIONAL_SHADOW
+
+	if (gl_FragCoord.w > shadow_split_offsets.w) {
+
+	vec3 pssm_coord;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+	float pssm_blend;
+	vec3 pssm_coord2;
+	bool use_blend=true;
+	vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz;
+	float w_inv = 1.0/gl_FragCoord.w;
 #endif
 
+
+#ifdef LIGHT_USE_PSSM4
+
+
+	if (gl_FragCoord.w > shadow_split_offsets.y) {
+
+		if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+			highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+			pssm_coord=splane.xyz/splane.w;
+			ambient_light=vec3(1.0,0.4,0.4);
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+			splane=(shadow_matrix2 * vec4(vertex,1.0));
+			pssm_coord2=splane.xyz/splane.w;
+			pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+		} else {
+
+			highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+			pssm_coord=splane.xyz/splane.w;
+			ambient_light=vec3(0.4,1.0,0.4);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+			splane=(shadow_matrix3 * vec4(vertex,1.0));
+			pssm_coord2=splane.xyz/splane.w;
+			pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv);
+#endif
+
+		}
+	} else {
+
+
+		if (gl_FragCoord.w > shadow_split_offsets.z) {
+
+			highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0));
+			pssm_coord=splane.xyz/splane.w;
+			ambient_light=vec3(0.4,0.4,1.0);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+			splane=(shadow_matrix4 * vec4(vertex,1.0));
+			pssm_coord2=splane.xyz/splane.w;
+			pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv);
+#endif
+
+		} else {
+			highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0));
+			pssm_coord=splane.xyz/splane.w;
+			diffuse_light*=vec3(1.0,0.4,1.0);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+			use_blend=false;
+
+#endif
+
+		}
+	}
+
+#endif //LIGHT_USE_PSSM4
+
+#ifdef LIGHT_USE_PSSM2
+
+	if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+		highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+		pssm_coord=splane.xyz/splane.w;
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+		splane=(shadow_matrix2 * vec4(vertex,1.0));
+		pssm_coord2=splane.xyz/splane.w;
+		pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+	} else {
+		highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+		pssm_coord=splane.xyz/splane.w;
+#if defined(LIGHT_USE_PSSM_BLEND)
+		use_blend=false;
+
+#endif
+
+	}
+
+#endif //LIGHT_USE_PSSM2
+
+#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
+	{ //regular orthogonal
+		highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+		pssm_coord=splane.xyz/splane.w;
+	}
+#endif
+
+
+	//one one sample
+	light_attenuation=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp);
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+	if (use_blend) {
+		float light_attenuation2=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp);
+		light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend);
+	}
+#endif
+
+	}
+
+#endif //LIGHT_DIRECTIONAL_SHADOW
+
+	light_compute(normal,-light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
+
+
+#endif //USE_FORWARD_DIRECTIONAL
+
+
 #ifdef USE_FORWARD_OMNI
 
 	vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex;
 	float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w;
 	float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w );
+
+	if (light_params.w>0.5) {
+		//there is a shadowmap
+
+		highp vec3 splane=(shadow_matrix1 * vec4(vertex,1.0)).xyz;
+		float shadow_len=length(splane);
+		splane=normalize(splane);
+		vec4 clamp_rect=light_clamp;
+
+		if (splane.z>=0.0) {
+
+			splane.z+=1.0;
+
+			clamp_rect.y+=clamp_rect.w;
+
+		} else {
+
+			splane.z=1.0 - splane.z;
+
+			//if (clamp_rect.z<clamp_rect.w) {
+			//	clamp_rect.x+=clamp_rect.z;
+			//} else {
+			//	clamp_rect.y+=clamp_rect.w;
+			//}
+
+		}
+
+		splane.xy/=splane.z;
+		splane.xy=splane.xy * 0.5 + 0.5;
+		splane.z = shadow_len * light_pos_inv_radius.w;
+
+		splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw;
+
+		light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect);
+	}
+
 	light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
 
-#endif
+
+#endif //USE_FORWARD_OMNI
 
 #ifdef USE_FORWARD_SPOT
 
-#endif
+	vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex;
+	float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w;
+	float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w );
+	vec3 spot_dir = light_direction_attenuation.xyz;
+	float spot_cutoff=light_params.y;
+	float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
+	float rim = (1.0 - scos) / (1.0 - spot_cutoff);
+	light_attenuation *= 1.0 - pow( rim, light_params.x);
+
+	if (light_params.w>0.5) {
+		//there is a shadowmap
+
+		highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+		splane.xyz/=splane.w;
+	//	splane.xy=splane.xy*0.5+0.5;
+
+		//splane.xy=light_clamp.xy+splane.xy*light_clamp.zw;
+		light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,light_clamp);
+
+	}
+
+	light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
+
+#endif //USE_FORWARD_SPOT
 
-#endif
 
 
 #if defined(USE_LIGHT_SHADER_CODE)
@@ -560,6 +782,11 @@ LIGHT_SHADER_CODE
 }
 #endif
 
+#ifdef RENDER_SHADOW
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else
+
+
 #ifdef USE_MULTIPLE_RENDER_TARGETS
 
 	//approximate ambient scale for SSAO, since we will lack full ambient
@@ -574,13 +801,17 @@ LIGHT_SHADER_CODE
 
 #else
 
+
 #ifdef SHADELESS
 	frag_color=vec4(albedo,alpha);
 #else
 	frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha);
-#endif
+#endif //SHADELESS
+
+#endif //USE_MULTIPLE_RENDER_TARGETS
+
+#endif //RENDER_SHADOW
 
-#endif
 
 }
 

+ 22 - 1
main/main.cpp

@@ -1296,6 +1296,17 @@ bool Main::start() {
 			appname = TranslationServer::get_singleton()->translate(appname);
 			OS::get_singleton()->set_window_title(appname);
 
+			int shadow_atlas_size = GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+			int shadow_atlas_q0_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+			int shadow_atlas_q1_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+			int shadow_atlas_q2_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+			int shadow_atlas_q3_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+
+			sml->get_root()->set_shadow_atlas_size(shadow_atlas_size);
+			sml->get_root()->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q0_subdiv));
+			sml->get_root()->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv));
+			sml->get_root()->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv));
+			sml->get_root()->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv));
 
 		} else {
 			GLOBAL_DEF("display/stretch_mode","disabled");
@@ -1304,7 +1315,17 @@ bool Main::start() {
 			Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height"));
 			sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));
 
-
+			GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+			Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size",PropertyInfo(Variant::INT,"rendering/shadow_atlas/size",PROPERTY_HINT_RANGE,"256,16384"));
+
+			GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+			GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+			GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+			GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+			Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_0_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_0_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+			Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_1_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_1_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+			Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_2_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_2_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+			Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_3_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_3_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
 		}
 
 

+ 80 - 11
scene/3d/light.cpp

@@ -202,7 +202,7 @@ void Light::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative"));
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR);
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask"), _SCS("set_cull_mask"), _SCS("get_cull_mask"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
+	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkness"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_DARKNESS);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/normal_bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS);
@@ -222,7 +222,6 @@ void Light::_bind_methods() {
 	BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET );
 	BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET );
 	BIND_CONSTANT( PARAM_SHADOW_SPLIT_3_OFFSET );
-	BIND_CONSTANT( PARAM_SHADOW_SPLIT_4_OFFSET );
 	BIND_CONSTANT( PARAM_SHADOW_NORMAL_BIAS );
 	BIND_CONSTANT( PARAM_SHADOW_BIAS );
 	BIND_CONSTANT( PARAM_SHADOW_BIAS_SPLIT_SCALE );
@@ -255,7 +254,6 @@ Light::Light(VisualServer::LightType p_type) {
 	set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1);
 	set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2);
 	set_param(PARAM_SHADOW_SPLIT_3_OFFSET,0.5);
-	set_param(PARAM_SHADOW_SPLIT_4_OFFSET,1.0);
 	set_param(PARAM_SHADOW_NORMAL_BIAS,0.1);
 	set_param(PARAM_SHADOW_BIAS,0.1);
 	set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE,0.1);
@@ -279,36 +277,107 @@ Light::~Light() {
 }
 /////////////////////////////////////////
 
+void DirectionalLight::set_shadow_mode(ShadowMode p_mode) {
+
+	shadow_mode=p_mode;
+	VS::get_singleton()->light_directional_set_shadow_mode(light,VS::LightDirectionalShadowMode(p_mode));
+}
+
+DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const {
+
+	return shadow_mode;
+}
+
+void DirectionalLight::set_blend_splits(bool p_enable) {
+
+	blend_splits=p_enable;
+}
+
+bool DirectionalLight::is_blend_splits_enabled() const {
+
+	return blend_splits;
+}
+
 
 void DirectionalLight::_bind_methods() {
 
+	ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&DirectionalLight::set_shadow_mode);
+	ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&DirectionalLight::get_shadow_mode);
 
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_4"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_4_OFFSET);
+	ObjectTypeDB::bind_method( _MD("set_blend_splits","enabled"),&DirectionalLight::set_blend_splits);
+	ObjectTypeDB::bind_method( _MD("is_blend_splits_enabled"),&DirectionalLight::is_blend_splits_enabled);
+
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "directional/shadow_mode",PROPERTY_HINT_ENUM,"Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode"));
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET);
+	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled"));
+
+	BIND_CONSTANT( SHADOW_ORTHOGONAL );
+	BIND_CONSTANT( SHADOW_PARALLEL_2_SPLITS );
+	BIND_CONSTANT( SHADOW_PARALLEL_4_SPLITS );
 
 }
 
 
 DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) {
 
+	set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
+	blend_splits=false;
+}
 
+void OmniLight::set_shadow_mode(ShadowMode p_mode) {
 
+	shadow_mode=p_mode;
+	VS::get_singleton()->light_omni_set_shadow_mode(light,VS::LightOmniShadowMode(p_mode));
 }
 
+OmniLight::ShadowMode OmniLight::get_shadow_mode() const{
+
+	return shadow_mode;
+}
+
+void OmniLight::set_shadow_detail(ShadowDetail p_detail){
+
+	shadow_detail=p_detail;
+	VS::get_singleton()->light_omni_set_shadow_detail(light,VS::LightOmniShadowDetail(p_detail));
+}
+OmniLight::ShadowDetail OmniLight::get_shadow_detail() const{
+
+	return shadow_detail;
+}
+
+
+
 
 void OmniLight::_bind_methods() {
 
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+	ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&OmniLight::set_shadow_mode);
+	ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&OmniLight::get_shadow_mode);
+
+	ObjectTypeDB::bind_method( _MD("set_shadow_detail","detail"),&OmniLight::set_shadow_detail);
+	ObjectTypeDB::bind_method( _MD("get_shadow_detail"),&OmniLight::get_shadow_detail);
+
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_mode",PROPERTY_HINT_ENUM,"Dual Paraboloid,Cube"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_detail",PROPERTY_HINT_ENUM,"Vertical,Horizontal"), _SCS("set_shadow_detail"), _SCS("get_shadow_detail"));
+
+}
+
+OmniLight::OmniLight() : Light( VisualServer::LIGHT_OMNI ) {
+
+	set_shadow_mode(SHADOW_DUAL_PARABOLOID);
+	set_shadow_detail(SHADOW_DETAIL_HORIZONTAL);
 
 }
 
 void SpotLight::_bind_methods() {
 
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE);
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE);
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION);
 
 }
 

+ 54 - 17
scene/3d/light.h

@@ -45,22 +45,21 @@ class Light : public VisualInstance {
 public:
 
 	enum Param {
-		PARAM_ENERGY,
-		PARAM_SPECULAR,
-		PARAM_RANGE,
-		PARAM_ATTENUATION,
-		PARAM_SPOT_ANGLE,
-		PARAM_SPOT_ATTENUATION,
-		PARAM_SHADOW_MAX_DISTANCE,
-		PARAM_SHADOW_DARKNESS,
-		PARAM_SHADOW_SPLIT_1_OFFSET,
-		PARAM_SHADOW_SPLIT_2_OFFSET,
-		PARAM_SHADOW_SPLIT_3_OFFSET,
-		PARAM_SHADOW_SPLIT_4_OFFSET,
-		PARAM_SHADOW_NORMAL_BIAS,
-		PARAM_SHADOW_BIAS,
-		PARAM_SHADOW_BIAS_SPLIT_SCALE,
-		PARAM_MAX
+		PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY,
+		PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR,
+		PARAM_RANGE = VS::LIGHT_PARAM_RANGE,
+		PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION,
+		PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE,
+		PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION,
+		PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE,
+		PARAM_SHADOW_DARKNESS = VS::LIGHT_PARAM_SHADOW_DARKNESS,
+		PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
+		PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
+		PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+		PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
+		PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS,
+		PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
+		PARAM_MAX = VS::LIGHT_PARAM_MAX
 	};
 
 private:
@@ -126,31 +125,69 @@ class DirectionalLight : public Light {
 
 public:
 
+	enum ShadowMode {
+		SHADOW_ORTHOGONAL,
+		SHADOW_PARALLEL_2_SPLITS,
+		SHADOW_PARALLEL_4_SPLITS
+	};
 
 private:
 
+	bool blend_splits;
+	ShadowMode shadow_mode;
 
 protected:
 	static void _bind_methods();
 public:
 
+	void set_shadow_mode(ShadowMode p_mode);
+	ShadowMode get_shadow_mode() const;
+
+	void set_blend_splits(bool p_enable);
+	bool is_blend_splits_enabled() const;
 
 	DirectionalLight();
 };
 
+VARIANT_ENUM_CAST(DirectionalLight::ShadowMode)
 
 class OmniLight : public Light {
 
 	OBJ_TYPE( OmniLight, Light );
+public:
+	// omni light
+	enum ShadowMode {
+		SHADOW_DUAL_PARABOLOID,
+		SHADOW_CUBE,
+	};
+
+	// omni light
+	enum ShadowDetail {
+		SHADOW_DETAIL_VERTICAL,
+		SHADOW_DETAIL_HORIZONTAL
+	};
+
+private:
+
+	ShadowMode shadow_mode;
+	ShadowDetail shadow_detail;
 protected:
 	static void _bind_methods();
 
 public:
 
+	void set_shadow_mode(ShadowMode p_mode);
+	ShadowMode get_shadow_mode() const;
 
-	OmniLight() : Light( VisualServer::LIGHT_OMNI ) { }
+	void set_shadow_detail(ShadowDetail p_detail);
+	ShadowDetail get_shadow_detail() const;
+
+	OmniLight();
 };
 
+VARIANT_ENUM_CAST(OmniLight::ShadowMode)
+VARIANT_ENUM_CAST(OmniLight::ShadowDetail)
+
 class SpotLight : public Light {
 
 	OBJ_TYPE( SpotLight, Light );

+ 1 - 1
scene/3d/navigation_mesh.cpp

@@ -201,7 +201,7 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
 	arr.resize(Mesh::ARRAY_MAX);
 	arr[Mesh::ARRAY_VERTEX]=varr;
 
-	debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr);
+	debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr);
 
 	return debug_mesh;
 }

+ 1 - 1
scene/main/scene_main_loop.cpp

@@ -845,7 +845,7 @@ Ref<Mesh> SceneTree::get_debug_contact_mesh() {
 	arr[Mesh::ARRAY_INDEX]=indices;
 
 
-	debug_contact_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr);
+	debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
 	debug_contact_mesh->surface_set_material(0,mat);
 
 	return debug_contact_mesh;

+ 61 - 0
scene/main/viewport.cpp

@@ -1297,6 +1297,39 @@ bool Viewport::get_clear_on_new_frame() const{
 	return clear_on_new_frame;
 }
 
+void Viewport::set_shadow_atlas_size(int p_size) {
+
+	shadow_atlas_size=p_size;
+	VS::get_singleton()->viewport_set_shadow_atlas_size(viewport,p_size);
+}
+
+int Viewport::get_shadow_atlas_size() const{
+
+	return shadow_atlas_size;
+}
+
+void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv){
+
+
+	ERR_FAIL_INDEX(p_quadrant,4);
+	ERR_FAIL_INDEX(p_subdiv,SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
+
+	if (shadow_atlas_quadrant_subdiv[p_quadrant]==p_subdiv)
+		return;
+
+	shadow_atlas_quadrant_subdiv[p_quadrant]=p_subdiv;
+	static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX]={0,1,4,16,64,256,1024};
+
+	VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport,p_quadrant,subdiv[p_subdiv]);
+
+}
+Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const{
+
+	ERR_FAIL_INDEX_V(p_quadrant,4,SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
+	return shadow_atlas_quadrant_subdiv[p_quadrant];
+}
+
+
 void Viewport::clear() {
 
 	//clear=true;
@@ -2661,6 +2694,12 @@ void Viewport::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
 	ObjectTypeDB::bind_method(_MD("_gui_remove_focus"), &Viewport::_gui_remove_focus);
 
+	ObjectTypeDB::bind_method(_MD("set_shadow_atlas_size","size"), &Viewport::set_shadow_atlas_size);
+	ObjectTypeDB::bind_method(_MD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size);
+
+	ObjectTypeDB::bind_method(_MD("set_shadow_atlas_quadrant_subdiv","quadrant","subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
+	ObjectTypeDB::bind_method(_MD("get_shadow_atlas_quadrant_subdiv","quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
+
 	ADD_PROPERTY( PropertyInfo(Variant::RECT2,"size"), _SCS("set_size"), _SCS("get_size") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") );
 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") );
@@ -2674,6 +2713,11 @@ void Viewport::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"physics/object_picking"), _SCS("set_physics_object_picking"), _SCS("get_physics_object_picking") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gui/disable_input"), _SCS("set_disable_input"), _SCS("is_input_disabled") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"3d/disable_3d"), _SCS("set_disable_3d"), _SCS("is_3d_disabled") );
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow_atlas/size"), _SCS("set_shadow_atlas_size"), _SCS("get_shadow_atlas_size") );
+	ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_0",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),0 );
+	ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_1",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),1 );
+	ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_2",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),2 );
+	ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_3",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),3 );
 
 	ADD_SIGNAL(MethodInfo("size_changed"));
 
@@ -2682,6 +2726,14 @@ void Viewport::_bind_methods() {
 	BIND_CONSTANT( UPDATE_WHEN_VISIBLE  );
 	BIND_CONSTANT( UPDATE_ALWAYS  );
 
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_4 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_16 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_64 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_256 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1024 );
+	BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_MAX );
 }
 
 
@@ -2719,6 +2771,15 @@ Viewport::Viewport() {
 	physics_object_over=0;
 	physics_last_mousepos=Vector2(1e20,1e20);
 
+	shadow_atlas_size=0;
+	for(int i=0;i<4;i++) {
+		shadow_atlas_quadrant_subdiv[0]=SHADOW_ATLAS_QUADRANT_SUBDIV_MAX;
+	}
+	set_shadow_atlas_quadrant_subdiv(0,SHADOW_ATLAS_QUADRANT_SUBDIV_4);
+	set_shadow_atlas_quadrant_subdiv(1,SHADOW_ATLAS_QUADRANT_SUBDIV_4);
+	set_shadow_atlas_quadrant_subdiv(2,SHADOW_ATLAS_QUADRANT_SUBDIV_16);
+	set_shadow_atlas_quadrant_subdiv(3,SHADOW_ATLAS_QUADRANT_SUBDIV_64);
+
 
 	String id=itos(get_instance_ID());
 	input_group = "_vp_input"+id;

+ 22 - 2
scene/main/viewport.h

@@ -86,6 +86,18 @@ public:
 		UPDATE_ALWAYS
 	};
 
+	enum ShadowAtlasQuadrantSubdiv {
+		SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_1,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_4,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_16,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_64,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_256,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_1024,
+		SHADOW_ATLAS_QUADRANT_SUBDIV_MAX,
+
+	};
+
 private:
 
 friend class ViewportTexture;
@@ -120,8 +132,6 @@ friend class ViewportTexture;
 	RID contact_3d_debug_multimesh;
 	RID contact_3d_debug_instance;
 
-
-
 	bool size_override;
 	bool size_override_stretch;
 	Size2 size_override_size;
@@ -175,6 +185,9 @@ friend class ViewportTexture;
 	RID texture_rid;
 	Ref<ViewportTexture> texture;
 
+	int shadow_atlas_size;
+	ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
+
 
 	struct GUI {
 		// info used when this is a window
@@ -347,6 +360,11 @@ public:
 	UpdateMode get_update_mode() const;
 	Ref<ViewportTexture> get_texture() const;
 
+	void set_shadow_atlas_size(int p_size);
+	int get_shadow_atlas_size() const;
+
+	void set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv);
+	ShadowAtlasQuadrantSubdiv get_shadow_atlas_quadrant_subdiv(int p_quadrant) const;
 
 	Vector2 get_camera_coords(const Vector2& p_viewport_coords) const;
 	Vector2 get_camera_rect_size() const;
@@ -393,4 +411,6 @@ public:
 };
 
 VARIANT_ENUM_CAST(Viewport::UpdateMode);
+VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
+
 #endif

+ 1 - 1
scene/resources/material.cpp

@@ -152,7 +152,7 @@ void FixedSpatialMaterial::_update_shader() {
 	switch(cull_mode) {
 		case CULL_BACK: code+=",cull_back"; break;
 		case CULL_FRONT: code+=",cull_front"; break;
-		case CULL_DISABLED: code+=",cull_disable"; break;
+		case CULL_DISABLED: code+=",cull_disabled"; break;
 
 	}
 

+ 92 - 10
scene/resources/mesh.cpp

@@ -125,11 +125,61 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) {
 		//create
 		Dictionary d=p_value;
 		ERR_FAIL_COND_V(!d.has("primitive"),false);
-		ERR_FAIL_COND_V(!d.has("arrays"),false);
-		ERR_FAIL_COND_V(!d.has("morph_arrays"),false);
+
+		if (d.has("arrays")) {
+			//old format
+			ERR_FAIL_COND_V(!d.has("morph_arrays"),false);
+			add_surface_from_arrays(PrimitiveType(int(d["primitive"])),d["arrays"],d["morph_arrays"]);
+
+		} else if (d.has("array_data")) {
+
+			DVector<uint8_t> array_data = d["array_data"];
+			DVector<uint8_t> array_index_data;
+			if (d.has("array_index_data"))
+				array_index_data=d["array_index_data"];
+
+			ERR_FAIL_COND_V(!d.has("format"),false);
+			uint32_t format = d["format"];
+
+			ERR_FAIL_COND_V(!d.has("primitive"),false);
+			uint32_t primitive = d["primitive"];
+
+			ERR_FAIL_COND_V(!d.has("vertex_count"),false);
+			int vertex_count = d["vertex_count"];
+
+			int index_count=0;
+			if (d.has("index_count"))
+				index_count=d["index_count"];
+
+			Vector< DVector<uint8_t> > morphs;
+
+			if (d.has("morph_data")) {
+				Array morph_data=d["morph_data"];
+				for(int i=0;i<morph_data.size();i++) {
+					DVector<uint8_t> morph = morph_data[i];
+					morphs.push_back(morph_data[i]);
+				}
+			}
+
+			ERR_FAIL_COND_V(!d.has("aabb"),false);
+			AABB aabb = d["aabb"];
+
+			Vector<AABB> bone_aabb;
+			if (d.has("bone_aabb")) {
+				Array baabb = d["bone_aabb"];
+				bone_aabb.resize(baabb.size());
+
+				for(int i=0;i<baabb.size();i++) {
+					bone_aabb[i]=baabb[i];
+				}
+			}
+
+			add_surface(format,PrimitiveType(primitive),array_data,vertex_count,array_index_data,index_count,aabb,morphs,bone_aabb);
+		} else {
+			ERR_FAIL_V(false);
+		}
 
 
-		add_surface(PrimitiveType(int(d["primitive"])),d["arrays"],d["morph_arrays"]);
 		if (d.has("material")) {
 
 			surface_set_material(idx,d["material"]);
@@ -185,9 +235,31 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const {
 	ERR_FAIL_INDEX_V(idx,surfaces.size(),false);
 
 	Dictionary d;
-	d["primitive"]=surface_get_primitive_type(idx);
-	d["arrays"]=surface_get_arrays(idx);
-	d["morph_arrays"]=surface_get_morph_arrays(idx);
+
+	d["array_data"]=VS::get_singleton()->mesh_surface_get_array(mesh,idx);
+	d["vertex_count"]=VS::get_singleton()->mesh_surface_get_array_len(mesh,idx);
+	d["array_index_data"]=VS::get_singleton()->mesh_surface_get_index_array(mesh,idx);
+	d["index_count"]=VS::get_singleton()->mesh_surface_get_array_index_len(mesh,idx);
+	d["primitive"]=VS::get_singleton()->mesh_surface_get_primitive_type(mesh,idx);
+	d["format"]=VS::get_singleton()->mesh_surface_get_format(mesh,idx);
+	d["aabb"]=VS::get_singleton()->mesh_surface_get_aabb(mesh,idx);
+
+	Vector<AABB> skel_aabb = VS::get_singleton()->mesh_surface_get_skeleton_aabb(mesh,idx);
+	Array arr;
+	for(int i=0;i<skel_aabb.size();i++) {
+		arr[i]=skel_aabb[i];
+	}
+	d["skeleton_aabb"]=arr;
+
+	Vector< DVector<uint8_t> > morph_data = VS::get_singleton()->mesh_surface_get_blend_shapes(mesh,idx);
+
+	Array md;
+	for(int i=0;i<morph_data.size();i++) {
+		md.push_back(morph_data[i]);
+	}
+
+	d["morph_data"]=md;
+
 	Ref<Material> m = surface_get_material(idx);
 	if (m.is_valid())
 		d["material"]=m;
@@ -234,7 +306,17 @@ void Mesh::_recompute_aabb() {
 
 }
 
-void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) {
+void Mesh::add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes,const Vector<AABB>& p_bone_aabbs) {
+
+	Surface s;
+	s.aabb=p_aabb;
+	surfaces.push_back(s);
+
+	VisualServer::get_singleton()->mesh_add_surface(mesh,p_format,(VS::PrimitiveType)p_primitive,p_array,p_vertex_count,p_index_array,p_index_count,p_aabb,p_blend_shapes,p_bone_aabbs);
+
+}
+
+void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) {
 
 
 	ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX);
@@ -279,8 +361,7 @@ void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Arr
 Array Mesh::surface_get_arrays(int p_surface) const {
 
 	ERR_FAIL_INDEX_V(p_surface,surfaces.size(),Array());
-	//return VisualServer::get_singleton()->mesh_get_surface_arrays(mesh,p_surface);
-	return Array();
+	return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh,p_surface);
 
 }
 Array Mesh::surface_get_morph_arrays(int p_surface) const {
@@ -929,7 +1010,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
 
 
 	Ref<Mesh> newmesh = memnew( Mesh );
-	newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays);
+	newmesh->add_surface_from_arrays(PRIMITIVE_TRIANGLES,arrays);
 	return newmesh;
 }
 
@@ -943,6 +1024,7 @@ void Mesh::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode);
 	ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode);
 
+	ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes"),&Mesh::add_surface_from_arrays,DEFVAL(Array()));
 	ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count);
 	ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove);
 	ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len);

+ 3 - 1
scene/resources/mesh.h

@@ -122,7 +122,9 @@ protected:
 
 public:
 
-	void add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array());
+	void add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array());
+	void add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>());
+
 	Array surface_get_arrays(int p_surface) const;
 	virtual Array surface_get_morph_arrays(int p_surface) const;
 

+ 1 - 1
scene/resources/mesh_data_tool.cpp

@@ -328,7 +328,7 @@ Error MeshDataTool::commit_to_surface(const Ref<Mesh>& p_mesh) {
 
 	Ref<Mesh> ncmesh=p_mesh;
 	int sc = ncmesh->get_surface_count();
-	ncmesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr);
+	ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
 	ncmesh->surface_set_material(sc,material);
 
 	return OK;

+ 1 - 1
scene/resources/shape.cpp

@@ -77,7 +77,7 @@ Ref<Mesh> Shape::get_debug_mesh() {
 
 		SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to<SceneTree>();
 
-		debug_mesh_cache->add_surface(Mesh::PRIMITIVE_LINES,arr);
+		debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr);
 
 		if (st) {
 			debug_mesh_cache->surface_set_material(0,st->get_debug_collision_material());

+ 1 - 1
scene/resources/surface_tool.cpp

@@ -410,7 +410,7 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
 
 	}
 
-	mesh->add_surface(primitive,a);
+	mesh->add_surface_from_arrays(primitive,a);
 	if (material.is_valid())
 		mesh->surface_set_material(surface,material);
 

+ 35 - 2
servers/visual/rasterizer.h

@@ -39,6 +39,16 @@
 class RasterizerScene {
 public:
 
+	/* SHADOW ATLAS API */
+
+	virtual RID shadow_atlas_create()=0;
+	virtual void shadow_atlas_set_size(RID p_atlas,int p_size)=0;
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision)=0;
+	virtual bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version)=0;
+
+	virtual int get_directional_light_shadow_size(RID p_light_intance)=0;
+	virtual void set_directional_shadow_count(int p_count)=0;
+
 	/* ENVIRONMENT API */
 
 	virtual RID environment_create()=0;
@@ -93,6 +103,7 @@ public:
 
 		virtual void base_removed()=0;
 		virtual void base_changed()=0;
+		virtual void base_material_changed()=0;
 
 		InstanceBase() : dependency_item(this) {
 
@@ -109,10 +120,11 @@ public:
 
 	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 light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass)=0;
 	virtual void light_instance_mark_visible(RID p_light_instance)=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 void render_scene(const Transform& p_cam_transform,const 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_environment,RID p_shadow_atlas)=0;
+	virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0;
 
 	virtual void set_scene_pass(uint64_t p_pass)=0;
 
@@ -179,6 +191,12 @@ public:
 
 	virtual void material_set_line_width(RID p_material, float p_width)=0;
 
+	virtual bool material_is_animated(RID p_material)=0;
+	virtual bool material_casts_shadows(RID p_material)=0;
+
+	virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance)=0;
+	virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance)=0;
+
 	/* MESH API */
 
 	virtual RID mesh_create()=0;
@@ -205,6 +223,10 @@ public:
 	virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const=0;
 	virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const=0;
 
+	virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const=0;
+	virtual Vector<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0;
+	virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const=0;
+
 	virtual void mesh_remove_surface(RID p_mesh,int p_index)=0;
 	virtual int mesh_get_surface_count(RID p_mesh) const=0;
 
@@ -279,10 +301,21 @@ 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_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode)=0;
+	virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail)=0;
+
 	virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode)=0;
 
+	virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light)=0;
+	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light)=0;
+
+	virtual bool light_has_shadow(RID p_light) const=0;
+
 	virtual VS::LightType light_get_type(RID p_light) const=0;
 	virtual AABB light_get_aabb(RID p_light) const=0;
+	virtual float light_get_param(RID p_light,VS::LightParam p_param)=0;
+	virtual uint64_t light_get_version(RID p_light) const=0;
+
 
 	/* PROBE API */
 

+ 1 - 1
servers/visual/shader_types.cpp

@@ -84,7 +84,7 @@ ShaderTypes::ShaderTypes()
 
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_front");
 	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("cull_disabled");
 
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
 	shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop");

+ 9 - 1
servers/visual/visual_server_raster.h

@@ -687,6 +687,10 @@ public:
 	BIND2RC(uint32_t,mesh_surface_get_format,RID,int)
 	BIND2RC(PrimitiveType,mesh_surface_get_primitive_type,RID,int)
 
+	BIND2RC(AABB,mesh_surface_get_aabb,RID,int)
+	BIND2RC(Vector<DVector<uint8_t> >,mesh_surface_get_blend_shapes,RID,int)
+	BIND2RC(Vector<AABB>,mesh_surface_get_skeleton_aabb,RID,int)
+
 	BIND2(mesh_remove_surface,RID,int)
 	BIND1RC(int,mesh_get_surface_count,RID)
 
@@ -759,6 +763,9 @@ public:
 	BIND2(light_set_cull_mask,RID ,uint32_t )
 	BIND2(light_set_shader,RID ,RID )
 
+	BIND2(light_omni_set_shadow_mode,RID,LightOmniShadowMode)
+	BIND2(light_omni_set_shadow_detail,RID,LightOmniShadowDetail)
+
 	BIND2(light_directional_set_shadow_mode,RID,LightDirectionalShadowMode)
 
 	/* PROBE API */
@@ -847,7 +854,8 @@ public:
 
 	BIND2(viewport_set_global_canvas_transform,RID,const Matrix32& )
 	BIND3(viewport_set_canvas_layer,RID ,RID ,int )
-
+	BIND2(viewport_set_shadow_atlas_size,RID ,int )
+	BIND3(viewport_set_shadow_atlas_quadrant_subdivision,RID ,int, int )
 
 	/* ENVIRONMENT API */
 

+ 605 - 33
servers/visual/visual_server_scene.cpp

@@ -96,7 +96,10 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
 
 		List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo);
 
-		light->shadow_sirty=true;
+		if (geom->can_cast_shadows) {
+
+			light->shadow_dirty=true;
+		}
 		geom->lighting_dirty=true;
 
 		return E; //this element should make freeing faster
@@ -180,7 +183,9 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
 		geom->lighting.erase(E->get().L);
 		light->geometries.erase(E);
 
-		light->shadow_sirty=true;
+		if (geom->can_cast_shadows) {
+			light->shadow_dirty=true;
+		}
 		geom->lighting_dirty=true;
 
 
@@ -346,6 +351,12 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
 		}
 
 		instance->morph_values.clear();
+
+		for(int i=0;i<instance->materials.size();i++) {
+			if (instance->materials[i].is_valid()) {
+				VSG::storage->material_remove_instance_owner(instance->materials[i],instance);
+			}
+		}
 		instance->materials.clear();
 
 #if 0
@@ -667,7 +678,16 @@ void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surfa
 
 	ERR_FAIL_INDEX(p_surface,instance->materials.size());
 
+	if (instance->materials[p_surface].is_valid()) {
+		VSG::storage->material_remove_instance_owner(instance->materials[p_surface],instance);
+	}
 	instance->materials[p_surface]=p_material;
+	instance->base_material_changed();
+
+	if (instance->materials[p_surface].is_valid()) {
+		VSG::storage->material_add_instance_owner(instance->materials[p_surface],instance);
+	}
+
 
 }
 
@@ -791,12 +811,14 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFl
 
 		} break;
 		case VS::INSTANCE_FLAG_CAST_SHADOW: {
-			/*if (p_enabled == true) {
-				instance->cast_shadows = SHADOW_CASTING_SETTING_ON;
+			if (p_enabled == true) {
+				instance->cast_shadows = VS::SHADOW_CASTING_SETTING_ON;
 			}
 			else {
-				instance->cast_shadows = SHADOW_CASTING_SETTING_OFF;
-			}*/
+				instance->cast_shadows = VS::SHADOW_CASTING_SETTING_OFF;
+			}
+
+			instance->base_material_changed(); // to actually compute if shadows are visible or not
 
 		} break;
 		case VS::INSTANCE_FLAG_DEPH_SCALE: {
@@ -820,8 +842,15 @@ void VisualServerScene::instance_geometry_set_material_override(RID p_instance,
 	Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND( !instance );
 
+	if (instance->material_override.is_valid()) {
+		VSG::storage->material_remove_instance_owner(instance->material_override,instance);
+	}
 	instance->material_override=p_material;
+	instance->base_material_changed();
 
+	if (instance->material_override.is_valid()) {
+		VSG::storage->material_add_instance_owner(instance->material_override,instance);
+	}
 
 }
 
@@ -843,6 +872,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
 		InstanceLightData *light = static_cast<InstanceLightData*>(p_instance->base_data);
 
 		VSG::scene_render->light_instance_set_transform( light->instance, p_instance->transform );
+		light->shadow_dirty=true;
 
 	}
 
@@ -860,11 +890,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
 	if ((1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
 
 		InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(p_instance->base_data);
-		//make sure lights are updated
+		//make sure lights are updated if it casts shadow
 
-		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 (geom->can_cast_shadows) {
+			for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+				InstanceLightData *light = static_cast<InstanceLightData*>(E->get()->base_data);
+				light->shadow_dirty=true;
+			}
 		}
 
 	}
@@ -1095,9 +1127,371 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
 
 
 
-void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size) {
 
 
+void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect) {
+
+
+	InstanceLightData * light = static_cast<InstanceLightData*>(p_instance->base_data);
+
+	switch(VSG::storage->light_get_type(p_instance->base)) {
+
+		case VS::LIGHT_DIRECTIONAL: {
+
+			float max_distance = p_camera->zfar;
+			float shadow_max = VSG::storage->light_get_param(p_instance->base,VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
+			if (shadow_max>0) {
+				max_distance=MIN(shadow_max,max_distance);
+			}
+			max_distance=MAX(max_distance,p_camera->znear+0.001);
+
+			float range = max_distance-p_camera->znear;
+
+			int splits=0;
+			switch(VSG::storage->light_directional_get_shadow_mode(p_instance->base)) {
+				case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: splits=1; break;
+				case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: splits=2; break;
+				case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits=4; break;
+			}
+
+			float distances[5];
+
+			distances[0]=p_camera->znear;
+			for(int i=0;i<splits;i++) {
+				distances[i+1]=p_camera->znear+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range;
+			};
+
+			distances[splits]=max_distance;
+
+			float texture_size=VSG::scene_render->get_directional_light_shadow_size(light->instance);
+
+			bool overlap = false;//rasterizer->light_instance_get_pssm_shadow_overlap(p_light->light_info->instance);
+
+			for (int i=0;i<splits;i++) {
+
+				// setup a camera matrix for that range!
+				CameraMatrix camera_matrix;
+
+				switch(p_camera->type) {
+
+					case Camera::ORTHOGONAL: {
+
+						camera_matrix.set_orthogonal(
+							p_camera->size,
+							p_viewport_rect.width / p_viewport_rect.height,
+							distances[(i==0 || !overlap )?i:i-1],
+							distances[i+1],
+							p_camera->vaspect
+
+						);
+					} break;
+					case Camera::PERSPECTIVE: {
+
+
+						camera_matrix.set_perspective(
+							p_camera->fov,
+							p_viewport_rect.width / (float)p_viewport_rect.height,
+							distances[(i==0 || !overlap )?i:i-1],
+							distances[i+1],
+							p_camera->vaspect
+
+						);
+
+					} break;
+				}
+
+				//obtain the frustum endpoints
+
+				Vector3 endpoints[8]; // frustum plane endpoints
+				bool res = camera_matrix.get_endpoints(p_camera->transform,endpoints);
+				ERR_CONTINUE(!res);
+
+				// obtain the light frustm ranges (given endpoints)
+
+				Vector3 x_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_X ).normalized();
+				Vector3 y_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_Y ).normalized();
+				Vector3 z_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_Z ).normalized();
+				//z_vec points agsint the camera, like in default opengl
+
+				float x_min,x_max;
+				float y_min,y_max;
+				float z_min,z_max;
+
+				float x_min_cam,x_max_cam;
+				float y_min_cam,y_max_cam;
+				float z_min_cam,z_max_cam;
+
+
+				//used for culling
+				for(int j=0;j<8;j++) {
+
+					float d_x=x_vec.dot(endpoints[j]);
+					float d_y=y_vec.dot(endpoints[j]);
+					float d_z=z_vec.dot(endpoints[j]);
+
+					if (j==0 || d_x<x_min)
+						x_min=d_x;
+					if (j==0 || d_x>x_max)
+						x_max=d_x;
+
+					if (j==0 || d_y<y_min)
+						y_min=d_y;
+					if (j==0 || d_y>y_max)
+						y_max=d_y;
+
+					if (j==0 || d_z<z_min)
+						z_min=d_z;
+					if (j==0 || d_z>z_max)
+						z_max=d_z;
+
+
+				}
+
+
+
+
+
+				{
+					//camera viewport stuff
+					//this trick here is what stabilizes the shadow (make potential jaggies to not move)
+					//at the cost of some wasted resolution. Still the quality increase is very well worth it
+
+
+					Vector3 center;
+
+					for(int j=0;j<8;j++) {
+
+						center+=endpoints[j];
+					}
+					center/=8.0;
+
+					//center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5;
+
+					float radius=0;
+
+					for(int j=0;j<8;j++) {
+
+						float d = center.distance_to(endpoints[j]);
+						if (d>radius)
+							radius=d;
+					}
+
+
+					radius *= texture_size/(texture_size-2.0); //add a texel by each side, so stepified texture will always fit
+
+					x_max_cam=x_vec.dot(center)+radius;
+					x_min_cam=x_vec.dot(center)-radius;
+					y_max_cam=y_vec.dot(center)+radius;
+					y_min_cam=y_vec.dot(center)-radius;
+					z_max_cam=z_vec.dot(center)+radius;
+					z_min_cam=z_vec.dot(center)-radius;
+
+					float unit = radius*2.0/texture_size;
+
+					x_max_cam=Math::stepify(x_max_cam,unit);
+					x_min_cam=Math::stepify(x_min_cam,unit);
+					y_max_cam=Math::stepify(y_max_cam,unit);
+					y_min_cam=Math::stepify(y_min_cam,unit);
+
+				}
+
+				//now that we now all ranges, we can proceed to make the light frustum planes, for culling octree
+
+				Vector<Plane> light_frustum_planes;
+				light_frustum_planes.resize(6);
+
+				//right/left
+				light_frustum_planes[0]=Plane( x_vec, x_max );
+				light_frustum_planes[1]=Plane( -x_vec, -x_min );
+				//top/bottom
+				light_frustum_planes[2]=Plane( y_vec, y_max );
+				light_frustum_planes[3]=Plane( -y_vec, -y_min );
+				//near/far
+				light_frustum_planes[4]=Plane( z_vec, z_max+1e6 );
+				light_frustum_planes[5]=Plane( -z_vec, -z_min ); // z_min is ok, since casters further than far-light plane are not needed
+
+				int cull_count = p_scenario->octree.cull_convex(light_frustum_planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK);
+
+				// a pre pass will need to be needed to determine the actual z-near to be used
+
+
+				for (int j=0;j<cull_count;j++) {
+
+					float min,max;
+					Instance *instance = instance_shadow_cull_result[j];
+					if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(instance->base_data)->can_cast_shadows) {
+						cull_count--;
+						SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]);
+						j--;
+
+					}
+
+					instance->transformed_aabb.project_range_in_plane(Plane(z_vec,0),min,max);
+					if (max>z_max)
+						z_max=max;
+				}
+
+				{
+					CameraMatrix ortho_camera;
+					real_t half_x = (x_max_cam-x_min_cam) * 0.5;
+					real_t half_y = (y_max_cam-y_min_cam) * 0.5;
+
+
+					ortho_camera.set_orthogonal( -half_x, half_x,-half_y,half_y, 0, (z_max-z_min_cam) );
+
+					Transform ortho_transform;
+					ortho_transform.basis=p_instance->transform.basis;
+					ortho_transform.origin=x_vec*(x_min_cam+half_x)+y_vec*(y_min_cam+half_y)+z_vec*z_max;
+
+					VSG::scene_render->light_instance_set_shadow_transform(light->instance,ortho_camera,ortho_transform,0,distances[i+1],i);
+				}
+
+
+
+				VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count);
+
+			}
+
+		} break;
+		case VS::LIGHT_OMNI: {
+
+			VS::LightOmniShadowMode shadow_mode = VSG::storage->light_omni_get_shadow_mode(p_instance->base);
+
+			switch(shadow_mode) {
+				case VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID: {
+
+					for(int i=0;i<2;i++) {
+
+						//using this one ensures that raster deferred will have it
+
+						float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE);
+
+						float z =i==0?-1:1;
+						Vector<Plane> planes;
+						planes.resize(5);
+						planes[0]=p_instance->transform.xform(Plane(Vector3(0,0,z),radius));
+						planes[1]=p_instance->transform.xform(Plane(Vector3(1,0,z).normalized(),radius));
+						planes[2]=p_instance->transform.xform(Plane(Vector3(-1,0,z).normalized(),radius));
+						planes[3]=p_instance->transform.xform(Plane(Vector3(0,1,z).normalized(),radius));
+						planes[4]=p_instance->transform.xform(Plane(Vector3(0,-1,z).normalized(),radius));
+
+
+						int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK);
+
+						for (int j=0;j<cull_count;j++) {
+
+							Instance *instance = instance_shadow_cull_result[j];
+							if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(instance->base_data)->can_cast_shadows) {
+								cull_count--;
+								SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]);
+								j--;
+
+							}
+						}
+
+						VSG::scene_render->light_instance_set_shadow_transform(light->instance,CameraMatrix(),p_instance->transform,radius,0,i);
+						VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count);
+					}
+				} break;
+				case VS::LIGHT_OMNI_SHADOW_CUBE: {
+
+					float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE);
+					CameraMatrix cm;
+					cm.set_perspective(90,1,0.01,radius);
+
+					for(int i=0;i<6;i++) {
+
+						//using this one ensures that raster deferred will have it
+
+
+
+						static const Vector3 view_normals[6]={
+							Vector3(-1, 0, 0),
+							Vector3(+1, 0, 0),
+							Vector3( 0,-1, 0),
+							Vector3( 0,+1, 0),
+							Vector3( 0, 0,-1),
+							Vector3( 0, 0,+1)
+						};
+						static const Vector3 view_up[6]={
+							Vector3( 0,-1, 0),
+							Vector3( 0,-1, 0),
+							Vector3( 0, 0,-1),
+							Vector3( 0, 0,+1),
+							Vector3( 0,-1, 0),
+							Vector3( 0,-1, 0)
+						};
+
+						Transform xform = p_instance->transform * Transform().looking_at(view_normals[i],view_up[i]);
+
+
+						Vector<Plane> planes = cm.get_projection_planes(xform);
+
+						int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK);
+
+						for (int j=0;j<cull_count;j++) {
+
+							Instance *instance = instance_shadow_cull_result[j];
+							if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(instance->base_data)->can_cast_shadows) {
+								cull_count--;
+								SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]);
+								j--;
+
+							}
+						}
+
+						VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,xform,radius,0,i);
+						VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count);
+					}
+
+					//restore the regular DP matrix
+					VSG::scene_render->light_instance_set_shadow_transform(light->instance,CameraMatrix(),p_instance->transform,radius,0,0);
+
+				} break;
+			}
+
+
+		} break;
+		case VS::LIGHT_SPOT: {
+
+
+			float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE);
+			float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
+
+			CameraMatrix cm;
+			cm.set_perspective( 90, 1.0, 0.01, radius );
+			print_line("perspective: "+cm);
+
+			Vector<Plane> planes = cm.get_projection_planes(p_instance->transform);
+			int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK);
+
+			for (int j=0;j<cull_count;j++) {
+
+				Instance *instance = instance_shadow_cull_result[j];
+				if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(instance->base_data)->can_cast_shadows) {
+					cull_count--;
+					SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]);
+					j--;
+
+				}
+			}
+
+
+			print_line("MOMONGO");
+			VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,p_instance->transform,radius,0,0);
+			VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,0,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count);
+
+		} break;
+	}
+
+}
+
+
+
+
+
+void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size,RID p_shadow_atlas) {
+
 
 	Camera *camera = camera_owner.getornull(p_camera);
 	ERR_FAIL_COND(!camera);
@@ -1112,8 +1506,10 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp
 
 	/* STEP 1 - SETUP CAMERA */
 	CameraMatrix camera_matrix;
+	Transform camera_inverse_xform = camera->transform.affine_inverse();
 	bool ortho=false;
 
+
 	switch(camera->type) {
 		case Camera::ORTHOGONAL: {
 
@@ -1268,12 +1664,14 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp
 					//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;
-					VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later
+					if (p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(ins->base)) {
+						VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later
+					}
 
 					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) {
@@ -1386,6 +1784,10 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp
 
 	// directional lights
 	{
+
+		Instance** lights_with_shadow = (Instance**)alloca(sizeof(Instance*)*light_cull_count);
+		int directional_shadow_count=0;
+
 		for (List<Instance*>::Element *E=scenario->directional_lights.front();E;E=E->next()) {
 
 			if (light_cull_count+directional_light_count>=MAX_LIGHTS_CULLED) {
@@ -1401,42 +1803,142 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp
 			//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);
+			if (light && VSG::storage->light_has_shadow(E->get()->base)) {
+				lights_with_shadow[directional_shadow_count++]=E->get();
+
 			}
-*/
 
 			//add to list
 
-
 			directional_light_ptr[directional_light_count++]=light->instance;
+		}
+
+		VSG::scene_render->set_directional_shadow_count(directional_shadow_count);
+
+		for(int i=0;i<directional_shadow_count;i++) {
+
+			   _light_instance_update_shadow(lights_with_shadow[i],camera,p_shadow_atlas,scenario,p_viewport_size);
 
 		}
 	}
 
-#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);
+
+	{ //setup shadow maps
+
+		//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)
+			if (!p_shadow_atlas.is_valid() || !VSG::storage->light_has_shadow(ins->base))
 				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
-			*/
+			InstanceLightData * light = static_cast<InstanceLightData*>(ins->base_data);
+
+			float coverage;
+
+			{	//compute coverage
+
+
+				Transform cam_xf = camera->transform;
+				float zn = camera_matrix.get_z_near();
+				Plane p (cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2) ); //camera near plane
+
+				float vp_w,vp_h; //near plane size in screen coordinates
+				camera_matrix.get_viewport_size(vp_w,vp_h);
+
+
+				switch(VSG::storage->light_get_type(ins->base)) {
+
+					case VS::LIGHT_OMNI: {
+
+						float radius = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_RANGE);
+
+						//get two points parallel to near plane
+						Vector3 points[2]={
+							ins->transform.origin,
+							ins->transform.origin+cam_xf.basis.get_axis(0)*radius
+						};
+
+						if (!ortho) {
+							//if using perspetive, map them to near plane
+							for(int j=0;j<2;j++) {
+								if (p.distance_to(points[j]) < 0 )	{
+									points[j].z=-zn; //small hack to keep size constant when hitting the screen
+
+								}
+
+								p.intersects_segment(cam_xf.origin,points[j],&points[j]); //map to plane
+							}
+
+
+						}
+
+						float screen_diameter = points[0].distance_to(points[1])*2;
+						coverage = screen_diameter / (vp_w+vp_h);
+					} break;
+					case VS::LIGHT_SPOT: {
+
+						float radius = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_RANGE);
+						float angle = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_SPOT_ANGLE);
+
+
+						float w = radius*Math::sin(Math::deg2rad(angle));
+						float d = radius*Math::cos(Math::deg2rad(angle));
+
+
+						Vector3 base = ins->transform.origin-ins->transform.basis.get_axis(2).normalized()*d;
+
+						Vector3 points[2]={
+							base,
+							base+cam_xf.basis.get_axis(0)*w
+						};
+
+						if (!ortho) {
+							//if using perspetive, map them to near plane
+							for(int j=0;j<2;j++) {
+								if (p.distance_to(points[j]) < 0 )	{
+									points[j].z=-zn; //small hack to keep size constant when hitting the screen
+
+								}
+
+								p.intersects_segment(cam_xf.origin,points[j],&points[j]); //map to plane
+							}
+
+
+						}
+
+						float screen_diameter = points[0].distance_to(points[1])*2;
+						coverage = screen_diameter / (vp_w+vp_h);
+
+
+					} break;
+					default: {
+						ERR_PRINT("Invalid Light Type");
+					}
+				}
+
+			}
+
+
+			if (light->shadow_dirty) {
+				light->last_version++;
+				light->shadow_dirty=false;
+			}
+
+
+
+			bool redraw = VSG::scene_render->shadow_atlas_update_light(p_shadow_atlas,light->instance,coverage,light->last_version);
+
+			if (redraw) {
+				//must redraw!
+				_light_instance_update_shadow(ins,camera,p_shadow_atlas,scenario,p_viewport_size);
+			}
 
-			_light_instance_update_shadow(ins,p_scenario,camera,cull_range);
-			ins->light_info->last_version=ins->version;
 		}
 	}
-#endif
+
 	/* ENVIRONMENT */
 
 	RID environment;
@@ -1492,7 +1994,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp
 
 
 
-	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);
+	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_count,environment,p_shadow_atlas);
+
 
 }
 
@@ -1505,9 +2008,77 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 		_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));
+			//remove materials no longer used and un-own them
+
+			int new_mat_count = VSG::storage->mesh_get_surface_count(p_instance->base);
+			for(int i=p_instance->materials.size()-1;i>=new_mat_count;i--) {
+				if (p_instance->materials[i].is_valid()) {
+					VSG::storage->material_remove_instance_owner(p_instance->materials[i],p_instance);
+				}
+			}
+			p_instance->materials.resize(new_mat_count);
+		}
+
+		if ((1<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+			InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(p_instance->base_data);
+
+			bool can_cast_shadows=true;
+
+			if (p_instance->cast_shadows==VS::SHADOW_CASTING_SETTING_OFF) {
+				can_cast_shadows=false;
+			} else if (p_instance->material_override.is_valid()) {
+				can_cast_shadows=VSG::storage->material_casts_shadows(p_instance->material_override);
+			} else {
+
+				RID mesh;
+
+				if (p_instance->base_type==VS::INSTANCE_MESH) {
+					mesh=p_instance->base;
+				} else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) {
+
+				}
+
+				if (mesh.is_valid()) {
+
+					bool cast_shadows=false;
+
+					for(int i=0;i<p_instance->materials.size();i++) {
+
+
+						RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i);
+
+						if (!mat.is_valid()) {
+							cast_shadows=true;
+							break;
+						}
+
+						if (VSG::storage->material_casts_shadows(mat)) {
+							cast_shadows=true;
+							break;
+						}
+					}
+
+					if (!cast_shadows) {
+						can_cast_shadows=false;
+					}
+				}
+
+			}
+
+			if (can_cast_shadows!=geom->can_cast_shadows) {
+				//ability to cast shadows change, let lights now
+				for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) {
+					InstanceLightData *light = static_cast<InstanceLightData*>(E->get()->base_data);
+					light->shadow_dirty=true;
+				}
+
+				geom->can_cast_shadows=can_cast_shadows;
+			}
 		}
+
 	}
 
 	_update_instance(p_instance);
@@ -1557,6 +2128,7 @@ bool VisualServerScene::free(RID p_rid) {
 		instance_set_room(p_rid,RID());
 		instance_set_scenario(p_rid,RID());
 		instance_set_base(p_rid,RID());
+		instance_geometry_set_material_override(p_rid,RID());
 
 		if (instance->skeleton.is_valid())
 			instance_attach_skeleton(p_rid,RID());

+ 14 - 5
servers/visual/visual_server_scene.h

@@ -195,6 +195,7 @@ public:
 		//aabb stuff
 		bool update_aabb;
 		bool update_materials;
+
 		SelfList<Instance> update_item;
 
 
@@ -232,6 +233,11 @@ public:
 			singleton->_instance_queue_update(this,true,true);
 		}
 
+		virtual void base_material_changed() {
+
+			singleton->_instance_queue_update(this,false,true);
+		}
+
 
 		Instance() : scenario_item(this), update_item(this), room_item(this) {
 
@@ -282,10 +288,12 @@ public:
 
 		List<Instance*> lighting;
 		bool lighting_dirty;
+		bool can_cast_shadows;
 
 		InstanceGeometryData() {
 
 			lighting_dirty=false;
+			can_cast_shadows=true;
 		}
 	};
 
@@ -298,18 +306,18 @@ public:
 		};
 
 		RID instance;
-		uint64_t last_hash;
+		uint64_t last_version;
 		List<Instance*>::Element *D; // directional light in scenario
 
-		bool shadow_sirty;
+		bool shadow_dirty;
 
 		List<PairInfo> geometries;
 
 		InstanceLightData() {
 
-			shadow_sirty=true;
+			shadow_dirty=true;
 			D=NULL;
-			last_hash=0;
+			last_version=0;
 		}
 	};
 
@@ -360,8 +368,9 @@ public:
 	_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
 	_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
 
+	_FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect);
 
-	void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size);
+	void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
 	void update_dirty_instances();
 	bool free(RID p_rid);
 

+ 25 - 2
servers/visual/visual_server_viewport.cpp

@@ -64,7 +64,7 @@ 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);
+		VSG::scene->render_camera(p_viewport->camera,p_viewport->scenario,p_viewport->size,p_viewport->shadow_atlas);
 	}
 
 	if (!p_viewport->hide_canvas) {
@@ -287,7 +287,8 @@ RID VisualServerViewport::viewport_create() {
 	viewport->self=rid;
 	viewport->hide_scenario=false;
 	viewport->hide_canvas=false;
-	viewport->render_target=VSG::storage->render_target_create();
+	viewport->render_target=VSG::storage->render_target_create();	
+	viewport->shadow_atlas=VSG::scene_render->shadow_atlas_create();
 
 	return rid;
 
@@ -496,6 +497,27 @@ void VisualServerViewport::viewport_set_canvas_layer(RID p_viewport,RID p_canvas
 
 }
 
+void VisualServerViewport::viewport_set_shadow_atlas_size(RID p_viewport,int p_size) {
+
+	Viewport * viewport = viewport_owner.getornull(p_viewport);
+	ERR_FAIL_COND(!viewport);
+
+	viewport->shadow_atlas_size=p_size;
+
+	VSG::scene_render->shadow_atlas_set_size( viewport->shadow_atlas, viewport->shadow_atlas_size);
+
+}
+
+void VisualServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv) {
+
+	Viewport * viewport = viewport_owner.getornull(p_viewport);
+	ERR_FAIL_COND(!viewport);
+
+	VSG::scene_render->shadow_atlas_set_quadrant_subdivision( viewport->shadow_atlas, p_quadrant, p_subdiv);
+
+}
+
+
 bool VisualServerViewport::free(RID p_rid) {
 
 	Viewport * viewport = viewport_owner.getornull(p_rid);
@@ -504,6 +526,7 @@ bool VisualServerViewport::free(RID p_rid) {
 
 
 	VSG::storage->free( viewport->render_target );
+	VSG::scene_render->free( viewport->shadow_atlas );
 
 	while(viewport->canvas_map.front()) {
 		viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key());

+ 7 - 0
servers/visual/visual_server_viewport.h

@@ -36,6 +36,9 @@ public:
 		bool disable_environment;
 		bool disable_3d;
 
+		RID shadow_atlas;
+		int shadow_atlas_size;
+
 
 		VS::ViewportClearMode clear_mode;
 
@@ -67,6 +70,7 @@ public:
 			rendered_in_prev_frame=false;
 			disable_environment=false;
 			viewport_to_screen=0;
+			shadow_atlas_size=0;
 
 		}
 	};
@@ -129,6 +133,9 @@ public:
 	void viewport_set_global_canvas_transform(RID p_viewport,const Matrix32& p_transform);
 	void viewport_set_canvas_layer(RID p_viewport,RID p_canvas,int p_layer);
 
+	void viewport_set_shadow_atlas_size(RID p_viewport,int p_size);
+	void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv);
+
 	void draw_viewports();
 
 	bool free(RID p_rid);

+ 449 - 1
servers/visual_server.cpp

@@ -1021,7 +1021,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi
 					break;
 				}
 				/* determine wether using 16 or 32 bits indices */
-				if (array_len>(1<<16)) {
+				if (array_len>=(1<<16)) {
 
 					elem_size=4;
 
@@ -1089,6 +1089,454 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi
 
 }
 
+Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector<uint8_t> p_vertex_data,int p_vertex_len,DVector<uint8_t> p_index_data,int p_index_len) const {
+
+
+	uint32_t offsets[ARRAY_MAX];
+
+	int total_elem_size=0;
+
+	for (int i=0;i<VS::ARRAY_MAX;i++) {
+
+
+		offsets[i]=0; //reset
+
+		if (!(p_format&(1<<i))) // no array
+			continue;
+
+
+		int elem_size=0;
+
+		switch(i) {
+
+			case VS::ARRAY_VERTEX: {
+
+
+				if (p_format&ARRAY_FLAG_USE_2D_VERTICES) {
+					elem_size=2;
+				} else {
+					elem_size=3;
+				}
+
+				if (p_format&ARRAY_COMPRESS_VERTEX) {
+					elem_size*=sizeof(int16_t);
+				} else {
+					elem_size*=sizeof(float);
+				}
+
+			} break;
+			case VS::ARRAY_NORMAL: {
+
+				if (p_format&ARRAY_COMPRESS_NORMAL) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*3;
+				}
+
+			} break;
+
+			case VS::ARRAY_TANGENT: {
+				if (p_format&ARRAY_COMPRESS_TANGENT) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+
+			} break;
+			case VS::ARRAY_COLOR: {
+
+				if (p_format&ARRAY_COMPRESS_COLOR) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+			} break;
+			case VS::ARRAY_TEX_UV: {
+				if (p_format&ARRAY_COMPRESS_TEX_UV) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*2;
+				}
+
+			} break;
+
+			case VS::ARRAY_TEX_UV2: {
+				if (p_format&ARRAY_COMPRESS_TEX_UV2) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(float)*2;
+				}
+
+			} break;
+			case VS::ARRAY_WEIGHTS: {
+
+				if (p_format&ARRAY_COMPRESS_WEIGHTS) {
+					elem_size=sizeof(uint16_t)*4;
+				} else {
+					elem_size=sizeof(float)*4;
+				}
+
+			} break;
+			case VS::ARRAY_BONES: {
+
+				if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) {
+					elem_size=sizeof(uint32_t);
+				} else {
+					elem_size=sizeof(uint16_t)*4;
+				}
+
+			} break;
+			case VS::ARRAY_INDEX: {
+
+				if (p_index_len<=0) {
+					ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+					break;
+				}
+				/* determine wether using 16 or 32 bits indices */
+				if (p_index_len>=(1<<16)) {
+
+					elem_size=4;
+
+				} else {
+					elem_size=2;
+				}
+				offsets[i]=elem_size;
+				continue;
+			} break;
+			default: {
+				ERR_FAIL_V( Array() );
+			}
+		}
+
+		offsets[i]=total_elem_size;
+		total_elem_size+=elem_size;
+
+
+	}
+
+	Array ret;
+	ret.resize(VS::ARRAY_MAX);
+
+	DVector<uint8_t>::Read r = p_vertex_data.read();
+
+	for(int i=0;i<VS::ARRAY_MAX;i++) {
+
+		if (!(p_format&(1<<i)))
+			continue;
+
+
+		switch(i) {
+
+			case VS::ARRAY_VERTEX: {
+
+
+				if (p_format&ARRAY_FLAG_USE_2D_VERTICES) {
+
+					DVector<Vector2> arr_2d;
+					arr_2d.resize(p_vertex_len);
+
+					if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+						DVector<Vector2>::Write w = arr_2d.write();
+
+						for(int j=0;j<p_vertex_len;j++) {
+
+							const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+							w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]));
+						}
+					} else {
+
+						DVector<Vector2>::Write w = arr_2d.write();
+
+						for(int j=0;j<p_vertex_len;j++) {
+
+							const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+							w[j]=Vector2(v[0],v[1]);
+						}
+					}
+
+					ret[i]=arr_2d;
+				} else {
+
+					DVector<Vector3> arr_3d;
+					arr_3d.resize(p_vertex_len);
+
+					if (p_format&ARRAY_COMPRESS_VERTEX) {
+
+						DVector<Vector3>::Write w = arr_3d.write();
+
+						for(int j=0;j<p_vertex_len;j++) {
+
+							const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+							w[j]=Vector3(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]),Math::halfptr_to_float(&v[1]));
+						}
+					} else {
+
+						DVector<Vector3>::Write w = arr_3d.write();
+
+						for(int j=0;j<p_vertex_len;j++) {
+
+							const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+							w[j]=Vector3(v[0],v[1],v[2]);
+						}
+					}
+
+					ret[i]=arr_3d;
+				}
+
+
+			} break;
+			case VS::ARRAY_NORMAL: {
+				DVector<Vector3> arr;
+				arr.resize(p_vertex_len);
+
+				if (p_format&ARRAY_COMPRESS_NORMAL) {
+
+					DVector<Vector3>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector3( float(v[0]/255.0)*2.0-1.0, float(v[1]/255.0)*2.0-1.0, float(v[2]/255.0)*2.0-1.0 );
+					}
+				} else {
+					DVector<Vector3>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector3(v[0],v[1],v[2]);
+					}
+				}
+
+				ret[i]=arr;
+
+			} break;
+
+			case VS::ARRAY_TANGENT: {
+				DVector<float> arr;
+				arr.resize(p_vertex_len*4);
+				if (p_format&ARRAY_COMPRESS_TANGENT) {
+					DVector<float>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=float(v[k]/255.0)*2.0-1.0;
+						}
+					}
+				} else {
+
+					DVector<float>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=v[k];
+						}
+					}
+
+				}
+
+				ret[i]=arr;
+
+			} break;
+			case VS::ARRAY_COLOR: {
+
+				DVector<Color> arr;
+				arr.resize(p_vertex_len);
+
+				if (p_format&ARRAY_COMPRESS_COLOR) {
+
+					DVector<Color>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Color( float(v[0]/255.0)*2.0-1.0, float(v[1]/255.0)*2.0-1.0, float(v[2]/255.0)*2.0-1.0, float(v[3]/255.0)*2.0-1.0 );
+					}
+				} else {
+					DVector<Color>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Color(v[0],v[1],v[2],v[3]);
+					}
+				}
+
+				ret[i]=arr;
+			} break;
+			case VS::ARRAY_TEX_UV: {
+
+				DVector<Vector2> arr;
+				arr.resize(p_vertex_len);
+
+				if (p_format&ARRAY_COMPRESS_TEX_UV) {
+
+					DVector<Vector2>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]));
+					}
+				} else {
+
+					DVector<Vector2>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector2(v[0],v[1]);
+					}
+				}
+
+				ret[i]=arr;
+			} break;
+
+			case VS::ARRAY_TEX_UV2: {
+				DVector<Vector2> arr;
+				arr.resize(p_vertex_len);
+
+				if (p_format&ARRAY_COMPRESS_TEX_UV2) {
+
+					DVector<Vector2>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]));
+					}
+				} else {
+
+					DVector<Vector2>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						w[j]=Vector2(v[0],v[1]);
+					}
+				}
+
+				ret[i]=arr;
+
+			} break;
+			case VS::ARRAY_WEIGHTS: {
+
+				DVector<float> arr;
+				arr.resize(p_vertex_len*4);
+				if (p_format&ARRAY_COMPRESS_WEIGHTS) {
+					DVector<float>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=float(v[k]/65535.0)*2.0-1.0;
+						}
+					}
+				} else {
+
+					DVector<float>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+						const float *v = (const float*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=v[k];
+						}
+					}
+
+				}
+
+				ret[i]=arr;
+
+			} break;
+			case VS::ARRAY_BONES: {
+
+				DVector<int> arr;
+				arr.resize(p_vertex_len*4);
+				if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) {
+
+					DVector<int>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+
+						const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=v[k];
+						}
+					}
+				} else {
+
+					DVector<int>::Write w = arr.write();
+
+					for(int j=0;j<p_vertex_len;j++) {
+						const int *v = (const int*)&r[j*total_elem_size+offsets[i]];
+						for(int k=0;k<4;k++) {
+							w[j*4+k]=v[k];
+						}
+					}
+
+				}
+
+				ret[i]=arr;
+
+			} break;
+			case VS::ARRAY_INDEX: {
+				/* determine wether using 16 or 32 bits indices */
+
+				DVector<uint8_t>::Read ir = p_index_data.read();
+
+				DVector<int> arr;
+				arr.resize(p_index_len);
+				if (p_index_len<(1<<16)) {
+
+					DVector<int>::Write w = arr.write();
+
+					for(int j=0;j<p_index_len;j++) {
+
+						const uint16_t *v = (const uint16_t*)&ir[j*2];
+						w[j]=*v;
+					}
+				} else {
+
+					DVector<int>::Write w = arr.write();
+
+					for(int j=0;j<p_index_len;j++) {
+						const int *v = (const int*)&ir[j*4];
+						w[j]=*v;
+					}
+
+				}
+				ret[i]=arr;
+			} break;
+			default: {
+				ERR_FAIL_V( ret );
+			}
+		}
+	}
+
+	return ret;
+}
+
+Array VisualServer::mesh_surface_get_arrays(RID p_mesh,int p_surface) const {
+
+	DVector<uint8_t> vertex_data = mesh_surface_get_array(p_mesh,p_surface);
+	ERR_FAIL_COND_V(vertex_data.size()==0,Array());
+	int vertex_len = mesh_surface_get_array_len(p_mesh,p_surface);
+
+	DVector<uint8_t> index_data = mesh_surface_get_index_array(p_mesh,p_surface);
+	int index_len = mesh_surface_get_array_index_len(p_mesh,p_surface);
+
+	uint32_t format = mesh_surface_get_format(p_mesh,p_surface);
+
+
+	return _get_array_from_surface(format,vertex_data,vertex_len,index_data,index_len);
+
+}
+
 void VisualServer::_bind_methods() {
 
 

+ 26 - 2
servers/visual_server.h

@@ -51,6 +51,8 @@ class VisualServer : public Object {
 	DVector<String> _shader_get_param_list(RID p_shader) const;
 	void _camera_set_orthogonal(RID p_camera,float p_size,float p_z_near,float p_z_far);
 	void _canvas_item_add_style_box(RID p_item, const Rect2& p_rect, const Rect2& p_source, RID p_texture,const Vector<float>& p_margins, const Color& p_modulate=Color(1,1,1));
+	Array _get_array_from_surface(uint32_t p_format,DVector<uint8_t> p_vertex_data,int p_vertex_len,DVector<uint8_t> p_index_data,int p_index_len) const;
+
 protected:
 	RID _make_test_cube();
 	void _free_internal_rids();
@@ -258,10 +260,15 @@ public:
 	virtual DVector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const=0;
 	virtual DVector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const=0;
 
+	virtual Array mesh_surface_get_arrays(RID p_mesh,int p_surface) const;
 
 	virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const=0;
 	virtual PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const=0;
 
+	virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const=0;
+	virtual Vector<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0;
+	virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const=0;
+
 	virtual void mesh_remove_surface(RID p_mesh,int p_index)=0;
 	virtual int mesh_get_surface_count(RID p_mesh) const=0;
 
@@ -354,7 +361,6 @@ public:
 		LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
 		LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
 		LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
-		LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET,
 		LIGHT_PARAM_SHADOW_NORMAL_BIAS,
 		LIGHT_PARAM_SHADOW_BIAS,
 		LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
@@ -372,10 +378,25 @@ 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;
 
+	// omni light
+	enum LightOmniShadowMode {
+		LIGHT_OMNI_SHADOW_DUAL_PARABOLOID,
+		LIGHT_OMNI_SHADOW_CUBE,
+	};
+
+	virtual void light_omni_set_shadow_mode(RID p_light,LightOmniShadowMode p_mode)=0;
+
+	// omni light
+	enum LightOmniShadowDetail {
+		LIGHT_OMNI_SHADOW_DETAIL_VERTICAL,
+		LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL
+	};
+
+	virtual void light_omni_set_shadow_detail(RID p_light,LightOmniShadowDetail p_detail)=0;
+
 	// directional light
 	enum LightDirectionalShadowMode {
 		LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL,
-		LIGHT_DIRECTIONAL_SHADOW_PERSPECTIVE,
 		LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS,
 		LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS
 	};
@@ -475,6 +496,9 @@ public:
 	virtual void viewport_set_global_canvas_transform(RID p_viewport,const Matrix32& p_transform)=0;
 	virtual void viewport_set_canvas_layer(RID p_viewport,RID p_canvas,int p_layer)=0;
 
+	virtual void viewport_set_shadow_atlas_size(RID p_viewport,int p_size)=0;
+	virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv)=0;
+
 
 	/* ENVIRONMENT API */
 

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

@@ -1468,7 +1468,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
 				mr.push_back(a);
 			}
 
-			p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d,mr);
+			p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr);
 
 			if (material.is_valid()) {
 				p_mesh->surface_set_material(surface, material);

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

@@ -1823,6 +1823,19 @@ void SpatialEditorViewport::_notification(int p_what) {
 				surface->update();
 		}
 
+
+		int shadowmap_size = Globals::get_singleton()->get("rendering/shadow_atlas/size");
+		int atlas_q0 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_0_subdiv");
+		int atlas_q1 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_1_subdiv");
+		int atlas_q2 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_2_subdiv");
+		int atlas_q3 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_3_subdiv");
+
+		viewport->set_shadow_atlas_size(shadowmap_size);
+		viewport->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
+		viewport->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
+		viewport->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
+		viewport->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
+
 	}
 
 	if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -2354,6 +2367,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	c->set_area_as_parent_rect();
 	viewport = memnew( Viewport );
 	viewport->set_disable_input(true);
+
 	c->add_child(viewport);
 	surface = memnew( Control );
 	add_child(surface);

+ 6 - 6
tools/editor/spatial_editor_gizmos.cpp

@@ -133,7 +133,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat
 	a[Mesh::ARRAY_COLOR]=color;
 
 
-	mesh->add_surface(Mesh::PRIMITIVE_LINES,a);
+	mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,a);
 	mesh->surface_set_material(0,p_material);
 
 	if (p_billboard) {
@@ -182,7 +182,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material>& p_material,
 	a.resize(Mesh::ARRAY_MAX);
 	a[Mesh::ARRAY_VERTEX]=vs;
 	a[Mesh::ARRAY_TEX_UV]=uv;
-	mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
+	mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
 	mesh->surface_set_material(0,p_material);
 
 	if (true) {
@@ -259,7 +259,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
 
 	}
 	a[VS::ARRAY_COLOR]=colors;
-	mesh->add_surface(Mesh::PRIMITIVE_POINTS,a);
+	mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS,a);
 	mesh->surface_set_material(0,SpatialEditorGizmos::singleton->handle2_material);
 
 	if (p_billboard) {
@@ -2321,7 +2321,7 @@ void NavigationMeshSpatialGizmo::redraw() {
 	Array a;
 	a.resize(Mesh::ARRAY_MAX);
 	a[0]=tmeshfaces;
-	m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+	m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,a);
 	m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
 	add_mesh(m);
 	add_collision_segments(lines);
@@ -3090,7 +3090,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		d.resize(VS::ARRAY_MAX);
 		d[Mesh::ARRAY_VERTEX]=cursor_points;
 		d[Mesh::ARRAY_COLOR]=cursor_colors;
-		pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES,d);
+		pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,d);
 		pos3d_mesh->surface_set_material(0,mat);
 	}
 
@@ -3114,7 +3114,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		d.resize(VS::ARRAY_MAX);
 		d[Mesh::ARRAY_VERTEX] = cursor_points;
 		d[Mesh::ARRAY_COLOR] = cursor_colors;
-		listener_line_mesh->add_surface(Mesh::PRIMITIVE_LINES, d);
+		listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
 		listener_line_mesh->surface_set_material(0, mat);
 	}
 

Some files were not shown because too many files changed in this diff