浏览代码

Support lights and shadows in GLES2, fixes #21853

Juan Linietsky 6 年之前
父节点
当前提交
3bdd1ff387

+ 303 - 3
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -186,6 +186,42 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
 		glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
 	}
 
+	if (p_normal_map == state.current_normal) {
+		//do none
+		state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, state.current_normal.is_valid());
+
+	} else if (p_normal_map.is_valid()) {
+
+		RasterizerStorageGLES2::Texture *normal_map = storage->texture_owner.getornull(p_normal_map);
+
+		if (!normal_map) {
+			state.current_normal = RID();
+			glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
+			glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
+			state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false);
+
+		} else {
+
+			normal_map = normal_map->get_ptr();
+
+			if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies
+				VisualServerRaster::redraw_request();
+			}
+
+			glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
+			glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
+			state.current_normal = p_normal_map;
+			state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, true);
+		}
+
+	} else {
+
+		state.current_normal = RID();
+		glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
+		glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
+		state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false);
+	}
+
 	return tex_return;
 }
 
@@ -1053,10 +1089,164 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
 
 		_set_uniforms();
 
-		_canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr);
+		if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked))
+			_canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr);
 
 		rebind_shader = true; // hacked in for now.
 
+		if ((blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA) && p_light && !unshaded) {
+
+			Light *light = p_light;
+			bool light_used = false;
+			VS::CanvasLightMode mode = VS::CANVAS_LIGHT_MODE_ADD;
+			state.uniforms.final_modulate = ci->final_modulate; // remove the canvas modulate
+
+			while (light) {
+
+				if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
+
+					//intersects this light
+
+					if (!light_used || mode != light->mode) {
+
+						mode = light->mode;
+
+						switch (mode) {
+
+							case VS::CANVAS_LIGHT_MODE_ADD: {
+								glBlendEquation(GL_FUNC_ADD);
+								glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+							} break;
+							case VS::CANVAS_LIGHT_MODE_SUB: {
+								glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+								glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+							} break;
+							case VS::CANVAS_LIGHT_MODE_MIX:
+							case VS::CANVAS_LIGHT_MODE_MASK: {
+								glBlendEquation(GL_FUNC_ADD);
+								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+							} break;
+						}
+					}
+
+					if (!light_used) {
+
+						state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, true);
+						light_used = true;
+					}
+
+					bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask & light->item_shadow_mask;
+
+					state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, has_shadow);
+					if (has_shadow) {
+						state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0);
+						switch (light->shadow_filter) {
+
+							case VS::CANVAS_LIGHT_FILTER_NONE: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, true); break;
+							case VS::CANVAS_LIGHT_FILTER_PCF3: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, true); break;
+							case VS::CANVAS_LIGHT_FILTER_PCF5: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, true); break;
+							case VS::CANVAS_LIGHT_FILTER_PCF7: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, true); break;
+							case VS::CANVAS_LIGHT_FILTER_PCF9: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, true); break;
+							case VS::CANVAS_LIGHT_FILTER_PCF13: state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, true); break;
+						}
+					}
+
+					bool light_rebind = state.canvas_shader.bind();
+
+					if (light_rebind) {
+
+						_set_uniforms();
+					}
+
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX, light->light_shader_xform);
+					Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized();
+					basis_inverse[2] = Vector2();
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX_INVERSE, basis_inverse);
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse());
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR, light->color * light->energy);
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS, light->light_shader_pos);
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT, light->height);
+					state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0);
+
+					if (has_shadow) {
+						RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer);
+						glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
+						glBindTexture(GL_TEXTURE_2D, cls->distance);
+						state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX, light->shadow_matrix_cache);
+						state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR, light->shadow_color);
+						state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE, (1.0 / light->shadow_buffer_size) * (1.0 + light->shadow_smooth));
+						if (light->radius_cache == 0) {
+							state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, 0.0);
+						} else {
+							state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, light->shadow_gradient_length / (light->radius_cache * 1.1));
+						}
+						state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_DISTANCE_MULT, light->radius_cache * 1.1);
+
+						/*canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache);
+						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult);
+						canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR,light->shadow_color);*/
+					}
+
+					glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
+					RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(light->texture);
+					if (!t) {
+						glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+					} else {
+						t = t->get_ptr();
+
+						glBindTexture(t->target, t->tex_id);
+					}
+
+					glActiveTexture(GL_TEXTURE0);
+					_canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); //redraw using light
+				}
+
+				light = light->next_ptr;
+			}
+
+			if (light_used) {
+
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, false);
+				state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, false);
+
+				state.canvas_shader.bind();
+
+				last_blend_mode = -1;
+
+				/*
+				//this is set again, so it should not be needed anyway?
+				state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(
+							ci->final_modulate.r * p_modulate.r,
+							ci->final_modulate.g * p_modulate.g,
+							ci->final_modulate.b * p_modulate.b,
+							ci->final_modulate.a * p_modulate.a );
+
+
+				state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,state.final_transform);
+				state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Transform2D());
+				state.canvas_shader.set_uniform(CanvasShaderGLES2::FINAL_MODULATE,state.canvas_item_modulate);
+
+				glBlendEquation(GL_FUNC_ADD);
+
+				if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+					glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+				} else {
+					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+				}
+
+				//@TODO RESET canvas_blend_mode
+				*/
+			}
+		}
+
 		if (reclip) {
 			glEnable(GL_SCISSOR_TEST);
 			int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
@@ -1077,8 +1267,116 @@ void RasterizerCanvasGLES2::canvas_debug_viewport_shadows(Light *p_lights_with_s
 }
 
 void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) {
-}
 
