support for 2D shadow casters

Added support for 2D shadow casters.

*DANGER* Shaders in CanvasItem CHANGED, if you are using shader in a
CanvasItem and pull this, you will lose them. Shaders now work through a
2D material system similar to 3D. If you don't want to lose the 2D
shader code, save the shader as a .shd, then create a material in
CanvasItem and re-assign the shader.
This commit is contained in:
Juan Linietsky 2015-03-02 00:54:10 -03:00
parent 0e732637d0
commit a1f715a4da
43 changed files with 2586 additions and 271 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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;

Binary file not shown.

Binary file not shown.

View file

@ -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');

View file

@ -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(shader_owner,shader_cache);
_canvas_item_setup_shader_uniforms(material,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) {

View file

@ -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();

View file

@ -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');

View file

@ -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

View file

@ -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
}

View file

@ -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 );
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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 );

View file

@ -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'])

View file

@ -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) {
void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) {
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
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
if (material.is_valid())
rid=material->get_rid();
VS::get_singleton()->canvas_item_set_material(canvas_item,rid);
_change_notify(); //properties for material exposed
}
void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) {
void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
use_parent_shader=p_use_parent_shader;
VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_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);
}
bool CanvasItem::get_use_parent_shader() const{
bool CanvasItem::get_use_parent_material() const{
return use_parent_shader;
return use_parent_material;
}
Ref<Shader> CanvasItem::get_shader() const{
Ref<CanvasItemMaterial> CanvasItem::get_material() const{
return shader;
return material;
}
void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) {
VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value);
}
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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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();
};

View file

@ -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);

View file

@ -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");

View file

@ -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;

View file

@ -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;

View file

@ -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{
if (canvas_item->material)
canvas_item->material->owners.erase(canvas_item);
CanvasItem *canvas_item = canvas_item_owner.get( p_item );
ERR_FAIL_COND_V(!canvas_item,RID());
return canvas_item->shader;
canvas_item->material=NULL;
}
void VisualServerRaster::canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value){
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,11 +6933,18 @@ 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();
}
}
}
}
@ -6697,6 +6952,38 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
}
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) {
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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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++)

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

View file

@ -4,6 +4,7 @@
#include "os/file_access.h"
#include "tools/editor/editor_settings.h"
void CollisionPolygon2DEditor::_notification(int p_what) {
switch(p_what) {

View file

@ -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()
{
}

View file

@ -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

View file

@ -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") );
}