diff options
-rw-r--r-- | drivers/gles2/rasterizer_gles2.cpp | 6 | ||||
-rw-r--r-- | drivers/gles2/shaders/canvas.glsl | 23 | ||||
-rw-r--r-- | scene/2d/light_2d.cpp | 3 | ||||
-rw-r--r-- | scene/2d/light_2d.h | 1 | ||||
-rw-r--r-- | servers/visual/rasterizer.h | 7 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.cpp | 44 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.h | 4 | ||||
-rw-r--r-- | servers/visual_server.h | 1 |
8 files changed, 71 insertions, 18 deletions
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index d0f2f88ee6..83b71fd5ff 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -9540,7 +9540,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_opacity = ci->final_opacity; - if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT))) + if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT) && !ci->light_masked )) _canvas_item_render_commands<false>(ci,current_clip,reclip); if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && !unshaded) { @@ -9572,7 +9572,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); glBlendFunc(GL_SRC_ALPHA,GL_ONE); } break; - case VS::CANVAS_LIGHT_MODE_MIX: { + 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); @@ -9620,6 +9621,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,Color(light->color.r*light->energy,light->color.g*light->energy,light->color.b*light->energy,light->color.a)); canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height); canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse()); + canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA,light->mode==VS::CANVAS_LIGHT_MODE_MASK?1.0:0.0); if (has_shadow) { diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index e297b328cd..259e82d704 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -155,6 +155,7 @@ uniform vec4 light_color; uniform vec4 light_shadow_color; uniform float light_height; varying vec4 light_uv_interp; +uniform float light_outside_alpha; #if defined(NORMAL_USED) varying vec4 local_rot; @@ -247,22 +248,27 @@ FRAGMENT_SHADER_CODE vec4 shadow_color=vec4(0.0,0.0,0.0,0.0); #endif + 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 { + #if defined(USE_LIGHT_SHADER_CODE) //light is written by the light shader -{ - vec4 light_out=light*color; + { + vec4 light_out=light*color; LIGHT_SHADER_CODE - color=light_out; -} + color=light_out; + } #else #if defined(NORMAL_USED) - vec3 light_normal = normalize(vec3(light_vec,-light_height)); - light*=max(dot(-light_normal,normal),0.0); + vec3 light_normal = normalize(vec3(light_vec,-light_height)); + light*=max(dot(-light_normal,normal),0.0); #endif - color*=light; + color*=light; /* #ifdef USE_NORMAL color.xy=local_rot.xy;//normal.xy; @@ -273,9 +279,6 @@ LIGHT_SHADER_CODE //light shader code #endif - 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=0.0; //invisible - } else { #ifdef USE_SHADOWS diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 852a6fb46b..a2112c7d37 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -333,7 +333,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale")); ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy"),_SCS("set_energy"),_SCS("get_energy")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix"),_SCS("set_mode"),_SCS("get_mode")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix,Mask"),_SCS("set_mode"),_SCS("get_mode")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max")); @@ -349,6 +349,7 @@ void Light2D::_bind_methods() { BIND_CONSTANT( MODE_ADD ); BIND_CONSTANT( MODE_SUB ); BIND_CONSTANT( MODE_MIX ); + BIND_CONSTANT( MODE_MASK ); } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index bf61868bac..0828d9ac33 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -11,6 +11,7 @@ public: MODE_ADD, MODE_SUB, MODE_MIX, + MODE_MASK, }; private: diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 50407f1b0f..d94067961f 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -610,6 +610,7 @@ public: CanvasLight *shadows_next_ptr; CanvasLight *filter_next_ptr; CanvasLight *next_ptr; + CanvasLight *mask_next_ptr; CanvasLight() { enabled=true; @@ -627,6 +628,7 @@ public: mode=VS::CANVAS_LIGHT_MODE_ADD; texture_cache=NULL; next_ptr=NULL; + mask_next_ptr=NULL; filter_next_ptr=NULL; shadow_buffer_size=2048; shadow_esm_mult=80; @@ -792,6 +794,7 @@ public: CanvasItem* material_owner; ViewportRender *vp_render; bool distance_field; + bool light_masked; Rect2 global_rect_cache; @@ -918,8 +921,8 @@ public: return rect; } - void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL; material_owner=NULL;} - CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1; blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; } + void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL; material_owner=NULL; light_masked=false; } + CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1; blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; light_masked=false; } virtual ~CanvasItem() { clear(); if (copy_back_buffer) memdelete(copy_back_buffer); } }; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index a94d4f64c7..79911121f5 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -6777,6 +6777,7 @@ void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void } + void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) { CanvasItem *ci = p_canvas_item; @@ -6878,6 +6879,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat ci->final_opacity=opacity * ci->self_opacity; ci->global_rect_cache=global_rect; ci->global_rect_cache.pos-=p_clip_rect.pos; + ci->light_masked=false; int zidx = p_z-CANVAS_ITEM_Z_MIN; @@ -6905,7 +6907,34 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat } -void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights) { +void VisualServerRaster::_light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights) { + + if (!p_masked_lights) + return; + + Rasterizer::CanvasItem *ci=p_canvas_item; + + while(ci) { + + Rasterizer::CanvasLight *light=p_masked_lights; + 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)) { + ci->light_masked=true; + } + + light=light->mask_next_ptr; + } + + ci=ci->next; + } + + + + +} + +void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights,Rasterizer::CanvasLight *p_masked_lights) { rasterizer->canvas_begin(); @@ -6938,6 +6967,11 @@ void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_trans for(int i=0;i<z_range;i++) { if (!z_list[i]) continue; + + if (p_masked_lights) { + _light_mask_canvas_items(CANVAS_ITEM_Z_MIN+i,z_list[i],p_masked_lights); + } + rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights); } } else { @@ -7072,6 +7106,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height); Rasterizer::CanvasLight *lights=NULL; Rasterizer::CanvasLight *lights_with_shadow=NULL; + Rasterizer::CanvasLight *lights_with_mask=NULL; Rect2 shadow_rect; int light_count=0; @@ -7119,9 +7154,14 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ cl->radius_cache=cl->rect_cache.size.length(); } + if (cl->mode==CANVAS_LIGHT_MODE_MASK) { + cl->mask_next_ptr=lights_with_mask; + lights_with_mask=cl; + } light_count++; } + } } @@ -7190,7 +7230,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ ptr=ptr->filter_next_ptr; } - _render_canvas( E->get()->canvas,xform,canvas_lights ); + _render_canvas( E->get()->canvas,xform,canvas_lights,lights_with_mask ); i++; if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index b6a5ca6308..e0127faf41 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -633,7 +633,9 @@ class VisualServerRaster : public VisualServer { static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect); void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights); void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner); - void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights); + void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights, Rasterizer::CanvasLight *p_masked_lights); + void _light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights); + Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max); Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max); diff --git a/servers/visual_server.h b/servers/visual_server.h index 96c3e15cde..c5100b8d30 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -1041,6 +1041,7 @@ public: CANVAS_LIGHT_MODE_ADD, CANVAS_LIGHT_MODE_SUB, CANVAS_LIGHT_MODE_MIX, + CANVAS_LIGHT_MODE_MASK, }; virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode)=0; |