+	RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer);
+	ERR_FAIL_COND(!cls);
+
+	glDisable(GL_BLEND);
+	glDisable(GL_SCISSOR_TEST);
+	glDisable(GL_DITHER);
+	glDisable(GL_CULL_FACE);
+	glDepthFunc(GL_LEQUAL);
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(true);
+
+	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+	state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
+	state.canvas_shadow_shader.bind();
+
+	glViewport(0, 0, cls->size, cls->height);
+	glClearDepth(1.0f);
+	glClearColor(1, 1, 1, 1);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	VS::CanvasOccluderPolygonCullMode cull = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+	for (int i = 0; i < 4; i++) {
+
+		//make sure it remains orthogonal, makes easy to read angle later
+
+		Transform light;
+		light.origin[0] = p_light_xform[2][0];
+		light.origin[1] = p_light_xform[2][1];
+		light.basis[0][0] = p_light_xform[0][0];
+		light.basis[0][1] = p_light_xform[1][0];
+		light.basis[1][0] = p_light_xform[0][1];
+		light.basis[1][1] = p_light_xform[1][1];
+
+		//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
+
+		//p_near=1;
+		CameraMatrix projection;
+		{
+			real_t fov = 90;
+			real_t nearp = p_near;
+			real_t farp = p_far;
+			real_t aspect = 1.0;
+
+			real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5));
+			real_t ymin = -ymax;
+			real_t xmin = ymin * aspect;
+			real_t xmax = ymax * aspect;
+
+			projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
+		}
+
+		Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0));
+		projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+
+		state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX, projection);
+		state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX, light);
+		state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::DISTANCE_NORM, 1.0 / p_far);
+
+		if (i == 0)
+			*p_xform_cache = projection;
+
+		glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4);
+
+		LightOccluderInstance *instance = p_occluders;
+
+		while (instance) {
+
+			RasterizerStorageGLES2::CanvasOccluder *cc = storage->canvas_occluder_owner.get(instance->polygon_buffer);
+			if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) {
+
+				instance = instance->next;
+				continue;
+			}
+
+			state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX, instance->xform_cache);
+			if (cull != instance->cull_cache) {
+
+				cull = instance->cull_cache;
+				switch (cull) {
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: {
+
+						glDisable(GL_CULL_FACE);
+
+					} break;
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: {
+
+						glEnable(GL_CULL_FACE);
+						glCullFace(GL_FRONT);
+					} break;
+					case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: {
+
+						glEnable(GL_CULL_FACE);
+						glCullFace(GL_BACK);
+
+					} break;
+				}
+			}
+
+			glBindVertexArray(cc->array_id);
+			glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0);
+
+			instance = instance->next;
+		}
+	}
+
+	glBindVertexArray(0);
+}
 void RasterizerCanvasGLES2::reset_canvas() {
 
 	glDisable(GL_CULL_FACE);
@@ -1094,7 +1392,7 @@ void RasterizerCanvasGLES2::reset_canvas() {
 	}
 
 	// bind the back buffer to a texture so shaders can use it.
-	// It should probably use texture unit -3 (as GLES3 does as well) but currently that's buggy.
+	// It should probably use texture unit -3 (as GLES2 does as well) but currently that's buggy.
 	// keeping this for now as there's nothing else that uses texture unit 2
 	// TODO ^
 	if (storage->frame.current_rt) {
@@ -1264,6 +1562,8 @@ void RasterizerCanvasGLES2::initialize() {
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 	}
 
+	state.canvas_shadow_shader.init();
+
 	state.canvas_shader.init();
 
 	state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);

+ 2 - 2
drivers/gles2/rasterizer_canvas_gles2.h

@@ -36,7 +36,7 @@
 #include "shaders/canvas.glsl.gen.h"
 #include "shaders/lens_distorted.glsl.gen.h"
 
-// #include "shaders/canvas_shadow.glsl.gen.h"
+#include "shaders/canvas_shadow.glsl.gen.h"
 
 class RasterizerSceneGLES2;
 
@@ -70,7 +70,7 @@ public:
 		Uniforms uniforms;
 		bool canvas_texscreen_used;
 		CanvasShaderGLES2 canvas_shader;
-		// CanvasShadowShaderGLES3 canvas_shadow_shader;
+		CanvasShadowShaderGLES2 canvas_shadow_shader;
 		LensDistortedShaderGLES2 lens_shader;
 
 		bool using_texture_rect;

+ 177 - 4
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -1138,6 +1138,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 
 		case VS::SHADER_CANVAS_ITEM: {
 
+			p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL;
 			p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX;
 
 			p_shader->canvas_item.uses_screen_texture = false;
@@ -1150,8 +1151,8 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
 			shaders.actions_canvas.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL);
 			shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA);
 
