diff options
43 files changed, 2583 insertions, 268 deletions
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e2371fe24f..ead6984650 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1778,6 +1778,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_ f->store_32(VERSION_MINOR); f->store_32(FORMAT_VERSION); + if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) { + f->close(); + return ERR_CANT_CREATE; + } + //f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed save_unicode_string(p_resource->get_type()); uint64_t md_at = f->get_pos(); @@ -1910,6 +1915,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_ f->store_buffer((const uint8_t*)"RSRC",4); //magic at end + if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) { + f->close(); + return ERR_CANT_CREATE; + } + f->close(); diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 75384d4ab6..033b4d5e5a 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -2592,6 +2592,11 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res } exit_tag("resource_file"); + if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) { + f->close(); + return ERR_CANT_CREATE; + } + f->close(); //memdelete(f); diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index a60dea7379..fbe5f8c741 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -121,7 +121,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) { - +#if 0 ///@TODO, give a check to this. I'm not sure if it's working. set_identity(); @@ -133,10 +133,27 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa matrix[2][3]=-(2*p_far*p_near) / (p_far-p_near); matrix[3][2]=-1; matrix[3][3]=0; +#else + float *te = &matrix[0][0]; + float x = 2 * p_near / ( p_right - p_left ); + float y = 2 * p_near / ( p_top - p_bottom ); + + float a = ( p_right + p_left ) / ( p_right - p_left ); + float b = ( p_top + p_bottom ) / ( p_top - p_bottom ); + float c = - ( p_far + p_near ) / ( p_far - p_near ); + float d = - 2 * p_far * p_near / ( p_far - p_near ); + + te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; + te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; + te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; + te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; + +#endif } + float CameraMatrix::get_z_far() const { const float * matrix = (const float*)this->matrix; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 21bbc8c7ee..d6129e150c 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -552,6 +552,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant& if (p_b.type==MATRIX32) { _RETURN( *p_a._data._matrix32 * *p_b._data._matrix32 ); }; + if (p_b.type==VECTOR2) { + _RETURN( p_a._data._matrix32->xform( *(const Vector2*)p_b._data._mem) ); + }; r_valid=false; return; } break; diff --git a/demos/3d/kinematic_char/cubelib.res b/demos/3d/kinematic_char/cubelib.res Binary files differindex 66b999d78d..27f2b9b3bd 100644 --- a/demos/3d/kinematic_char/cubelib.res +++ b/demos/3d/kinematic_char/cubelib.res diff --git a/demos/3d/kinematic_char/level.scn b/demos/3d/kinematic_char/level.scn Binary files differindex a276fe22e1..7ccb2430c1 100644 --- a/demos/3d/kinematic_char/level.scn +++ b/demos/3d/kinematic_char/level.scn diff --git a/drivers/SCsub b/drivers/SCsub index 46334468ba..a1a2191cbc 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -10,7 +10,6 @@ SConscript('alsa/SCsub'); SConscript('pulseaudio/SCsub');
SConscript('windows/SCsub');
SConscript('gles2/SCsub');
-SConscript('gles1/SCsub');
SConscript('gl_context/SCsub');
SConscript('openssl/SCsub');
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index aba0b5ca90..aa7bad0b8f 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -971,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu - if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { + if (!(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { texture->has_alpha=true; } @@ -2525,7 +2525,7 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui void RasterizerGLES2::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) { ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?"); - ERR_FAIL_V(); + ERR_FAIL(); } Array RasterizerGLES2::mesh_get_surface_arrays(RID p_mesh,int p_surface) const { @@ -4116,6 +4116,10 @@ void RasterizerGLES2::begin_frame() { shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter"))); #endif + canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF5,shadow_filter==SHADOW_FILTER_PCF5); + canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF13,shadow_filter==SHADOW_FILTER_PCF13); + canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM); + window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height ); double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec @@ -7874,7 +7878,8 @@ void RasterizerGLES2::canvas_begin() { canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; canvas_texscreen_used=false; uses_texpixel_size=false; - canvas_last_shader=RID(); + + canvas_last_material=NULL; } @@ -8364,6 +8369,476 @@ void RasterizerGLES2::canvas_set_transform(const Matrix32& p_transform) { //canvas_transform = Variant(p_transform); } +RID RasterizerGLES2::canvas_light_occluder_create() { + + CanvasOccluder *co = memnew( CanvasOccluder ); + co->index_id=0; + co->vertex_id=0; + co->len=0; + + return canvas_occluder_owner.make_rid(co); +} + +void RasterizerGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const DVector<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()) { + + + + DVector<float> geometry; + DVector<uint16_t> indices; + int lc = p_lines.size(); + + geometry.resize(lc*6); + indices.resize(lc*3); + + DVector<float>::Write vw=geometry.write(); + DVector<uint16_t>::Write iw=indices.write(); + + + DVector<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_STATIC_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; + + } + + + +} + +RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) { + + CanvasLightShadow *cls = memnew( CanvasLightShadow ); + if (p_width>max_texture_size) + p_width=max_texture_size; + + cls->size=p_width; + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + // Create a render buffer + glGenRenderbuffers(1, &cls->rbo); + glBindRenderbuffer(GL_RENDERBUFFER, cls->rbo); + + // Create a texture for storing the depth + glGenTextures(1, &cls->depth); + glBindTexture(GL_TEXTURE_2D, cls->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Remove artifact on the edges of the shadowmap + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + cls->height=16; + + //print_line("ERROR? "+itos(glGetError())); + if ( read_depth_supported ) { + + // We'll use a depth texture to store the depths in the shadow map + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + +#ifdef GLEW_ENABLED + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + + // Attach the depth texture to FBO depth attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, cls->depth, 0); + +#ifdef GLEW_ENABLED + glDrawBuffer(GL_NONE); +#endif + } else { + // We'll use a RGBA texture into which we pack the depth info + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + // Attach the RGBA texture to FBO color attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, cls->depth, 0); + + // Allocate 16-bit depth buffer + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); + + // Attach the render buffer as depth buffer - will be ignored + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, cls->rbo); + + + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); +#ifdef GLEW_ENABLED + if (read_depth_supported) { + glDrawBuffer(GL_BACK); + } +#endif + glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer); + DEBUG_TEST_ERROR("2D Shadow Buffer Init"); + ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() ); + +#ifdef GLEW_ENABLED + if (read_depth_supported) { + glDrawBuffer(GL_BACK); + } +#endif + + return canvas_light_shadow_owner.make_rid(cls); +} + +void RasterizerGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache) { + + CanvasLightShadow *cls = 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); + + if (!use_rgba_shadowmaps) + glColorMask(0, 0, 0, 0); + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + canvas_shadow_shader.bind(); + + const int vp_height = 10; + + 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 near = p_near; + real_t far = p_far; + real_t aspect = 1.0; + + real_t ymax = near * 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, near, far ); + } + + Vector3 cam_target=Matrix3(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()); + + //print_line("near: "+rtos(p_near)); + //print_line("far: "+rtos(p_far)); + //projection.set_perspective(60,size/float(vp_height),p_near,p_far); + + // CameraMatrix light_mat = projection * CameraMatrix(camera); + + canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX,projection); + canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX,light); + + if (i==0) + *p_xform_cache=projection; + + glViewport(0, (cls->height/4)*i, cls->size,cls->height/4); + + CanvasLightOccluderInstance *instance=p_occluders; + + while(instance) { + + CanvasOccluder *cc = canvas_occluder_owner.get(instance->polygon_buffer); + if (!cc || cc->len==0 || !(p_light_mask&instance->light_mask)) { + + instance=instance->next; + continue; + } + + 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; + } + } +/* + if (i==0) { + for(int i=0;i<cc->lines.size();i++) { + Vector2 p = instance->xform_cache.xform(cc->lines.get(i)); + Plane pp(Vector3(p.x,p.y,0),1); + pp.normal = light.xform(pp.normal); + pp = projection.xform4(pp); + print_line(itos(i)+": "+pp.normal/pp.d); + //pp=light_mat.xform4(pp); + //print_line(itos(i)+": "+pp.normal/pp.d); + } + } +*/ + glBindBuffer(GL_ARRAY_BUFFER,cc->vertex_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,cc->index_id); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); + glDrawElements(GL_TRIANGLES,cc->len*3,GL_UNSIGNED_SHORT,0); + + + instance=instance->next; + } + + + } + + glDisableVertexAttribArray(VS::ARRAY_VERTEX); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + if (shadow_filter==SHADOW_FILTER_ESM) { + //blur the buffer +#if 0 + //this is ignord, it did not make any difference.. + if (read_depth_supported) { + glDepthFunc(GL_ALWAYS); + } else { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + } + glDisable(GL_CULL_FACE); + glViewport(0, 0, cls->size,cls->height); + + int passes=1; + CanvasLightShadow *blur = canvas_light_shadow_owner.get(canvas_shadow_blur); + + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,true); + copy_shader.bind(); + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,1); + copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1); + glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); + + for(int i=0;i<passes;i++) { + + glBindFramebuffer(GL_FRAMEBUFFER, blur->fbo); + glActiveTexture(GL_TEXTURE0); + + if (read_depth_supported) + glBindTexture(GL_TEXTURE_2D,cls->depth); + else + glBindTexture(GL_TEXTURE_2D,cls->rgba); + + + { + Vector2 src_sb_uv[4]={ + Vector2( 0, 1), + Vector2( 1, 1), + Vector2( 1, 0), + Vector2( 0, 0) + }; + static const Vector2 dst_pos[4]={ + Vector2(-1, 1), + Vector2( 1, 1), + Vector2( 1,-1), + Vector2(-1,-1) + }; + + + + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/cls->size); + _draw_gui_primitive(4,dst_pos,NULL,src_sb_uv); + } + + glActiveTexture(GL_TEXTURE0); + if (read_depth_supported) + glBindTexture(GL_TEXTURE_2D,blur->depth); + else + glBindTexture(GL_TEXTURE_2D,blur->rgba); + + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + { + float hlimit = float(cls->size) / blur->size; + //hlimit*=2.0; + Vector2 src_sb_uv[4]={ + Vector2( 0, 1), + Vector2( hlimit, 1), + Vector2( hlimit, 0), + Vector2( 0, 0) + }; + static const Vector2 dst_pos[4]={ + Vector2(-1, 1), + Vector2( 1, 1), + Vector2( 1,-1), + Vector2(-1,-1) + }; + + + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/blur->size); + _draw_gui_primitive(4,dst_pos,NULL,src_sb_uv); + } + + } + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false); + glDepthFunc(GL_LEQUAL); +#endif + } + + glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); + glColorMask(1, 1, 1, 1); + + + +} + + +void RasterizerGLES2::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow) { + + CanvasLight* light=p_lights_with_shadow; + + canvas_begin(); //reset + + int h = 10; + int w = viewport.width; + int ofs = h; + while(light) { + + if (light->shadow_buffer.is_valid()) { + + CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer); + if (sb) { + glActiveTexture(GL_TEXTURE0); + if (read_depth_supported) + glBindTexture(GL_TEXTURE_2D,sb->depth); + else + glBindTexture(GL_TEXTURE_2D,sb->rgba); + _draw_textured_quad(Rect2(h,ofs,w-h*2,h),Rect2(0,0,sb->size,10),Size2(sb->size,10),false,false); + ofs+=h*2; + + } + } + + light=light->shadows_next_ptr; + } + +} + void RasterizerGLES2::_canvas_normal_set_flip(const Vector2& p_flip) { if (p_flip==normal_flip) @@ -8508,14 +8983,14 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem } -void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItem *shader_owner,Shader* shader) { +void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) { if (canvas_shader.bind()) rebind_texpixel_size=true; - if (shader_owner->shader_version!=shader->version) { + if (material->shader_version!=shader->version) { //todo optimize uniforms - shader_owner->shader_version=shader->version; + material->shader_version=shader->version; } if (shader->has_texscreen && framebuffer.active) { @@ -8558,14 +9033,14 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItem *shader_owner, } -void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* shader) { +void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* shader) { //this can be optimized.. int tex_id=1; int idx=0; for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) { - Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key()); + Map<StringName,Variant>::Element *F=material->shader_param.find(E->key()); if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) { @@ -8623,6 +9098,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_modulate=p_modulate; canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); + bool reset_modulate=false; + while(p_item_list) { CanvasItem *ci=p_item_list; @@ -8632,12 +9109,13 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const draw_viewport_func(ci->vp_render->owner,ci->vp_render->udata,ci->vp_render->rect); } memdelete(ci->vp_render); - ci->vp_render=NULL; - canvas_last_shader=RID(); + ci->vp_render=NULL; + canvas_last_material=NULL; canvas_use_modulate=p_modulate!=Color(1,1,1,1); canvas_modulate=p_modulate; canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); rebind_shader=true; + reset_modulate=true; } @@ -8660,13 +9138,14 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const //begin rect - CanvasItem *shader_owner = ci->shader_owner?ci->shader_owner:ci; + CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci; + CanvasItemMaterial *material = material_owner->material; - if (shader_owner->shader!=canvas_last_shader || rebind_shader) { + if (material!=canvas_last_material || rebind_shader) { Shader *shader = NULL; - if (shader_owner->shader.is_valid()) { - shader = this->shader_owner.get(shader_owner->shader); + if (material && material->shader.is_valid()) { + shader = shader_owner.get(material->shader); if (shader && !shader->valid) { shader=NULL; } @@ -8676,7 +9155,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const if (shader) { canvas_shader.set_custom_shader(shader->custom_code_id); - _canvas_item_setup_shader_params(shader_owner,shader); + _canvas_item_setup_shader_params(material,shader); } else { shader_cache=NULL; canvas_shader.set_custom_shader(0); @@ -8688,16 +9167,26 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform); if (canvas_use_modulate) - canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); - canvas_last_shader=shader_owner->shader; + reset_modulate=true; + canvas_last_material=material; rebind_shader=false; } - if (shader_cache) { + if (material && shader_cache) { + + _canvas_item_setup_shader_uniforms(material,shader_cache); + } - _canvas_item_setup_shader_uniforms(shader_owner,shader_cache); + if (material && material->unshaded) { + canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1)); + reset_modulate=true; + } else if (reset_modulate) { + canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); + reset_modulate=false; } + + canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); @@ -8747,7 +9236,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const _canvas_item_render_commands<false>(ci,current_clip,reclip); - if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light) { + if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && (!material || !material->unshaded)) { CanvasLight *light = p_light; bool light_used=false; @@ -8785,13 +9274,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const normal_flip=Vector2(1,1); } + canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,light->shadow_buffer.is_valid()); + bool light_rebind = canvas_shader.bind(); if (light_rebind) { - if (shader_owner && shader_cache) { - _canvas_item_setup_shader_params(shader_owner,shader_cache); - _canvas_item_setup_shader_uniforms(shader_owner,shader_cache); + if (material && shader_cache) { + _canvas_item_setup_shader_params(material,shader_cache); + _canvas_item_setup_shader_uniforms(material,shader_cache); } canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); @@ -8800,6 +9291,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const if (canvas_use_modulate) canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,Vector2(1,1)); + canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE,1.0/light->shadow_buffer_size); } @@ -8808,6 +9300,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos); canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,light->color); canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height); + if (light->shadow_buffer.is_valid()) { + + CanvasLightShadow *cls = canvas_light_shadow_owner.get(light->shadow_buffer); + glActiveTexture(GL_TEXTURE0+max_texture_units-3); + if (read_depth_supported) + glBindTexture(GL_TEXTURE_2D,cls->depth); + else + glBindTexture(GL_TEXTURE_2D,cls->rgba); + + canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_TEXTURE,max_texture_units-3); + canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache); + canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse()); + canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); + + } + + glActiveTexture(GL_TEXTURE0+max_texture_units-2); canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_TEXTURE,max_texture_units-2); Texture *t = texture_owner.get(light->texture); @@ -8831,12 +9340,13 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,false); canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); + canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,false); canvas_shader.bind(); - if (shader_owner && shader_cache) { - _canvas_item_setup_shader_params(shader_owner,shader_cache); - _canvas_item_setup_shader_uniforms(shader_owner,shader_cache); + if (material && shader_cache) { + _canvas_item_setup_shader_params(material,shader_cache); + _canvas_item_setup_shader_uniforms(material,shader_cache); } canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); @@ -9067,6 +9577,11 @@ bool RasterizerGLES2::is_environment(const RID& p_rid) const { } bool RasterizerGLES2::is_shader(const RID& p_rid) const { + return shader_owner.owns(p_rid); +} + +bool RasterizerGLES2::is_canvas_light_occluder(const RID& p_rid) const { + return false; } @@ -9244,7 +9759,30 @@ void RasterizerGLES2::free(const RID& p_rid) { glDeleteTextures(1,&sampled_light->texture); sampled_light_owner.free(p_rid); memdelete( sampled_light ); + } 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); + + canvas_occluder_owner.free(p_rid); + memdelete(co); + + } 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->rbo); + glDeleteTextures(1,&cls->depth); + if (!read_depth_supported) { + glDeleteTextures(1,&cls->rgba); + } + + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); }; } @@ -9779,10 +10317,12 @@ void RasterizerGLES2::init() { material_shader.init(); canvas_shader.init(); copy_shader.init(); + canvas_shadow_shader.init(); #ifdef GLEW_ENABLED material_shader.set_conditional(MaterialShaderGLES2::USE_GLES_OVER_GL,true); canvas_shader.set_conditional(CanvasShaderGLES2::USE_GLES_OVER_GL,true); + canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_GLES_OVER_GL,true); copy_shader.set_conditional(CopyShaderGLES2::USE_GLES_OVER_GL,true); #endif @@ -9923,8 +10463,11 @@ void RasterizerGLES2::init() { glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units); + glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_texture_size); //read_depth_supported=false; + canvas_shadow_blur = canvas_light_shadow_buffer_create(max_texture_size); + { //shadowmaps OS::VideoMode vm=OS::get_singleton()->get_video_mode(); @@ -9946,6 +10489,7 @@ void RasterizerGLES2::init() { //material_shader material_shader.set_conditional(MaterialShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps); + canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps); } @@ -9978,7 +10522,7 @@ void RasterizerGLES2::init() { void RasterizerGLES2::finish() { - + free(canvas_shadow_blur); } int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) { diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 173ca14180..f09714f50c 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -51,6 +51,7 @@ #include "drivers/gles2/shaders/material.glsl.h" #include "drivers/gles2/shaders/canvas.glsl.h" +#include "drivers/gles2/shaders/canvas_shadow.glsl.h" #include "drivers/gles2/shaders/blur.glsl.h" #include "drivers/gles2/shaders/copy.glsl.h" #include "drivers/gles2/shader_compiler_gles2.h" @@ -816,6 +817,7 @@ class RasterizerGLES2 : public Rasterizer { bool current_depth_mask; VS::MaterialBlendMode current_blend_mode; bool use_fast_texture_filter; + int max_texture_size; bool fragment_lighting; RID shadow_material; @@ -1160,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer { void _process_glow_and_bloom(); //void _update_blur_buffer(); + /*********/ /* FRAME */ /*********/ @@ -1178,6 +1181,45 @@ class RasterizerGLES2 : public Rasterizer { } _rinfo; + /*******************/ + /* CANVAS OCCLUDER */ + /*******************/ + + + struct CanvasOccluder { + + GLuint vertex_id; // 0 means, unconfigured + GLuint index_id; // 0 means, unconfigured + DVector<Vector2> lines; + int len; + }; + + RID_Owner<CanvasOccluder> canvas_occluder_owner; + + /***********************/ + /* CANVAS LIGHT SHADOW */ + /***********************/ + + + struct CanvasLightShadow { + + int size; + int height; + GLuint fbo; + GLuint rbo; + GLuint depth; + GLuint rgba; //for older devices + + GLuint blur; + + }; + + RID_Owner<CanvasLightShadow> canvas_light_shadow_owner; + + RID canvas_shadow_blur; + + /* ETC */ + RenderTarget *current_rt; bool current_rt_transparent; bool current_rt_vflip; @@ -1192,7 +1234,7 @@ class RasterizerGLES2 : public Rasterizer { bool uses_texpixel_size; bool rebind_texpixel_size; Transform canvas_transform; - RID canvas_last_shader; + CanvasItemMaterial *canvas_last_material; bool canvas_texscreen_used; Vector2 normal_flip; _FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2& p_flip); @@ -1227,10 +1269,12 @@ class RasterizerGLES2 : public Rasterizer { VS::ScenarioDebugMode current_debug; RID overdraw_material; + mutable MaterialShaderGLES2 material_shader; mutable CanvasShaderGLES2 canvas_shader; BlurShaderGLES2 blur_shader; CopyShaderGLES2 copy_shader; + mutable CanvasShadowShaderGLES2 canvas_shadow_shader; mutable ShaderCompilerGLES2 shader_precompiler; @@ -1254,8 +1298,8 @@ class RasterizerGLES2 : public Rasterizer { template<bool use_normalmap> _FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip); - _FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItem *shader_owner,Shader* p_shader); - _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItem *shader_owner,Shader* p_shader); + _FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* p_shader); + _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* p_shader); public: /* TEXTURE API */ @@ -1572,7 +1616,17 @@ public: virtual void canvas_set_transform(const Matrix32& p_transform); virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light); + virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow); + /* CANVAS LIGHT SHADOW */ + + //buffer + virtual RID canvas_light_shadow_buffer_create(int p_width); + virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache); + + //occluder + virtual RID canvas_light_occluder_create(); + virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines); /* ENVIRONMENT */ @@ -1611,6 +1665,8 @@ public: virtual bool is_environment(const RID& p_rid) const; virtual bool is_shader(const RID& p_rid) const; + virtual bool is_canvas_light_occluder(const RID& p_rid) const; + virtual void free(const RID& p_rid); virtual void init(); diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index c665cf9036..9679223b16 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -3,6 +3,7 @@ Import('env') if env['BUILDERS'].has_key('GLSL120GLES'): env.GLSL120GLES('material.glsl'); env.GLSL120GLES('canvas.glsl'); + env.GLSL120GLES('canvas_shadow.glsl'); env.GLSL120GLES('blur.glsl'); env.GLSL120GLES('copy.glsl'); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 227a8b7bdd..9022f30d7f 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -34,6 +34,10 @@ varying vec4 local_rot; uniform vec2 normal_flip; #endif +#ifdef USE_SHADOWS +highp varying vec2 pos; +#endif + #endif #if defined(ENABLE_VAR1_INTERP) @@ -63,6 +67,8 @@ VERTEX_SHADER_CODE outvec = modelview_matrix * outvec; #endif + + #ifdef USE_PIXEL_SNAP outvec.xy=floor(outvec.xy+0.5); @@ -75,6 +81,9 @@ VERTEX_SHADER_CODE light_uv_interp.xy = (light_matrix * outvec).xy; light_uv_interp.zw = outvec.xy-light_pos; +#ifdef USE_SHADOWS + pos=outvec.xy; +#endif #if defined(NORMAL_USED) local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy )*normal_flip.x; @@ -154,6 +163,15 @@ varying vec4 local_rot; uniform sampler2D shadow_texture; uniform float shadow_attenuation; +uniform highp mat4 shadow_matrix; +uniform highp mat4 light_local_matrix; +highp varying vec2 pos; +uniform float shadowpixel_size; + +#ifdef SHADOW_ESM +uniform float shadow_esm_multiplier; +#endif + #endif #endif @@ -173,10 +191,6 @@ void main() { vec3 normal = vec3(0,0,1); #endif -#ifdef USE_MODULATE - - color*=modulate; -#endif color *= texture2D( texture, uv_interp ); #if defined(ENABLE_SCREEN_UV) @@ -191,6 +205,12 @@ FRAGMENT_SHADER_CODE color = vec4(vec3(enc32),1.0); #endif +#ifdef USE_MODULATE + + color*=modulate; +#endif + + #ifdef USE_LIGHTING #if defined(NORMAL_USED) @@ -201,13 +221,96 @@ FRAGMENT_SHADER_CODE vec4 light = texture2D(light_texture,light_uv_interp.xy) * light_color; #ifdef USE_SHADOWS - //this might not be that great on mobile? - float light_dist = length(light_texture.zw); - float light_angle = atan2(light_texture.x,light_texture.z) + 1.0 * 0.5; - float shadow_dist = texture2D(shadow_texture,vec2(light_angle,0)); - if (light_dist>shadow_dist) { - light*=shadow_attenuation; + + + vec2 lpos = (light_local_matrix * vec4(pos,0.0,1.0)).xy; + float angle_to_light = -atan(lpos.x,lpos.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 = lpos; + sh=0+(1.0/8.0); + } else if (abs_angle>135.0*PI/180.0) { + point = -lpos; + sh = 0.5+(1.0/8.0); + } else if (angle_to_light>0) { + + point = vec2(lpos.y,-lpos.x); + sh = 0.25+(1.0/8.0); + } else { + + point = vec2(-lpos.y,lpos.x); + sh = 0.75+(1.0/8.0); + + } + + + 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; + + float shadow_attenuation; + +#ifdef SHADOW_PCF5 + + shadow_attenuation=0.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0; + shadow_attenuation/=5.0; + +#endif + +#ifdef SHADOW_PCF13 + + shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*3.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*4.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*5.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*6.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*3.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*4.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*5.0,sh)).z<sz?0.0:1.0; + shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*6.0,sh)).z<sz?0.0:1.0; + shadow_attenuation/=13.0; + +#endif + +#ifdef SHADOW_ESM + + + { + float unnormalized = su/shadowpixel_size; + float fractional = fract(unnormalized); + unnormalized = floor(unnormalized); + float zc = texture2D(shadow_texture,vec2((unnormalized-0.5)*shadowpixel_size,sh)).z; + float zn = texture2D(shadow_texture,vec2((unnormalized+0.5)*shadowpixel_size,sh)).z; + float z = mix(zc,zn,fractional); + shadow_attenuation=clamp(exp(shadow_esm_multiplier* ( z - sz )),0.0,1.0); } + +#endif + +#if !defined(SHADOW_PCF5) && !defined(SHADOW_PCF13) && !defined(SHADOW_ESM) + + shadow_attenuation = texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0; + +#endif + + light*=shadow_attenuation; //use shadows #endif diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..40cf321dce --- /dev/null +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -0,0 +1,62 @@ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision mediump float; +precision mediump int; +#endif + +uniform highp mat4 projection_matrix; +uniform highp mat4 light_matrix; +uniform highp mat4 world_matrix; + +attribute highp vec3 vertex; // attrib:0 + +#ifndef USE_DEPTH_SHADOWS + +varying vec4 position_interp; + +#endif + + +void main() { + + gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0))); + +#ifndef USE_DEPTH_SHADOWS + position_interp = gl_Position; +#endif + +} + +[fragment] + +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision mediump float; +precision mediump int; +#endif + +#ifndef USE_DEPTH_SHADOWS + +varying vec4 position_interp; + +#endif + +void main() { + +#ifdef USE_DEPTH_SHADOWS + +#else + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias; + 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); + gl_FragColor = comp; +#endif + +} + diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index a6073cbb29..e24685432c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -28,14 +28,18 @@ /*************************************************************************/ #ifdef WINDOWS_ENABLED +#include <Windows.h> +#include "Shlwapi.h" #include "file_access_windows.h" + #include <sys/types.h> #include <sys/stat.h> #include <wchar.h> #include <tchar.h> #include "print_string.h" + #ifdef _MSC_VER #define S_ISREG(m) ((m)&_S_IFREG) #endif @@ -111,10 +115,20 @@ void FileAccessWindows::close() { //unlink(save_path.utf8().get_data()); //print_line("renaming.."); - _wunlink(save_path.c_str()); //unlink if exists - int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); + //_wunlink(save_path.c_str()); //unlink if exists + //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); + + + bool rename_error; + if (!PathFileExistsW(save_path.c_str())) { + //creating new file + rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str())!=0; + } else { + //atomic replace for existing file + rename_error = !ReplaceFileW(save_path.c_str(), (save_path+".tmp").c_str(), NULL, 2|4, NULL, NULL); + } save_path=""; - ERR_FAIL_COND( rename_error != 0); + ERR_FAIL_COND( rename_error ); } diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 0aa115ffbc..d3a9abf4b7 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -2696,7 +2696,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour } file->store_string(source); - + if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } file->close(); memdelete(file); return OK; diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index 857d1a4a54..4c0c095e10 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -396,6 +396,14 @@ void AudioDriverOpenSL::finish(){ void AudioDriverOpenSL::set_pause(bool p_pause) { pause=p_pause; + + if (active) { + if (pause) { + (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); + } else { + (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); + } + } } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 6f1c03b593..6b91c01dfc 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -151,7 +151,7 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_ sample_manager = memnew( SampleManagerMallocSW ); audio_server = memnew( AudioServerSW(sample_manager) ); - audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false); + audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,true); audio_server->init(); spatial_sound_server = memnew( SpatialSoundServerSW ); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 16dd695c59..62bab00f7b 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -115,7 +115,7 @@ def configure(env): env.Append(CCFLAGS=['/DGLES2_ENABLED'])
env.Append(CCFLAGS=['/DGLEW_ENABLED'])
- LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32']
+ LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32']
env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
@@ -229,7 +229,7 @@ def configure(env): env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
- env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
+ env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
if (env["bits"]=="32" and env["mingw64_for_32"]!="yes"):
# env.Append(LIBS=['gcc_s'])
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 223adaf9bb..4a1842100a 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -36,6 +36,192 @@ #include "scene/resources/texture.h" #include "scene/resources/style_box.h" + +bool CanvasItemMaterial::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name==SceneStringNames::get_singleton()->shader_shader) { + set_shader(p_value); + return true; + } else if (p_name==SceneStringNames::get_singleton()->shader_unshaded) { + set_unshaded(p_value); + print_line("set unshaded"); + return true; + } else { + + if (shader.is_valid()) { + + + StringName pr = shader->remap_param(p_name); + if (!pr) { + String n = p_name; + if (n.find("param/")==0) { //backwards compatibility + pr = n.substr(6,n.length()); + } + } + if (pr) { + VisualServer::get_singleton()->canvas_item_material_set_shader_param(material,pr,p_value); + return true; + } + } + } + + return false; +} + +bool CanvasItemMaterial::_get(const StringName& p_name,Variant &r_ret) const { + + + if (p_name==SceneStringNames::get_singleton()->shader_shader) { + + r_ret=get_shader(); + return true; + } else if (p_name==SceneStringNames::get_singleton()->shader_unshaded) { + + + r_ret=unshaded; + return true; + } else { + + if (shader.is_valid()) { + + StringName pr = shader->remap_param(p_name); + if (pr) { + r_ret=VisualServer::get_singleton()->canvas_item_material_get_shader_param(material,pr); + return true; + } + } + + } + + + return false; +} + + +void CanvasItemMaterial::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"CanvasItemShader,CanvasItemShaderGraph" ) ); + p_list->push_back( PropertyInfo( Variant::BOOL, "shader/unshaded") ); + + if (!shader.is_null()) { + + shader->get_param_list(p_list); + } + +} + +void CanvasItemMaterial::set_shader(const Ref<Shader>& p_shader) { + + ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM); +#ifdef TOOLS_ENABLED + + if (shader.is_valid()) { + shader->disconnect("changed",this,"_shader_changed"); + } +#endif + shader=p_shader; + +#ifdef TOOLS_ENABLED + + if (shader.is_valid()) { + shader->connect("changed",this,"_shader_changed"); + } +#endif + + RID rid; + if (shader.is_valid()) + rid=shader->get_rid(); + + VS::get_singleton()->canvas_item_material_set_shader(material,rid); + _change_notify(); //properties for shader exposed + emit_changed(); +} + +Ref<Shader> CanvasItemMaterial::get_shader() const{ + + return shader; +} + +void CanvasItemMaterial::set_shader_param(const StringName& p_param,const Variant& p_value){ + + VS::get_singleton()->canvas_item_material_set_shader_param(material,p_param,p_value); +} + +Variant CanvasItemMaterial::get_shader_param(const StringName& p_param) const{ + + return VS::get_singleton()->canvas_item_material_get_shader_param(material,p_param); +} + +void CanvasItemMaterial::_shader_changed() { + + +} + +RID CanvasItemMaterial::get_rid() const { + + return material; +} + +void CanvasItemMaterial::set_unshaded(bool p_unshaded) { + + unshaded=p_unshaded; + VS::get_singleton()->canvas_item_material_set_unshaded(material,p_unshaded); +} + +bool CanvasItemMaterial::is_unshaded() const{ + + return unshaded; +} + +void CanvasItemMaterial::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"),&CanvasItemMaterial::set_shader); + ObjectTypeDB::bind_method(_MD("get_shader:Shader"),&CanvasItemMaterial::get_shader); + ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItemMaterial::set_shader_param); + ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItemMaterial::get_shader_param); + ObjectTypeDB::bind_method(_MD("set_unshaded","unshaded"),&CanvasItemMaterial::set_unshaded); + ObjectTypeDB::bind_method(_MD("is_unshaded"),&CanvasItemMaterial::is_unshaded); + +} + +void CanvasItemMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const { + + String f = p_function.operator String(); + if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) { + + if (shader.is_valid()) { + List<PropertyInfo> pl; + shader->get_param_list(&pl); + for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { + r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\""); + } + } + } + Resource::get_argument_options(p_function,p_idx,r_options); +} + +CanvasItemMaterial::CanvasItemMaterial() { + + material=VS::get_singleton()->canvas_item_material_create(); + unshaded=false; +} + +CanvasItemMaterial::~CanvasItemMaterial(){ + + VS::get_singleton()->free(material); +} + + + + + + + + +/////////////////////////////////////////////////////////////////// + + + bool CanvasItem::is_visible() const { if (!is_inside_tree()) @@ -730,111 +916,35 @@ bool CanvasItem::is_draw_behind_parent_enabled() const{ return behind; } -void CanvasItem::set_shader(const Ref<Shader>& p_shader) { - - ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM); - -#ifdef TOOLS_ENABLED - - if (shader.is_valid()) { - shader->disconnect("changed",this,"_shader_changed"); - } -#endif - shader=p_shader; - -#ifdef TOOLS_ENABLED +void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) { - if (shader.is_valid()) { - shader->connect("changed",this,"_shader_changed"); - } -#endif + material=p_material; RID rid; - if (shader.is_valid()) - rid=shader->get_rid(); - VS::get_singleton()->canvas_item_set_shader(canvas_item,rid); - _change_notify(); //properties for shader exposed -} - -void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) { - - use_parent_shader=p_use_parent_shader; - VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_use_parent_shader); + if (material.is_valid()) + rid=material->get_rid(); + VS::get_singleton()->canvas_item_set_material(canvas_item,rid); + _change_notify(); //properties for material exposed } -bool CanvasItem::get_use_parent_shader() const{ +void CanvasItem::set_use_parent_material(bool p_use_parent_material) { - return use_parent_shader; + use_parent_material=p_use_parent_material; + VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item,p_use_parent_material); } -Ref<Shader> CanvasItem::get_shader() const{ +bool CanvasItem::get_use_parent_material() const{ - return shader; + return use_parent_material; } -void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) { +Ref<CanvasItemMaterial> CanvasItem::get_material() const{ - VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value); + return material; } -Variant CanvasItem::get_shader_param(const StringName& p_param) const { - - return VS::get_singleton()->canvas_item_get_shader_param(canvas_item,p_param); -} - -bool CanvasItem::_set(const StringName& p_name, const Variant& p_value) { - - if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); - if (pr) { - set_shader_param(pr,p_value); - return true; - } - } - return false; -} -bool CanvasItem::_get(const StringName& p_name,Variant &r_ret) const{ - if (shader.is_valid()) { - StringName pr = shader->remap_param(p_name); - if (pr) { - r_ret=get_shader_param(pr); - return true; - } - } - return false; - -} -void CanvasItem::_get_property_list( List<PropertyInfo> *p_list) const{ - - if (shader.is_valid()) { - shader->get_param_list(p_list); - } -} - -#ifdef TOOLS_ENABLED -void CanvasItem::_shader_changed() { - - _change_notify(); -} -#endif - -void CanvasItem::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const { - - if (p_idx==0 && shader.is_valid() && (p_function.operator String()=="get_shader_param" || p_function.operator String()=="set_shader_param")) { - - List<PropertyInfo> pl; - shader->get_param_list(&pl); - for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { - r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\""); - } - - return; - } - - Node::get_argument_options(p_function,p_idx,r_options); -} void CanvasItem::_bind_methods() { @@ -880,9 +990,6 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("_set_on_top","on_top"),&CanvasItem::_set_on_top); ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_on_top); -#ifdef TOOLS_ENABLED - ObjectTypeDB::bind_method(_MD("_shader_changed"),&CanvasItem::_shader_changed); -#endif //ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0)); @@ -901,20 +1008,18 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform); ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform); + ObjectTypeDB::bind_method(_MD("get_global_transform_with_canvas"),&CanvasItem::get_global_transform_with_canvas); ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform); ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect); ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas); ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); //ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport); - ObjectTypeDB::bind_method(_MD("set_shader","shader"),&CanvasItem::set_shader); - ObjectTypeDB::bind_method(_MD("get_shader"),&CanvasItem::get_shader); - ObjectTypeDB::bind_method(_MD("set_use_parent_shader","enable"),&CanvasItem::set_use_parent_shader); - ObjectTypeDB::bind_method(_MD("get_use_parent_shader"),&CanvasItem::get_use_parent_shader); - - ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItem::set_shader_param); - ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItem::get_shader_param); + ObjectTypeDB::bind_method(_MD("set_material","material:CanvasItemMaterial"),&CanvasItem::set_material); + ObjectTypeDB::bind_method(_MD("get_material:CanvasItemMaterial"),&CanvasItem::get_material); + ObjectTypeDB::bind_method(_MD("set_use_parent_material","enable"),&CanvasItem::set_use_parent_material); + ObjectTypeDB::bind_method(_MD("get_use_parent_material"),&CanvasItem::get_use_parent_material); BIND_VMETHOD(MethodInfo("_draw")); @@ -926,8 +1031,8 @@ void CanvasItem::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") ); ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") ); - ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"shader/shader",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"), _SCS("set_shader"),_SCS("get_shader") ); - ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") ); //exporting these two things doesn't really make much sense i think //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") ); //ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled")); @@ -1004,7 +1109,7 @@ CanvasItem::CanvasItem() : xform_change(this) { block_transform_notify=false; // viewport=NULL; canvas_layer=NULL; - use_parent_shader=false; + use_parent_material=false; global_invalid=true; light_mask=1; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 2441d205ce..0c7be261ab 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -40,6 +40,41 @@ class Font; class StyleBox; +class CanvasItemMaterial : public Resource{ + + OBJ_TYPE(CanvasItemMaterial,Resource); + RID material; + Ref<Shader> shader; + bool unshaded; + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + + void _shader_changed(); + static void _bind_methods(); + + void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; + +public: + + void set_shader(const Ref<Shader>& p_shader); + Ref<Shader> get_shader() const; + + void set_shader_param(const StringName& p_param,const Variant& p_value); + Variant get_shader_param(const StringName& p_param) const; + + void set_unshaded(bool p_unshaded); + bool is_unshaded() const; + + virtual RID get_rid() const; + CanvasItemMaterial(); + ~CanvasItemMaterial(); +}; + + class CanvasItem : public Node { OBJ_TYPE( CanvasItem, Node ); @@ -81,9 +116,9 @@ private: bool drawing; bool block_transform_notify; bool behind; - bool use_parent_shader; + bool use_parent_material; - Ref<Shader> shader; + Ref<CanvasItemMaterial> material; mutable Matrix32 global_transform; mutable bool global_invalid; @@ -104,9 +139,6 @@ private: void _queue_sort_children(); void _sort_children(); -#ifdef TOOLS_ENABLED - void _shader_changed(); -#endif void _notify_transform(CanvasItem *p_node); void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } @@ -114,11 +146,6 @@ private: protected: - bool _set(const StringName& p_name, const Variant& p_value); - bool _get(const StringName& p_name,Variant &r_ret) const; - void _get_property_list( List<PropertyInfo> *p_list) const; - - _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } void item_rect_changed(); @@ -216,16 +243,12 @@ public: RID get_canvas() const; Ref<World2D> get_world_2d() const; - void set_shader(const Ref<Shader>& p_shader); - Ref<Shader> get_shader() const; + void set_material(const Ref<CanvasItemMaterial>& p_material); + Ref<CanvasItemMaterial> get_material() const; - void set_use_parent_shader(bool p_use_parent_shader); - bool get_use_parent_shader() const; + void set_use_parent_material(bool p_use_parent_material); + bool get_use_parent_material() const; - void set_shader_param(const StringName& p_param,const Variant& p_value); - Variant get_shader_param(const StringName& p_param) const; - - void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; CanvasItem(); ~CanvasItem(); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index cea8c06d3f..93be0c397f 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -170,6 +170,29 @@ bool Light2D::is_shadow_enabled() const { return shadow; } +void Light2D::set_shadow_buffer_size( int p_size ) { + + shadow_buffer_size=p_size; + VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light,shadow_buffer_size); +} + +int Light2D::get_shadow_buffer_size() const { + + return shadow_buffer_size; +} + +void Light2D::set_shadow_esm_multiplier( float p_multiplier) { + + shadow_esm_multiplier=p_multiplier; + VS::get_singleton()->canvas_light_set_shadow_esm_multiplier(canvas_light,p_multiplier); +} + +float Light2D::get_shadow_esm_multiplier() const{ + + return shadow_esm_multiplier; +} + + void Light2D::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { @@ -229,18 +252,26 @@ void Light2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled); ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled); + ObjectTypeDB::bind_method(_MD("set_shadow_buffer_size","size"),&Light2D::set_shadow_buffer_size); + ObjectTypeDB::bind_method(_MD("get_shadow_buffer_size"),&Light2D::get_shadow_buffer_size); + + ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier); + ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture_offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"height"),_SCS("set_height"),_SCS("get_height")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_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,"z_range_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")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"layer_range_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow_enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled")); + 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")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier")); } @@ -258,6 +289,8 @@ Light2D::Light2D() { layer_max=0; item_mask=1; subtract_mode=false; + shadow_buffer_size=2048; + shadow_esm_multiplier=80; } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index dbfd233d39..89f351c3cd 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -17,6 +17,8 @@ private: int layer_min; int layer_max; int item_mask; + int shadow_buffer_size; + float shadow_esm_multiplier; bool subtract_mode; Ref<Texture> texture; Vector2 texture_offset; @@ -68,6 +70,12 @@ public: void set_shadow_enabled( bool p_enabled); bool is_shadow_enabled() const; + void set_shadow_buffer_size( int p_size ); + int get_shadow_buffer_size() const; + + void set_shadow_esm_multiplier( float p_multiplier); + float get_shadow_esm_multiplier() const; + virtual Rect2 get_item_rect() const; Light2D(); diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp new file mode 100644 index 0000000000..186ea2e248 --- /dev/null +++ b/scene/2d/light_occluder_2d.cpp @@ -0,0 +1,201 @@ +#include "light_occluder_2d.h" + + +void OccluderPolygon2D::set_polygon(const DVector<Vector2>& p_polygon) { + + polygon=p_polygon; + VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,p_polygon,closed); + emit_changed(); +} + +DVector<Vector2> OccluderPolygon2D::get_polygon() const{ + + return polygon; +} + +void OccluderPolygon2D::set_closed(bool p_closed) { + + if (closed==p_closed) + return; + closed=p_closed; + VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed); + emit_changed(); +} + +bool OccluderPolygon2D::is_closed() const{ + + return closed; +} + +void OccluderPolygon2D::set_cull_mode(CullMode p_mode){ + + cull=p_mode; + VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon,VS::CanvasOccluderPolygonCullMode(p_mode)); +} + +OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const{ + + return cull; +} + + +RID OccluderPolygon2D::get_rid() const { + + return occ_polygon; +} + +void OccluderPolygon2D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_closed","closed"),&OccluderPolygon2D::set_closed); + ObjectTypeDB::bind_method(_MD("is_closed"),&OccluderPolygon2D::is_closed); + + ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&OccluderPolygon2D::set_cull_mode); + ObjectTypeDB::bind_method(_MD("get_cull_mode"),&OccluderPolygon2D::get_cull_mode); + + ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon); + ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon); + + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode")); + + BIND_CONSTANT(CULL_DISABLED); + BIND_CONSTANT(CULL_CLOCKWISE); + BIND_CONSTANT(CULL_COUNTER_CLOCKWISE); +} + + +OccluderPolygon2D::OccluderPolygon2D() { + + occ_polygon=VS::get_singleton()->canvas_occluder_polygon_create(); + closed=true; + cull=CULL_DISABLED; +} + +OccluderPolygon2D::~OccluderPolygon2D() { + + VS::get_singleton()->free(occ_polygon); +} + +#ifdef DEBUG_ENABLED +void LightOccluder2D::_poly_changed() { + + update(); +} +#endif + + +void LightOccluder2D::_notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_CANVAS) { + + VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas()); + VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform()); + + } + if (p_what==NOTIFICATION_TRANSFORM_CHANGED) { + + VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform()); + } + + if (p_what==NOTIFICATION_DRAW) { + + if (get_tree()->is_editor_hint()) { + + if (occluder_polygon.is_valid()) { + + DVector<Vector2> poly = occluder_polygon->get_polygon(); + + if (poly.size()) { + if (occluder_polygon->is_closed()) { + Vector<Color> color; + color.push_back(Color(0,0,0,0.6)); + draw_polygon(Variant(poly),color); + } else { + + int ps=poly.size(); + DVector<Vector2>::Read r = poly.read(); + for(int i=0;i<ps-1;i++) { + + draw_line(r[i],r[i+1],Color(0,0,0,0.6),3); + } + } + } + } + } + } + + + if (p_what==NOTIFICATION_EXIT_CANVAS) { + + VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,RID()); + } + + +} + +void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon) { + +#ifdef DEBUG_ENABLED + if (occluder_polygon.is_valid()) + occluder_polygon->disconnect("changed",this,"_poly_changed"); +#endif + occluder_polygon=p_polygon; + + if (occluder_polygon.is_valid()) + VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,occluder_polygon->get_rid()); + else + VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,RID()); + +#ifdef DEBUG_ENABLED + if (occluder_polygon.is_valid()) + occluder_polygon->connect("changed",this,"_poly_changed"); + update(); +#endif + +} + +Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const { + + return occluder_polygon; +} + +void LightOccluder2D::set_occluder_light_mask(int p_mask) { + + mask=p_mask; + VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder,mask); +} + +int LightOccluder2D::get_occluder_light_mask() const{ + + return mask; +} + +void LightOccluder2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_occluder_polygon","polygon:OccluderPolygon2D"),&LightOccluder2D::set_occluder_polygon); + ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"),&LightOccluder2D::get_occluder_polygon); + + ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&LightOccluder2D::set_occluder_light_mask); + ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&LightOccluder2D::get_occluder_light_mask); + +#ifdef DEBUG_ENABLED + ObjectTypeDB::bind_method("_poly_changed",&LightOccluder2D::_poly_changed); +#endif + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"),_SCS("set_occluder_polygon"),_SCS("get_occluder_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask")); +} + +LightOccluder2D::LightOccluder2D() { + + occluder=VS::get_singleton()->canvas_light_occluder_create(); + mask=1; +} + +LightOccluder2D::~LightOccluder2D() { + + VS::get_singleton()->free(occluder); +} + diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h new file mode 100644 index 0000000000..0343e3697e --- /dev/null +++ b/scene/2d/light_occluder_2d.h @@ -0,0 +1,73 @@ +#ifndef LIGHTOCCLUDER2D_H +#define LIGHTOCCLUDER2D_H + +#include "scene/2d/node_2d.h" + +class OccluderPolygon2D : public Resource { + + OBJ_TYPE(OccluderPolygon2D,Resource); +public: + + enum CullMode { + CULL_DISABLED, + CULL_CLOCKWISE, + CULL_COUNTER_CLOCKWISE + }; +private: + + + RID occ_polygon; + DVector<Vector2> polygon; + bool closed; + CullMode cull; + +protected: + + static void _bind_methods(); +public: + + void set_polygon(const DVector<Vector2>& p_polygon); + DVector<Vector2> get_polygon() const; + + void set_closed(bool p_closed); + bool is_closed() const; + + void set_cull_mode(CullMode p_mode); + CullMode get_cull_mode() const; + + virtual RID get_rid() const; + OccluderPolygon2D(); + ~OccluderPolygon2D(); + +}; + +VARIANT_ENUM_CAST(OccluderPolygon2D::CullMode); + +class LightOccluder2D : public Node2D { + OBJ_TYPE(LightOccluder2D,Node2D); + + RID occluder; + bool enabled; + int mask; + Ref<OccluderPolygon2D> occluder_polygon; + +#ifdef DEBUG_ENABLED + void _poly_changed(); +#endif + +protected: + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon); + Ref<OccluderPolygon2D> get_occluder_polygon() const; + + void set_occluder_light_mask(int p_mask); + int get_occluder_light_mask() const; + + LightOccluder2D(); + ~LightOccluder2D(); +}; + +#endif // LIGHTOCCLUDER2D_H diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 95eafa0df4..1109139180 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -152,11 +152,11 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const { case PROJECTION_PERSPECTIVE: { - p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_NOEDITOR) ); if (keep_aspect==KEEP_WIDTH) - p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) ); + p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) ); else - p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) ); + p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) ); } break; diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index a82c69e67f..45c7fa912c 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -310,6 +310,17 @@ int GeometryInstance::get_baked_light_texture_id() const{ return baked_light_texture_id; } +void GeometryInstance::set_extra_cull_margin(float p_margin) { + + ERR_FAIL_COND(p_margin<0); + extra_cull_margin=p_margin; + VS::get_singleton()->instance_set_extra_visibility_margin(get_instance(),extra_cull_margin); +} + +float GeometryInstance::get_extra_cull_margin() const{ + + return extra_cull_margin; +} void GeometryInstance::_bind_methods() { @@ -328,6 +339,9 @@ void GeometryInstance::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id); ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id); + ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin); + ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); + ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE); @@ -336,6 +350,7 @@ void GeometryInstance::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS); ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin")); ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "geometry/extra_cull_margin",PROPERTY_HINT_RANGE,"0,16384,0"), _SCS("set_extra_cull_margin"), _SCS("get_extra_cull_margin")); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index e9fefe1ba0..e08acbe9a2 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -108,6 +108,7 @@ private: void _find_baked_light(); BakedLightInstance *baked_light_instance; int baked_light_texture_id; + float extra_cull_margin; void _baked_light_changed(); void _update_visibility(); @@ -132,6 +133,9 @@ public: void set_baked_light_texture_id(int p_id); int get_baked_light_texture_id() const; + void set_extra_cull_margin(float p_margin); + float get_extra_cull_margin() const; + GeometryInstance(); }; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index ff525203bf..f90db42614 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -80,6 +80,7 @@ #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" #include "scene/2d/light_2d.h" +#include "scene/2d/light_occluder_2d.h" #include "scene/2d/canvas_item.h" #include "scene/2d/sprite.h" @@ -454,6 +455,7 @@ void register_scene_types() { //ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false); //ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false); + ObjectTypeDB::register_type<CanvasItemMaterial>(); ObjectTypeDB::register_virtual_type<CanvasItem>(); ObjectTypeDB::register_type<Node2D>(); ObjectTypeDB::register_type<Particles2D>(); @@ -476,6 +478,8 @@ void register_scene_types() { ObjectTypeDB::register_type<VisibilityEnabler2D>(); ObjectTypeDB::register_type<Polygon2D>(); ObjectTypeDB::register_type<Light2D>(); + ObjectTypeDB::register_type<LightOccluder2D>(); + ObjectTypeDB::register_type<OccluderPolygon2D>(); ObjectTypeDB::register_type<YSort>(); ObjectTypeDB::set_type_enabled("CollisionShape2D",false); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index af5e6d4165..c30ff0044e 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -41,6 +41,7 @@ SceneStringNames::SceneStringNames() { visibility_changed=StaticCString::create("visibility_changed"); input_event=StaticCString::create("input_event"); shader_shader=StaticCString::create("shader/shader"); + shader_unshaded=StaticCString::create("shader/unshaded"); enter_tree=StaticCString::create("enter_tree"); exit_tree=StaticCString::create("exit_tree"); item_rect_changed=StaticCString::create("item_rect_changed"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 14e5e83b8d..184cbe347b 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -56,6 +56,7 @@ public: StringName _input_event; StringName item_rect_changed; StringName shader_shader; + StringName shader_unshaded; StringName enter_tree; StringName exit_tree; StringName size_flags_changed; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 4c9d0491b1..62ab8b3c56 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -572,8 +572,8 @@ public: struct CanvasLight { + bool enabled; - bool shadow; Color color; Matrix32 xform; float height; @@ -586,21 +586,26 @@ public: RID texture; Vector2 texture_offset; RID canvas; + RID shadow_buffer; + int shadow_buffer_size; + float shadow_esm_mult; void *texture_cache; // implementation dependent Rect2 rect_cache; Matrix32 xform_cache; + float radius_cache; //used for shadow far plane + CameraMatrix shadow_matrix_cache; Matrix32 light_shader_xform; Vector2 light_shader_pos; + CanvasLight *shadows_next_ptr; CanvasLight *filter_next_ptr; CanvasLight *next_ptr; CanvasLight() { - enabled=true; - shadow=false; + enabled=true; color=Color(1,1,1); height=0; z_min=-1024; @@ -612,9 +617,24 @@ public: texture_cache=NULL; next_ptr=NULL; filter_next_ptr=NULL; + shadow_buffer_size=2048; + shadow_esm_mult=80; + } }; + struct CanvasItem; + + struct CanvasItemMaterial { + + RID shader; + Map<StringName,Variant> shader_param; + uint32_t shader_version; + Set<CanvasItem*> owners; + bool unshaded; + + CanvasItemMaterial() {unshaded=false; shader_version=0; } + }; struct CanvasItem { @@ -744,16 +764,14 @@ public: mutable bool rect_dirty; mutable Rect2 rect; CanvasItem*next; - RID shader; - Map<StringName,Variant> shader_param; - uint32_t shader_version; + CanvasItemMaterial* material; float final_opacity; Matrix32 final_transform; Rect2 final_clip_rect; CanvasItem* final_clip_owner; - CanvasItem* shader_owner; + CanvasItem* material_owner; ViewportRender *vp_render; Rect2 global_rect_cache; @@ -881,8 +899,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; shader_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; shader_version=0; shader_owner=NULL;} + 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; } virtual ~CanvasItem() { clear(); } }; @@ -905,7 +923,36 @@ public: virtual void canvas_set_transform(const Matrix32& p_transform)=0; virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light)=0; + virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow)=0; + /* LIGHT SHADOW MAPPING */ + + virtual RID canvas_light_occluder_create()=0; + virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0; + + + virtual RID canvas_light_shadow_buffer_create(int p_width)=0; + struct CanvasLightOccluderInstance { + + + bool enabled; + RID canvas; + RID polygon; + RID polygon_buffer; + Rect2 aabb_cache; + Matrix32 xform; + Matrix32 xform_cache; + int light_mask; + VS::CanvasOccluderPolygonCullMode cull_cache; + + CanvasLightOccluderInstance *next; + + CanvasLightOccluderInstance() { enabled=true; next=NULL; light_mask=1; cull_cache=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; } + }; + + + + virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache)=0; /* ENVIRONMENT */ @@ -945,6 +992,8 @@ public: virtual bool is_environment(const RID& p_rid) const=0; virtual bool is_shader(const RID& p_rid) const=0; + virtual bool is_canvas_light_occluder(const RID& p_rid) const=0; + virtual void free(const RID& p_rid)=0; virtual void init()=0; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index feb14d8a9d..3bcf0b8a3e 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -3765,55 +3765,32 @@ void VisualServerRaster::canvas_item_set_z_as_relative_to_parent(RID p_item, boo } -void VisualServerRaster::canvas_item_set_use_parent_shader(RID p_item, bool p_enable) { +void VisualServerRaster::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { VS_CHANGED; CanvasItem *canvas_item = canvas_item_owner.get( p_item ); ERR_FAIL_COND(!canvas_item); - canvas_item->use_parent_shader=p_enable; + canvas_item->use_parent_material=p_enable; } -void VisualServerRaster::canvas_item_set_shader(RID p_item, RID p_shader) { +void VisualServerRaster::canvas_item_set_material(RID p_item, RID p_material) { VS_CHANGED; CanvasItem *canvas_item = canvas_item_owner.get( p_item ); ERR_FAIL_COND(!canvas_item); - canvas_item->shader=p_shader; -} - -RID VisualServerRaster::canvas_item_get_shader(RID p_item) const{ - - CanvasItem *canvas_item = canvas_item_owner.get( p_item ); - ERR_FAIL_COND_V(!canvas_item,RID()); - return canvas_item->shader; -} + if (canvas_item->material) + canvas_item->material->owners.erase(canvas_item); -void VisualServerRaster::canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value){ + canvas_item->material=NULL; - VS_CHANGED; - CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); - ERR_FAIL_COND(!canvas_item); - if (p_value.get_type()==Variant::NIL) - canvas_item->shader_param.erase(p_param); - else - canvas_item->shader_param[p_param]=p_value; - -} -Variant VisualServerRaster::canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const{ - - CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); - ERR_FAIL_COND_V(!canvas_item,Variant()); - if (!canvas_item->shader_param.has(p_param)) { - ERR_FAIL_COND_V(!canvas_item->shader.is_valid(),Variant()); - return rasterizer->shader_get_default_param(canvas_item->shader,p_param); + if (canvas_item_material_owner.owns(p_material)) { + canvas_item->material=canvas_item_material_owner.get(p_material); + canvas_item->material->owners.insert(canvas_item); } - - return canvas_item->shader_param[p_param]; } - void VisualServerRaster::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { VS_CHANGED; @@ -3989,19 +3966,41 @@ void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_ena Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); ERR_FAIL_COND(!clight); - clight->shadow=p_enabled; + + if (clight->shadow_buffer.is_valid()==p_enabled) + return; + if (p_enabled) { + clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size); + } else { + rasterizer->free(clight->shadow_buffer); + clight->shadow_buffer=RID(); + + } } + void VisualServerRaster::canvas_light_set_shadow_buffer_size(RID p_light, int p_size){ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); ERR_FAIL_COND(!clight); + ERR_FAIL_COND(p_size<32 || p_size>16384); + + clight->shadow_buffer_size=nearest_power_of_2(p_size); + + + if (clight->shadow_buffer.is_valid()) { + rasterizer->free(clight->shadow_buffer); + clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size); + } + } -void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size){ + +void VisualServerRaster::canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier) { Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); ERR_FAIL_COND(!clight); + clight->shadow_esm_mult=p_multiplier; } @@ -4009,26 +4008,217 @@ void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size) RID VisualServerRaster::canvas_light_occluder_create() { - return RID(); + Rasterizer::CanvasLightOccluderInstance *occluder = memnew( Rasterizer::CanvasLightOccluderInstance ); + + return canvas_light_occluder_owner.make_rid( occluder ); + } void VisualServerRaster::canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas) { + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!occluder); + + if (occluder->canvas.is_valid()) { + + Canvas *canvas = canvas_owner.get(occluder->canvas); + canvas->occluders.erase(occluder); + } + + if (!canvas_owner.owns(p_canvas)) + p_canvas=RID(); + + occluder->canvas=p_canvas; + if (occluder->canvas.is_valid()) { + + Canvas *canvas = canvas_owner.get(occluder->canvas); + canvas->occluders.insert(occluder); + } } void VisualServerRaster::canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled){ + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!occluder); + + occluder->enabled=p_enabled; } -void VisualServerRaster::canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape){ +void VisualServerRaster::canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon) { + + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!occluder); + + if (occluder->polygon.is_valid()) { + CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon); + if (occluder_poly) { + occluder_poly->owners.erase(occluder); + } + } + occluder->polygon=p_polygon; + occluder->polygon_buffer=RID(); + + if (occluder->polygon.is_valid()) { + CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon); + if (!occluder_poly) + occluder->polygon=RID(); + ERR_FAIL_COND(!occluder_poly); + occluder_poly->owners.insert(occluder); + occluder->polygon_buffer=occluder_poly->occluder; + occluder->aabb_cache=occluder_poly->aabb; + occluder->cull_cache=occluder_poly->cull_mode; + } } + +void VisualServerRaster::canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform) { + + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!occluder); + + occluder->xform=p_xform; + +} + +void VisualServerRaster::canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask) { + + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!occluder); + + occluder->light_mask=p_mask; + +} + + +RID VisualServerRaster::canvas_occluder_polygon_create() { + + CanvasLightOccluderPolygon * occluder_poly = memnew( CanvasLightOccluderPolygon ); + occluder_poly->occluder=rasterizer->canvas_light_occluder_create(); + return canvas_light_occluder_polygon_owner.make_rid(occluder_poly); + +} + +void VisualServerRaster::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const DVector<Vector2>& p_shape, bool p_close){ + + if (p_shape.size()<3) { + canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,p_shape); + return; + } + + DVector<Vector2> lines; + int lc = p_shape.size()*2; + + lines.resize(lc-(p_close?0:2)); + { + DVector<Vector2>::Write w = lines.write(); + DVector<Vector2>::Read r = p_shape.read(); + + int max=lc/2; + if (!p_close) { + max--; + } + for(int i=0;i<max;i++) { + + Vector2 a = r[i]; + Vector2 b = r[(i+1)%(lc/2)]; + w[i*2+0]=a; + w[i*2+1]=b; + } + + } + + canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,lines); +} + +void VisualServerRaster::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape) { + + CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon); + ERR_FAIL_COND(!occluder_poly); + ERR_FAIL_COND(p_shape.size()&1); + + int lc = p_shape.size(); + occluder_poly->aabb=Rect2(); + { + DVector<Vector2>::Read r = p_shape.read(); + for(int i=0;i<lc;i++) { + if (i==0) + occluder_poly->aabb.pos=r[i]; + else + occluder_poly->aabb.expand_to(r[i]); + } + } + + rasterizer->canvas_light_occluder_set_polylines(occluder_poly->occluder,p_shape); + for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) { + E->get()->aabb_cache=occluder_poly->aabb; + } +} + +void VisualServerRaster::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode) { + + CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon); + ERR_FAIL_COND(!occluder_poly); + occluder_poly->cull_mode=p_mode; + for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) { + E->get()->cull_cache=p_mode; + } + +} + +RID VisualServerRaster::canvas_item_material_create() { + + Rasterizer::CanvasItemMaterial *material = memnew( Rasterizer::CanvasItemMaterial ); + return canvas_item_material_owner.make_rid(material); + +} + +void VisualServerRaster::canvas_item_material_set_shader(RID p_material, RID p_shader){ + + VS_CHANGED; + Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); + ERR_FAIL_COND(!material); + material->shader=p_shader; + +} +void VisualServerRaster::canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value){ + + VS_CHANGED; + Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); + ERR_FAIL_COND(!material); + if (p_value.get_type()==Variant::NIL) + material->shader_param.erase(p_param); + else + material->shader_param[p_param]=p_value; + + +} +Variant VisualServerRaster::canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const{ + Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); + ERR_FAIL_COND_V(!material,Variant()); + if (!material->shader_param.has(p_param)) { + ERR_FAIL_COND_V(!material->shader.is_valid(),Variant()); + return rasterizer->shader_get_default_param(material->shader,p_param); + } + + return material->shader_param[p_param]; +} + +void VisualServerRaster::canvas_item_material_set_unshaded(RID p_material, bool p_unshaded){ + + VS_CHANGED; + Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); + ERR_FAIL_COND(!material); + material->unshaded=p_unshaded; + +} + + /******** CANVAS *********/ @@ -4285,6 +4475,10 @@ void VisualServerRaster::free( RID p_rid ) { E->get()->canvas=RID(); } + for (Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=canvas->occluders.front();E;E=E->next()) { + + E->get()->canvas=RID(); + } canvas_owner.free( p_rid ); @@ -4314,10 +4508,26 @@ void VisualServerRaster::free( RID p_rid ) { canvas_item->child_items[i]->parent=RID(); } + if (canvas_item->material) { + canvas_item->material->owners.erase(canvas_item); + } + canvas_item_owner.free( p_rid ); memdelete( canvas_item ); + } else if (canvas_item_material_owner.owns(p_rid)) { + + Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get(p_rid); + ERR_FAIL_COND(!material); + for(Set<Rasterizer::CanvasItem*>::Element *E=material->owners.front();E;E=E->next()) { + + E->get()->material=NULL; + } + + canvas_item_material_owner.free(p_rid); + memdelete(material); + } else if (canvas_light_owner.owns(p_rid)) { Rasterizer::CanvasLight *canvas_light = canvas_light_owner.get(p_rid); @@ -4329,9 +4539,44 @@ void VisualServerRaster::free( RID p_rid ) { canvas->lights.erase(canvas_light); } + if (canvas_light->shadow_buffer.is_valid()) + rasterizer->free(canvas_light->shadow_buffer); + canvas_light_owner.free( p_rid ); memdelete( canvas_light ); + } else if (canvas_light_occluder_owner.owns(p_rid)) { + + Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid); + ERR_FAIL_COND(!occluder); + + if (occluder->polygon.is_valid()) { + + CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon); + if (occluder_poly) { + occluder_poly->owners.erase(occluder); + } + + } + + canvas_light_occluder_owner.free( p_rid ); + memdelete(occluder); + + } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) { + + CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_rid); + ERR_FAIL_COND(!occluder_poly); + rasterizer->free(occluder_poly->occluder); + + while(occluder_poly->owners.size()) { + + occluder_poly->owners.front()->get()->polygon=RID(); + occluder_poly->owners.erase( occluder_poly->owners.front() ); + } + + canvas_light_occluder_polygon_owner.free( p_rid ); + memdelete(occluder_poly); + } else if (scenario_owner.owns(p_rid)) { Scenario *scenario=scenario_owner.get(p_rid); @@ -6410,7 +6655,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_shader_owner) { +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; @@ -6455,11 +6700,11 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat ci->vp_render=NULL; } - if (ci->use_parent_shader && p_shader_owner) - ci->shader_owner=p_shader_owner; + if (ci->use_parent_material && p_material_owner) + ci->material_owner=p_material_owner; else { - p_shader_owner=ci; - ci->shader_owner=NULL; + p_material_owner=ci; + ci->material_owner=NULL; } @@ -6493,7 +6738,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat if (child_items[i]->ontop) continue; - _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner); + _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner); } @@ -6524,7 +6769,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat if (!child_items[i]->ontop) continue; - _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner); + _render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner); } } @@ -6658,6 +6903,8 @@ 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; + Rect2 shadow_rect; for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) { @@ -6676,6 +6923,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ cl->rect_cache=Rect2(-offset+cl->texture_offset,tsize); cl->xform_cache=xf * cl->xform; + if (clip_rect.intersects_transformed(cl->xform_cache,cl->rect_cache)) { cl->filter_next_ptr=lights; lights=cl; @@ -6685,16 +6933,55 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ scale.elements[2]=cl->rect_cache.pos; cl->light_shader_xform = (cl->xform_cache * scale).affine_inverse(); cl->light_shader_pos=cl->xform_cache[2]; + if (cl->shadow_buffer.is_valid()) { + cl->shadows_next_ptr=lights_with_shadow; + if (lights_with_shadow==NULL) { + shadow_rect = cl->xform_cache.xform(cl->rect_cache); + } else { + shadow_rect=shadow_rect.merge( cl->xform_cache.xform(cl->rect_cache) ); + } + lights_with_shadow=cl; + cl->radius_cache=cl->rect_cache.size.length(); + + } } + } + } + + canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get(); + } + + if (lights_with_shadow) { + //update shadows if any + + Rasterizer::CanvasLightOccluderInstance * occluders=NULL; + + //make list of occluders + for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) { + + Matrix32 xf = p_viewport->global_transform * E->get().transform; + for(Set<Rasterizer::CanvasLightOccluderInstance*>::Element *F=E->get().canvas->occluders.front();F;F=F->next()) { + F->get()->xform_cache = xf * F->get()->xform; + if (shadow_rect.intersects_transformed(F->get()->xform_cache,F->get()->aabb_cache)) { + F->get()->next=occluders; + occluders=F->get(); + + } } } + //update the light shadowmaps with them + Rasterizer::CanvasLight *light=lights_with_shadow; + while(light) { - canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get(); + rasterizer->canvas_light_shadow_buffer_update(light->shadow_buffer,light->xform_cache.affine_inverse(),light->item_mask,light->radius_cache/1000.0,light->radius_cache*1.1,occluders,&light->shadow_matrix_cache); + light=light->shadows_next_ptr; + } + rasterizer->set_viewport(viewport_rect); //must reset viewport afterwards } for (Map<Viewport::CanvasKey,Viewport::CanvasData*>::Element *E=canvas_map.front();E;E=E->next()) { @@ -6719,6 +7006,8 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ i++; } + + rasterizer->canvas_debug_viewport_shadows(lights_with_shadow); } //capture diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 9b2b0c9c1a..b9a3f83364 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -371,7 +371,7 @@ class VisualServerRaster : public VisualServer { - + mutable RID_Owner<Rasterizer::CanvasItemMaterial> canvas_item_material_owner; struct CanvasItem : public Rasterizer::CanvasItem { @@ -384,7 +384,7 @@ class VisualServerRaster : public VisualServer { bool sort_y; float opacity; float self_opacity; - bool use_parent_shader; + bool use_parent_material; Vector<CanvasItem*> child_items; @@ -396,7 +396,7 @@ class VisualServerRaster : public VisualServer { opacity=1; self_opacity=1; sort_y=false; - use_parent_shader=false; + use_parent_material=false; z_relative=true; } }; @@ -410,6 +410,24 @@ class VisualServerRaster : public VisualServer { } }; + struct CanvasLightOccluder; + + struct CanvasLightOccluderPolygon { + + bool active; + Rect2 aabb; + CanvasOccluderPolygonCullMode cull_mode; + RID occluder; + Set<Rasterizer::CanvasLightOccluderInstance*> owners; + + CanvasLightOccluderPolygon() { active=false; cull_mode=CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; } + }; + + + RID_Owner<CanvasLightOccluderPolygon> canvas_light_occluder_polygon_owner; + + RID_Owner<Rasterizer::CanvasLightOccluderInstance> canvas_light_occluder_owner; + struct CanvasLight; struct Canvas { @@ -422,6 +440,7 @@ class VisualServerRaster : public VisualServer { }; Set<Rasterizer::CanvasLight*> lights; + Set<Rasterizer::CanvasLightOccluderInstance*> occluders; Vector<ChildItem> child_items; Color modulate; @@ -610,7 +629,7 @@ class VisualServerRaster : public VisualServer { void _render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario); 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_shader_owner); + 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); 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); @@ -1131,15 +1150,8 @@ public: virtual void canvas_item_set_z(RID p_item, int p_z); virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable); - virtual void canvas_item_set_shader(RID p_item, RID p_shader); - virtual RID canvas_item_get_shader(RID p_item) const; - - virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable); - - - - virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value); - virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const; + virtual void canvas_item_set_material(RID p_item, RID p_material); + virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable); virtual RID canvas_light_create(); virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas); @@ -1156,17 +1168,36 @@ public: virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable); virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled); virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size); - virtual void canvas_light_set_shadow_filter(RID p_light, int p_size); + virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier); virtual RID canvas_light_occluder_create(); virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas); virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled); - virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape); + virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon); + virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform); + virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask); + + + virtual RID canvas_occluder_polygon_create(); + virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_close); + virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape); + virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode); + + virtual void canvas_item_clear(RID p_item); virtual void canvas_item_raise(RID p_item); + /* CANVAS ITEM MATERIAL */ + + virtual RID canvas_item_material_create(); + virtual void canvas_item_material_set_shader(RID p_material, RID p_shader); + virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value); + virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const; + virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded); + + /* CURSOR */ virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 6c95b6ed58..1890f7b760 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -1139,14 +1139,9 @@ public: FUNC2(canvas_item_set_z,RID,int); FUNC2(canvas_item_set_z_as_relative_to_parent,RID,bool); - FUNC2(canvas_item_set_shader,RID, RID ); - FUNC1RC(RID,canvas_item_get_shader,RID ); + FUNC2(canvas_item_set_material,RID, RID ); - FUNC2(canvas_item_set_use_parent_shader,RID, bool ); - - - FUNC3(canvas_item_set_shader_param,RID,const StringName&,const Variant&); - FUNC2RC(Variant,canvas_item_get_shader_param,RID,const StringName&); + FUNC2(canvas_item_set_use_parent_material,RID, bool ); FUNC1(canvas_item_clear,RID); FUNC1(canvas_item_raise,RID); @@ -1167,14 +1162,31 @@ public: FUNC2(canvas_light_set_subtract_mode,RID,bool); FUNC2(canvas_light_set_shadow_enabled,RID,bool); FUNC2(canvas_light_set_shadow_buffer_size,RID,int); - FUNC2(canvas_light_set_shadow_filter,RID,int); + FUNC2(canvas_light_set_shadow_esm_multiplier,RID,float); + /* CANVAS OCCLUDER */ FUNC0R(RID,canvas_light_occluder_create); FUNC2(canvas_light_occluder_attach_to_canvas,RID,RID); FUNC2(canvas_light_occluder_set_enabled,RID,bool); - FUNC2(canvas_light_occluder_set_shape,RID,const DVector<Vector2>&); + FUNC2(canvas_light_occluder_set_polygon,RID,RID); + FUNC2(canvas_light_occluder_set_transform,RID,const Matrix32&); + FUNC2(canvas_light_occluder_set_light_mask,RID,int); + + + FUNC0R(RID,canvas_occluder_polygon_create); + FUNC3(canvas_occluder_polygon_set_shape,RID,const DVector<Vector2>&,bool); + FUNC2(canvas_occluder_polygon_set_shape_as_lines,RID,const DVector<Vector2>&); + FUNC2(canvas_occluder_polygon_set_cull_mode,RID,CanvasOccluderPolygonCullMode); + + /* CANVAS MATERIAL */ + + FUNC0R(RID,canvas_item_material_create); + FUNC2(canvas_item_material_set_shader,RID,RID); + FUNC3(canvas_item_material_set_shader_param,RID,const StringName&,const Variant&); + FUNC2RC(Variant,canvas_item_material_get_shader_param,RID,const StringName&); + FUNC2(canvas_item_material_set_unshaded,RID,bool); /* CURSOR */ FUNC2(cursor_set_rotation,float , int ); // radians diff --git a/servers/visual_server.h b/servers/visual_server.h index 37368e32f4..ccf6978ae3 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -998,13 +998,9 @@ public: virtual void canvas_item_clear(RID p_item)=0; virtual void canvas_item_raise(RID p_item)=0; - virtual void canvas_item_set_shader(RID p_item, RID p_shader)=0; - virtual RID canvas_item_get_shader(RID p_item) const=0; + virtual void canvas_item_set_material(RID p_item, RID p_material)=0; - virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable)=0; - - virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value)=0; - virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const=0; + virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable)=0; virtual RID canvas_light_create()=0; virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas)=0; @@ -1021,13 +1017,34 @@ public: virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable)=0; virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled)=0; virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size)=0; - virtual void canvas_light_set_shadow_filter(RID p_light, int p_size)=0; + virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier)=0; + virtual RID canvas_light_occluder_create()=0; virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas)=0; virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled)=0; - virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape)=0; + virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon)=0; + virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform)=0; + virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask)=0; + + virtual RID canvas_occluder_polygon_create()=0; + virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_closed)=0; + virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape)=0; + enum CanvasOccluderPolygonCullMode { + CANVAS_OCCLUDER_POLYGON_CULL_DISABLED, + CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE, + CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE, + }; + virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode)=0; + + /* CANVAS ITEM MATERIAL */ + + virtual RID canvas_item_material_create()=0; + virtual void canvas_item_material_set_shader(RID p_material, RID p_shader)=0; + virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value)=0; + virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const=0; + virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded)=0; /* CURSOR */ virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index cc1a05f7d3..3d42867d9a 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -90,6 +90,7 @@ #include "plugins/baked_light_editor_plugin.h" #include "plugins/polygon_2d_editor_plugin.h" #include "plugins/navigation_polygon_editor_plugin.h" +#include "plugins/light_occluder_2d_editor_plugin.h" // end #include "tools/editor/io_plugins/editor_texture_import_plugin.h" #include "tools/editor/io_plugins/editor_scene_import_plugin.h" @@ -4115,6 +4116,7 @@ EditorNode::EditorNode() { add_editor_plugin( memnew( PathEditorPlugin(this) ) ); add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) ); add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) ); + add_editor_plugin( memnew( LightOccluder2DEditorPlugin(this) ) ); add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) ); for(int i=0;i<EditorPlugins::get_plugin_count();i++) diff --git a/tools/editor/icons/icon_canvas_item_material.png b/tools/editor/icons/icon_canvas_item_material.png Binary files differnew file mode 100644 index 0000000000..2fe8921653 --- /dev/null +++ b/tools/editor/icons/icon_canvas_item_material.png diff --git a/tools/editor/icons/icon_canvas_modulate.png b/tools/editor/icons/icon_canvas_modulate.png Binary files differnew file mode 100644 index 0000000000..2a34df7793 --- /dev/null +++ b/tools/editor/icons/icon_canvas_modulate.png diff --git a/tools/editor/icons/icon_light_occluder_2d.png b/tools/editor/icons/icon_light_occluder_2d.png Binary files differnew file mode 100644 index 0000000000..c66dd536d3 --- /dev/null +++ b/tools/editor/icons/icon_light_occluder_2d.png diff --git a/tools/editor/icons/icon_occluder_polygon_2d.png b/tools/editor/icons/icon_occluder_polygon_2d.png Binary files differnew file mode 100644 index 0000000000..705794b729 --- /dev/null +++ b/tools/editor/icons/icon_occluder_polygon_2d.png diff --git a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp index ed228e9a1c..dab6df9a39 100644 --- a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -4,6 +4,7 @@ #include "os/file_access.h" #include "tools/editor/editor_settings.h" + void CollisionPolygon2DEditor::_notification(int p_what) { switch(p_what) { diff --git a/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp new file mode 100644 index 0000000000..c1fb81b66a --- /dev/null +++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -0,0 +1,500 @@ +#include "light_occluder_2d_editor_plugin.h" + +#include "canvas_item_editor_plugin.h" +#include "os/file_access.h" +#include "tools/editor/editor_settings.h" + +void LightOccluder2DEditor::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_READY: { + + button_create->set_icon( get_icon("Edit","EditorIcons")); + button_edit->set_icon( get_icon("MovePoint","EditorIcons")); + button_edit->set_pressed(true); + get_tree()->connect("node_removed",this,"_node_removed"); + create_poly->connect("confirmed",this,"_create_poly"); + + } break; + case NOTIFICATION_FIXED_PROCESS: { + + + } break; + } + +} +void LightOccluder2DEditor::_node_removed(Node *p_node) { + + if(p_node==node) { + node=NULL; + hide(); + canvas_item_editor->get_viewport_control()->update(); + } + +} + + +Vector2 LightOccluder2DEditor::snap_point(const Vector2& p_point) const { + + if (canvas_item_editor->is_snap_active()) { + + return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap()); + + } else { + return p_point; + } +} + +void LightOccluder2DEditor::_menu_option(int p_option) { + + switch(p_option) { + + case MODE_CREATE: { + + mode=MODE_CREATE; + button_create->set_pressed(true); + button_edit->set_pressed(false); + } break; + case MODE_EDIT: { + + mode=MODE_EDIT; + button_create->set_pressed(false); + button_edit->set_pressed(true); + } break; + + } +} + +void LightOccluder2DEditor::_wip_close(bool p_closed) { + + undo_redo->create_action("Create Poly"); + undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",node->get_occluder_polygon()->get_polygon()); + undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",wip); + undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_closed",node->get_occluder_polygon()->is_closed()); + undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_closed",p_closed); + + undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->commit_action(); + wip.clear(); + wip_active=false; + mode=MODE_EDIT; + button_edit->set_pressed(true); + button_create->set_pressed(false); + edited_point=-1; +} + +bool LightOccluder2DEditor::forward_input_event(const InputEvent& p_event) { + + + if (!node) + return false; + + if (node->get_occluder_polygon().is_null()) { + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { + create_poly->set_text("No OccluderPolygon2D resource on this node.\nCreate and assign one?"); + create_poly->popup_centered_minsize(); + } + return false; + } + switch(p_event.type) { + + case InputEvent::MOUSE_BUTTON: { + + const InputEventMouseButton &mb=p_event.mouse_button; + + Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); + + + Vector2 gpoint = Point2(mb.x,mb.y); + Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); + cpoint=snap_point(cpoint); + cpoint = node->get_global_transform().affine_inverse().xform(cpoint); + + Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon()); + + //first check if a point is to be added (segment split) + real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8); + + switch(mode) { + + + case MODE_CREATE: { + + if (mb.button_index==BUTTON_LEFT && mb.pressed) { + + + if (!wip_active) { + + wip.clear(); + wip.push_back( cpoint ); + wip_active=true; + edited_point_pos=cpoint; + canvas_item_editor->get_viewport_control()->update(); + edited_point=1; + return true; + } else { + + + if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) { + //wip closed + _wip_close(true); + + return true; + } else if (wip.size()>1 && xform.xform(wip[wip.size()-1]).distance_to(gpoint)<grab_treshold) { + //wip closed + _wip_close(false); + return true; + + } else { + + wip.push_back( cpoint ); + edited_point=wip.size(); + canvas_item_editor->get_viewport_control()->update(); + return true; + + //add wip point + } + } + } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) { + _wip_close(true); + } + + + + } break; + + case MODE_EDIT: { + + if (mb.button_index==BUTTON_LEFT) { + if (mb.pressed) { + + if (mb.mod.control) { + + + if (poly.size() < 3) { + + undo_redo->create_action("Edit Poly"); + undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); + poly.push_back(cpoint); + undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); + undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->commit_action(); + return true; + } + + //search edges + int closest_idx=-1; + Vector2 closest_pos; + real_t closest_dist=1e10; + for(int i=0;i<poly.size();i++) { + + Vector2 points[2] ={ xform.xform(poly[i]), + xform.xform(poly[(i+1)%poly.size()]) }; + + Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points); + if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2) + continue; //not valid to reuse point + + real_t d = cp.distance_to(gpoint); + if (d<closest_dist && d<grab_treshold) { + closest_dist=d; + closest_pos=cp; + closest_idx=i; + } + + + } + + if (closest_idx>=0) { + + pre_move_edit=poly; + poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos)); + edited_point=closest_idx+1; + edited_point_pos=xform.affine_inverse().xform(closest_pos); + node->get_occluder_polygon()->set_polygon(Variant(poly)); + canvas_item_editor->get_viewport_control()->update(); + return true; + } + } else { + + //look for points to move + + int closest_idx=-1; + Vector2 closest_pos; + real_t closest_dist=1e10; + for(int i=0;i<poly.size();i++) { + + Vector2 cp =xform.xform(poly[i]); + + real_t d = cp.distance_to(gpoint); + if (d<closest_dist && d<grab_treshold) { + closest_dist=d; + closest_pos=cp; + closest_idx=i; + } + + } + + if (closest_idx>=0) { + + pre_move_edit=poly; + edited_point=closest_idx; + edited_point_pos=xform.affine_inverse().xform(closest_pos); + canvas_item_editor->get_viewport_control()->update(); + return true; + } + } + } else { + + if (edited_point!=-1) { + + //apply + + ERR_FAIL_INDEX_V(edited_point,poly.size(),false); + poly[edited_point]=edited_point_pos; + undo_redo->create_action("Edit Poly"); + undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); + undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",pre_move_edit); + undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->commit_action(); + + edited_point=-1; + return true; + } + } + } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) { + + + + int closest_idx=-1; + Vector2 closest_pos; + real_t closest_dist=1e10; + for(int i=0;i<poly.size();i++) { + + Vector2 cp =xform.xform(poly[i]); + + real_t d = cp.distance_to(gpoint); + if (d<closest_dist && d<grab_treshold) { + closest_dist=d; + closest_pos=cp; + closest_idx=i; + } + + } + + if (closest_idx>=0) { + + + undo_redo->create_action("Edit Poly (Remove Point)"); + undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); + poly.remove(closest_idx); + undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); + undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); + undo_redo->commit_action(); + return true; + } + + } + + + + } break; + } + + + + } break; + case InputEvent::MOUSE_MOTION: { + + const InputEventMouseMotion &mm=p_event.mouse_motion; + + if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) { + + Vector2 gpoint = Point2(mm.x,mm.y); + Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); + cpoint=snap_point(cpoint); + edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint); + + canvas_item_editor->get_viewport_control()->update(); + + } + + } break; + } + + return false; +} +void LightOccluder2DEditor::_canvas_draw() { + + if (!node || !node->get_occluder_polygon().is_valid()) + return; + + Control *vpc = canvas_item_editor->get_viewport_control(); + + Vector<Vector2> poly; + + if (wip_active) + poly=wip; + else + poly=Variant(node->get_occluder_polygon()->get_polygon()); + + + Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); + Ref<Texture> handle= get_icon("EditorHandle","EditorIcons"); + + int len = poly.size(); + + for(int i=0;i<poly.size();i++) { + + + Vector2 p,p2; + p = i==edited_point ? edited_point_pos : poly[i]; + if ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point)) + p2=edited_point_pos; + else + p2 = poly[(i+1)%poly.size()]; + + Vector2 point = xform.xform(p); + Vector2 next_point = xform.xform(p2); + + Color col=Color(1,0.3,0.1,0.8); + + if (i==poly.size()-1 && (!node->get_occluder_polygon()->is_closed() || wip_active)) { + + } else { + vpc->draw_line(point,next_point,col,2); + } + vpc->draw_texture(handle,point-handle->get_size()*0.5); + } +} + + + +void LightOccluder2DEditor::edit(Node *p_collision_polygon) { + + if (!canvas_item_editor) { + canvas_item_editor=CanvasItemEditor::get_singleton(); + } + + if (p_collision_polygon) { + + node=p_collision_polygon->cast_to<LightOccluder2D>(); + if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) + canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw"); + wip.clear(); + wip_active=false; + edited_point=-1; + + } else { + node=NULL; + + if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) + canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw"); + + } + +} + +void LightOccluder2DEditor::_create_poly() { + + undo_redo->create_action("Create Occluder Polygon"); + undo_redo->add_do_method(node,"set_occluder_polygon",Ref<OccluderPolygon2D>(memnew( OccluderPolygon2D))); + undo_redo->add_undo_method(node,"set_occluder_polygon",Variant(REF())); + undo_redo->commit_action(); +} + +void LightOccluder2DEditor::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_menu_option"),&LightOccluder2DEditor::_menu_option); + ObjectTypeDB::bind_method(_MD("_canvas_draw"),&LightOccluder2DEditor::_canvas_draw); + ObjectTypeDB::bind_method(_MD("_node_removed"),&LightOccluder2DEditor::_node_removed); + ObjectTypeDB::bind_method(_MD("_create_poly"),&LightOccluder2DEditor::_create_poly); + +} + + +LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) { + + canvas_item_editor=NULL; + editor=p_editor; + undo_redo = editor->get_undo_redo(); + + add_child( memnew( VSeparator )); + button_create = memnew( ToolButton ); + add_child(button_create); + button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE)); + button_create->set_toggle_mode(true); + button_create->set_tooltip("Create a new polygon from scratch"); + + button_edit = memnew( ToolButton ); + add_child(button_edit); + button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT)); + button_edit->set_toggle_mode(true); + button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point."); + + create_poly = memnew( ConfirmationDialog ); + add_child(create_poly); + create_poly->get_ok()->set_text("Create"); + + + //add_constant_override("separation",0); + +#if 0 + options = memnew( MenuButton ); + add_child(options); + options->set_area_as_parent_rect(); + options->set_text("Polygon"); + //options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE); + options->get_popup()->connect("item_pressed", this,"_menu_option"); +#endif + + mode = MODE_EDIT; + wip_active=false; + +} + + +void LightOccluder2DEditorPlugin::edit(Object *p_object) { + + collision_polygon_editor->edit(p_object->cast_to<Node>()); +} + +bool LightOccluder2DEditorPlugin::handles(Object *p_object) const { + + return p_object->is_type("LightOccluder2D"); +} + +void LightOccluder2DEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + collision_polygon_editor->show(); + } else { + + collision_polygon_editor->hide(); + collision_polygon_editor->edit(NULL); + } + +} + +LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) { + + editor=p_node; + collision_polygon_editor = memnew( LightOccluder2DEditor(p_node) ); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); + + collision_polygon_editor->hide(); + + + +} + + +LightOccluder2DEditorPlugin::~LightOccluder2DEditorPlugin() +{ +} + diff --git a/tools/editor/plugins/light_occluder_2d_editor_plugin.h b/tools/editor/plugins/light_occluder_2d_editor_plugin.h new file mode 100644 index 0000000000..5fb5631d05 --- /dev/null +++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.h @@ -0,0 +1,87 @@ +#ifndef LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H +#define LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H + + + +#include "tools/editor/editor_plugin.h" +#include "tools/editor/editor_node.h" +#include "scene/2d/light_occluder_2d.h" +#include "scene/gui/tool_button.h" +#include "scene/gui/button_group.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class CanvasItemEditor; + +class LightOccluder2DEditor : public HBoxContainer { + + OBJ_TYPE(LightOccluder2DEditor, HBoxContainer ); + + UndoRedo *undo_redo; + enum Mode { + + MODE_CREATE, + MODE_EDIT, + + }; + + Mode mode; + + ToolButton *button_create; + ToolButton *button_edit; + + CanvasItemEditor *canvas_item_editor; + EditorNode *editor; + Panel *panel; + LightOccluder2D *node; + MenuButton *options; + + int edited_point; + Vector2 edited_point_pos; + Vector<Vector2> pre_move_edit; + Vector<Vector2> wip; + bool wip_active; + + ConfirmationDialog *create_poly; + + void _wip_close(bool p_closed); + void _canvas_draw(); + void _menu_option(int p_option); + void _create_poly(); + +protected: + void _notification(int p_what); + void _node_removed(Node *p_node); + static void _bind_methods(); +public: + + Vector2 snap_point(const Vector2& p_point) const; + bool forward_input_event(const InputEvent& p_event); + void edit(Node *p_collision_polygon); + LightOccluder2DEditor(EditorNode *p_editor); +}; + +class LightOccluder2DEditorPlugin : public EditorPlugin { + + OBJ_TYPE( LightOccluder2DEditorPlugin, EditorPlugin ); + + LightOccluder2DEditor *collision_polygon_editor; + EditorNode *editor; + +public: + + virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); } + + virtual String get_name() const { return "LightOccluder2D"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_node); + virtual bool handles(Object *p_node) const; + virtual void make_visible(bool p_visible); + + LightOccluder2DEditorPlugin(EditorNode *p_node); + ~LightOccluder2DEditorPlugin(); + +}; + +#endif // LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index a600683097..25c39b3173 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -1857,8 +1857,33 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p } else { p_item->set_text(1,"<"+res->get_type()+">"); }; + + if (has_icon(res->get_type(),"EditorIcons")) { + + p_item->set_icon(1,get_icon(res->get_type(),"EditorIcons")); + } else { + + Dictionary d = p_item->get_metadata(0); + int hint=d.has("hint")?d["hint"].operator int():-1; + String hint_text=d.has("hint_text")?d["hint_text"]:""; + if (hint==PROPERTY_HINT_RESOURCE_TYPE) { + + if (has_icon(hint_text,"EditorIcons")) { + + p_item->set_icon(1,get_icon(hint_text,"EditorIcons")); + + } else { + p_item->set_icon(1,get_icon("Object","EditorIcons")); + + } + } + } + + + } + } break; default: {}; } @@ -2529,7 +2554,10 @@ void PropertyEditor::update_tree() { item->set_editable( 1, !read_only ); item->add_button(1,get_icon("EditResource","EditorIcons")); String type; + if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) + type=p.hint_string; bool notnil=false; + if (obj->get( p.name ).get_type() == Variant::NIL || obj->get( p.name ).operator RefPtr().is_null()) { item->set_text(1,"<null>"); @@ -2553,12 +2581,18 @@ void PropertyEditor::update_tree() { }; notnil=true; + if (has_icon(res->get_type(),"EditorIcons")) { + type=res->get_type(); + } } - if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) { + + if (type!=String()) { + if (type.find(",")!=-1) + type=type.get_slice(",",0); //printf("prop %s , type %s\n",p.name.ascii().get_data(),p.hint_string.ascii().get_data()); - if (has_icon(p.hint_string,"EditorIcons")) - item->set_icon( 0, get_icon(p.hint_string,"EditorIcons") ); + if (has_icon(type,"EditorIcons")) + item->set_icon( 0, get_icon(type,"EditorIcons") ); else item->set_icon( 0, get_icon("Object","EditorIcons") ); } |