-			// shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED);
-			// shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY);
+			shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED);
+			shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY);
 
 			shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv;
 			shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv;
@@ -4193,16 +4194,161 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie
 /* CANVAS SHADOW */
 
 RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) {
-	return RID();
+
+	CanvasLightShadow *cls = memnew(CanvasLightShadow);
+	if (p_width > config.max_texture_size)
+		p_width = config.max_texture_size;
+
+	cls->size = p_width;
+	cls->height = 16;
+
+	glActiveTexture(GL_TEXTURE0);
+
+	glGenFramebuffers(1, &cls->fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
+
+	glGenRenderbuffers(1, &cls->depth);
+	glBindRenderbuffer(GL_RENDERBUFFER, cls->depth);
+	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cls->size, cls->height);
+	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth);
+	glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+	glGenTextures(1, &cls->distance);
+	glBindTexture(GL_TEXTURE_2D, cls->distance);
+	if (config.use_rgba_2d_shadows) {
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+	} else {
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, NULL);
+	}
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0);
+
+	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	//printf("errnum: %x\n",status);
+	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
+
+	if (status != GL_FRAMEBUFFER_COMPLETE) {
+		memdelete(cls);
+		ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
+	}
+
+	return canvas_light_shadow_owner.make_rid(cls);
 }
 
 /* LIGHT SHADOW MAPPING */
 
 RID RasterizerStorageGLES2::canvas_light_occluder_create() {
-	return RID();
+
+	CanvasOccluder *co = memnew(CanvasOccluder);
+	co->index_id = 0;
+	co->vertex_id = 0;
+	co->len = 0;
+	glGenVertexArrays(1, &co->array_id);
+
+	return canvas_occluder_owner.make_rid(co);
 }
 
 void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
+
+	CanvasOccluder *co = canvas_occluder_owner.get(p_occluder);
+	ERR_FAIL_COND(!co);
+
+	co->lines = p_lines;
+
+	if (p_lines.size() != co->len) {
+
+		if (co->index_id)
+			glDeleteBuffers(1, &co->index_id);
+		if (co->vertex_id)
+			glDeleteBuffers(1, &co->vertex_id);
+
+		co->index_id = 0;
+		co->vertex_id = 0;
+		co->len = 0;
+	}
+
+	if (p_lines.size()) {
+
+		PoolVector<float> geometry;
+		PoolVector<uint16_t> indices;
+		int lc = p_lines.size();
+
+		geometry.resize(lc * 6);
+		indices.resize(lc * 3);
+
+		PoolVector<float>::Write vw = geometry.write();
+		PoolVector<uint16_t>::Write iw = indices.write();
+
+		PoolVector<Vector2>::Read lr = p_lines.read();
+
+		const int POLY_HEIGHT = 16384;
+
+		for (int i = 0; i < lc / 2; i++) {
+
+			vw[i * 12 + 0] = lr[i * 2 + 0].x;
+			vw[i * 12 + 1] = lr[i * 2 + 0].y;
+			vw[i * 12 + 2] = POLY_HEIGHT;
+
+			vw[i * 12 + 3] = lr[i * 2 + 1].x;
+			vw[i * 12 + 4] = lr[i * 2 + 1].y;
+			vw[i * 12 + 5] = POLY_HEIGHT;
+
+			vw[i * 12 + 6] = lr[i * 2 + 1].x;
+			vw[i * 12 + 7] = lr[i * 2 + 1].y;
+			vw[i * 12 + 8] = -POLY_HEIGHT;
+
+			vw[i * 12 + 9] = lr[i * 2 + 0].x;
+			vw[i * 12 + 10] = lr[i * 2 + 0].y;
+			vw[i * 12 + 11] = -POLY_HEIGHT;
+
+			iw[i * 6 + 0] = i * 4 + 0;
+			iw[i * 6 + 1] = i * 4 + 1;
+			iw[i * 6 + 2] = i * 4 + 2;
+
+			iw[i * 6 + 3] = i * 4 + 2;
+			iw[i * 6 + 4] = i * 4 + 3;
+			iw[i * 6 + 5] = i * 4 + 0;
+		}
+
+		//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
+
+		if (!co->vertex_id) {
+			glGenBuffers(1, &co->vertex_id);
+			glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
+			glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW);
+		} else {
+
+			glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
+			glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr());
+		}
+
+		glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+		if (!co->index_id) {
+
+			glGenBuffers(1, &co->index_id);
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
+			glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW);
+		} else {
+
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
+			glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr());
+		}
+
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
+
+		co->len = lc;
+		glBindVertexArray(co->array_id);
+		glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id);
+		glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+		glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0);
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id);
+		glBindVertexArray(0);
+	}
 }
 
 VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
@@ -4415,6 +4561,32 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
 		lightmap_capture_data_owner.free(p_rid);
 		memdelete(lightmap_capture);
 		return true;
+
+	} else if (canvas_occluder_owner.owns(p_rid)) {
+
+		CanvasOccluder *co = canvas_occluder_owner.get(p_rid);
+		if (co->index_id)
+			glDeleteBuffers(1, &co->index_id);
+		if (co->vertex_id)
+			glDeleteBuffers(1, &co->vertex_id);
+
+		glDeleteVertexArrays(1, &co->array_id);
+
+		canvas_occluder_owner.free(p_rid);
+		memdelete(co);
+
+		return true;
+
+	} else if (canvas_light_shadow_owner.owns(p_rid)) {
+
+		CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid);
+		glDeleteFramebuffers(1, &cls->fbo);
+		glDeleteRenderbuffers(1, &cls->depth);
+		glDeleteTextures(1, &cls->distance);
+		canvas_light_shadow_owner.free(p_rid);
+		memdelete(cls);
+
+		return true;
 	} else {
 		return false;
 	}
@@ -4471,6 +4643,7 @@ void RasterizerStorageGLES2::initialize() {
 	config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float");
 	config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc");
 	config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
+	config.use_rgba_2d_shadows = false;
 
 	frame.count = 0;
 	frame.delta = 0;

+ 25 - 2
drivers/gles2/rasterizer_storage_gles2.h

@@ -76,6 +76,8 @@ public:
 		bool keep_original_textures;
 
 		bool force_vertex_shading;
+
+		bool use_rgba_2d_shadows;
 	} config;
 
 	struct Resources {
@@ -86,6 +88,7 @@ public:
 		GLuint aniso_tex;
 
 		GLuint radical_inverse_vdc_cache_tex;
+		bool use_rgba_2d_shadows;
 
 		GLuint quadie;
 
@@ -400,7 +403,6 @@ public:
 
 			int blend_mode;
 
-			/*
 			enum LightMode {
 				LIGHT_MODE_NORMAL,
 				LIGHT_MODE_UNSHADED,
@@ -408,7 +410,6 @@ public:
 			};
 
 			int light_mode;
-			*/
 
 			bool uses_screen_texture;
 			bool uses_screen_uv;
@@ -1161,10 +1162,32 @@ public:
 
 	/* CANVAS SHADOW */
 
+	struct CanvasLightShadow : public RID_Data {
+
+		int size;
+		int height;
+		GLuint fbo;
+		GLuint depth;
+		GLuint distance; //for older devices
+	};
+
+	RID_Owner<CanvasLightShadow> canvas_light_shadow_owner;
+
 	virtual RID canvas_light_shadow_buffer_create(int p_width);
 
 	/* LIGHT SHADOW MAPPING */
 
+	struct CanvasOccluder : public RID_Data {
+
+		GLuint array_id; // 0 means, unconfigured
+		GLuint vertex_id; // 0 means, unconfigured
+		GLuint index_id; // 0 means, unconfigured
+		PoolVector<Vector2> lines;
+		int len;
+	};
+
+	RID_Owner<CanvasOccluder> canvas_occluder_owner;
+
 	virtual RID canvas_light_occluder_create();
 	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines);
 

+ 1 - 1
drivers/gles2/shaders/SCsub

@@ -6,7 +6,7 @@ if 'GLES2_GLSL' in env['BUILDERS']:
     env.GLES2_GLSL('copy.glsl');
 #    env.GLES2_GLSL('resolve.glsl');
     env.GLES2_GLSL('canvas.glsl');
-#    env.GLES2_GLSL('canvas_shadow.glsl');
+    env.GLES2_GLSL('canvas_shadow.glsl');
     env.GLES2_GLSL('scene.glsl');
     env.GLES2_GLSL('cubemap_filter.glsl');
     env.GLES2_GLSL('cube_to_dp.glsl');

+ 321 - 1
drivers/gles2/shaders/canvas.glsl

@@ -31,6 +31,38 @@ uniform vec4 src_rect;
 
 uniform highp float time;
 
+
+
+#ifdef USE_LIGHTING
+
+// light matrices
+uniform highp mat4 light_matrix;
+uniform highp mat4 light_matrix_inverse;
+uniform highp mat4 light_local_matrix;
+uniform highp mat4 shadow_matrix;
+uniform highp vec4 light_color;
+uniform highp vec4 light_shadow_color;
+uniform highp vec2 light_pos;
+uniform highp float shadowpixel_size;
+uniform highp float shadow_gradient;
+uniform highp float light_height;
+uniform highp float light_outside_alpha;
+uniform highp float shadow_distance_mult;
+
+varying vec4 light_uv_interp;
+varying vec2 transformed_light_uv;
+varying vec4 local_rot;
+
+#ifdef USE_SHADOWS
+varying highp vec2 pos;
+#endif
+
+const bool at_light_pass = true;
+#else
+const bool at_light_pass = false;
+#endif
+
+
 /* clang-format off */
 
 VERTEX_SHADER_GLOBALS
@@ -48,8 +80,19 @@ vec2 select(vec2 a, vec2 b, bvec2 c) {
 
 void main() {
 
+
 	vec4 color = color_attrib;
 
+#ifdef USE_INSTANCING
+	mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
+	color *= instance_color;
+	vec4 instance_custom = instance_custom_data;
+
+#else
+	mat4 extra_matrix_instance = extra_matrix;
+	vec4 instance_custom = vec4(0.0);
+#endif
+
 #ifdef USE_TEXTURE_RECT
 
 	if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
@@ -96,6 +139,27 @@ VERTEX_SHADER_CODE
 #endif
 
 	gl_Position = projection_matrix * outvec;
+
+#ifdef USE_LIGHTING
+
+	light_uv_interp.xy = (light_matrix * outvec).xy;
+	light_uv_interp.zw = (light_local_matrix * outvec).xy;
+
+	transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping
+
+#ifdef USE_SHADOWS
+	pos = outvec.xy;
+#endif
+
+	local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy);
+	local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy);
+#ifdef USE_TEXTURE_RECT
+	local_rot.xy *= sign(src_rect.z);
+	local_rot.zw *= sign(src_rect.w);
+#endif
+
+#endif
+
 }
 
 /* clang-format off */
@@ -133,6 +197,41 @@ uniform vec2 screen_pixel_size;
 
 #endif
 
+#ifdef USE_LIGHTING
+
+uniform highp mat4 light_matrix;
+uniform highp mat4 light_local_matrix;
+uniform highp mat4 shadow_matrix;
+uniform highp vec4 light_color;
+uniform highp vec4 light_shadow_color;
+uniform highp vec2 light_pos;
+uniform highp float shadowpixel_size;
+uniform highp float shadow_gradient;
+uniform highp float light_height;
+uniform highp float light_outside_alpha;
+uniform highp float shadow_distance_mult;
+
+uniform lowp sampler2D light_texture; // texunit:-3
+varying vec4 light_uv_interp;
+varying vec2 transformed_light_uv;
+
+varying vec4 local_rot;
+
+#ifdef USE_SHADOWS
+
+uniform highp sampler2D shadow_texture; // texunit:-4
+varying highp vec2 pos;
+
+#endif
+
+const bool at_light_pass = true;
+#else
+const bool at_light_pass = false;
+#endif
+
+uniform bool use_default_normal;
+
+
 /* clang-format off */
 
 FRAGMENT_SHADER_GLOBALS
@@ -151,15 +250,236 @@ void main() {
 #ifdef SCREEN_UV_USED
 	vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
 #endif
+
+	vec3 normal;
+
+#if defined(NORMAL_USED)
+
+	bool normal_used = true;
+#else
+	bool normal_used = false;
+#endif
+
+	if (use_default_normal) {
+		normal.xy = texture2D(normal_texture, uv_interp).xy * 2.0 - 1.0;
+		normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+		normal_used = true;
+	} else {
+		normal = vec3(0.0, 0.0, 1.0);
+	}
+
 	{
+		float normal_depth = 1.0;
+
+#if defined(NORMALMAP_USED)
+		vec3 normal_map = vec3(0.0, 0.0, 1.0);
+		normal_used = true;
+#endif
+
 		/* clang-format off */
 
 FRAGMENT_SHADER_CODE
 
 		/* clang-format on */
-	}
 
+#if defined(NORMALMAP_USED)
+		normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth);
+#endif
+	}
 	color *= final_modulate;
 
+#ifdef USE_LIGHTING
+
+	vec2 light_vec = transformed_light_uv;
+
+	if (normal_used) {
+		normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy;
+	}
+
+	float att = 1.0;
+
+	vec2 light_uv = light_uv_interp.xy;
+	vec4 light = texture2D(light_texture, light_uv);
+
+	if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) {
+		color.a *= light_outside_alpha; //invisible
+
+	} else {
+		float real_light_height = light_height;
+		vec4 real_light_color = light_color;
+		vec4 real_light_shadow_color = light_shadow_color;
+
+#if defined(USE_LIGHT_SHADER_CODE)
+		//light is written by the light shader
+		light_compute(
+				light,
+				light_vec,
+				real_light_height,
+				real_light_color,
+				light_uv,
+				real_light_shadow_color,
+				normal,
+				uv,
+#if defined(SCREEN_UV_USED)
+				screen_uv,
+#endif
+				color);
+#endif
+
+		light *= real_light_color;
+
+		if (normal_used) {
+			vec3 light_normal = normalize(vec3(light_vec, -real_light_height));
+			light *= max(dot(-light_normal, normal), 0.0);
+		}
+
+		color *= light;
+
+#ifdef USE_SHADOWS
+		light_vec = light_uv_interp.zw; //for shadows
+		float angle_to_light = -atan(light_vec.x, light_vec.y);
+		float PI = 3.14159265358979323846264;
+		/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
+		float ang*/
+
+		float su, sz;
+
+		float abs_angle = abs(angle_to_light);
+		vec2 point;
+		float sh;
+		if (abs_angle < 45.0 * PI / 180.0) {
+			point = light_vec;
+			sh = 0.0 + (1.0 / 8.0);
+		} else if (abs_angle > 135.0 * PI / 180.0) {
+			point = -light_vec;
+			sh = 0.5 + (1.0 / 8.0);
+		} else if (angle_to_light > 0.0) {
+
+			point = vec2(light_vec.y, -light_vec.x);
+			sh = 0.25 + (1.0 / 8.0);
+		} else {
+
+			point = vec2(-light_vec.y, light_vec.x);
+			sh = 0.75 + (1.0 / 8.0);
+		}
+
+		highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0);
+		s.xyz /= s.w;
+		su = s.x * 0.5 + 0.5;
+		sz = s.z * 0.5 + 0.5;
+		//sz=lightlength(light_vec);
+
+		highp float shadow_attenuation = 0.0;
+
+#ifdef USE_RGBA_SHADOWS
+
+#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1))
+
+#else
+
+#define SHADOW_DEPTH(m_tex, m_uv) (texture2D((m_tex), (m_uv)).r)
+
+#endif
+
+#ifdef SHADOW_USE_GRADIENT
+
+#define SHADOW_TEST(m_ofs)                                                    \
+	{                                                                         \
+		highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh));       \
+		shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); \
+	}
+
+#else
+
+#define SHADOW_TEST(m_ofs)                                              \
+	{                                                                   \
+		highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); \
+		shadow_attenuation += step(sz, sd);                             \
+	}
+
+#endif
+
+#ifdef SHADOW_FILTER_NEAREST
+
+		SHADOW_TEST(su);
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF3
+
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		shadow_attenuation /= 3.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF5
+
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		shadow_attenuation /= 5.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF7
+
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		shadow_attenuation /= 7.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF9
+
+		SHADOW_TEST(su + shadowpixel_size * 4.0);
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		SHADOW_TEST(su - shadowpixel_size * 4.0);
+		shadow_attenuation /= 9.0;
+
+#endif
+
+#ifdef SHADOW_FILTER_PCF13
+
+		SHADOW_TEST(su + shadowpixel_size * 6.0);
+		SHADOW_TEST(su + shadowpixel_size * 5.0);
+		SHADOW_TEST(su + shadowpixel_size * 4.0);
+		SHADOW_TEST(su + shadowpixel_size * 3.0);
+		SHADOW_TEST(su + shadowpixel_size * 2.0);
+		SHADOW_TEST(su + shadowpixel_size);
+		SHADOW_TEST(su);
+		SHADOW_TEST(su - shadowpixel_size);
+		SHADOW_TEST(su - shadowpixel_size * 2.0);
+		SHADOW_TEST(su - shadowpixel_size * 3.0);
+		SHADOW_TEST(su - shadowpixel_size * 4.0);
+		SHADOW_TEST(su - shadowpixel_size * 5.0);
+		SHADOW_TEST(su - shadowpixel_size * 6.0);
+		shadow_attenuation /= 13.0;
+
+#endif
+
+		//color *= shadow_attenuation;
+		color = mix(real_light_shadow_color, color, shadow_attenuation);
+//use shadows
+#endif
+	}
+
+//use lighting
+#endif
+
 	gl_FragColor = color;
 }

+ 22 - 16
drivers/gles2/shaders/canvas_shadow.glsl

@@ -1,15 +1,23 @@
 /* clang-format off */
 [vertex]
 
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision highp float;
+precision highp int;
+#endif
+
+attribute highp vec3 vertex; // attrib:0
+
 uniform highp mat4 projection_matrix;
 /* clang-format on */
 uniform highp mat4 light_matrix;
 uniform highp mat4 world_matrix;
 uniform highp float distance_norm;
 
-layout(location = 0) in highp vec3 vertex;
-
-out highp vec4 position_interp;
+varying highp vec4 position_interp;
 
 void main() {
 
@@ -20,31 +28,29 @@ void main() {
 /* clang-format off */
 [fragment]
 
-in highp vec4 position_interp;
-/* clang-format on */
-
-#ifdef USE_RGBA_SHADOWS
-
-layout(location = 0) out lowp vec4 distance_buf;
-
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
 #else
+precision mediump float;
+precision mediump int;
+#endif
 
-layout(location = 0) out highp float distance_buf;
+varying highp vec4 position_interp;
+/* clang-format on */
 
-#endif
 
 void main() {
 
-	highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; //bias;
+	highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
 
 #ifdef USE_RGBA_SHADOWS
 
 	highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
 	comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
-	distance_buf = comp;
+	gl_FragColor = comp;
 #else
 
-	distance_buf = depth;
-
+	gl_FragColor = vec4(depth);
 #endif
 }