diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/SCsub | 1 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_gles2.cpp | 1201 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_gles2.h | 100 | ||||
-rw-r--r-- | drivers/gles2/shader_compiler_gles2.cpp | 22 | ||||
-rw-r--r-- | drivers/gles2/shader_compiler_gles2.h | 3 | ||||
-rw-r--r-- | drivers/gles2/shaders/SCsub | 1 | ||||
-rw-r--r-- | drivers/gles2/shaders/canvas.glsl | 190 | ||||
-rw-r--r-- | drivers/gles2/shaders/canvas_shadow.glsl | 62 | ||||
-rw-r--r-- | drivers/unix/ip_unix.cpp | 7 | ||||
-rw-r--r-- | drivers/unix/os_unix.cpp | 20 | ||||
-rw-r--r-- | drivers/windows/file_access_windows.cpp | 20 |
11 files changed, 1387 insertions, 240 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index 46334468ba..a1a2191cbc 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -10,7 +10,6 @@ SConscript('alsa/SCsub'); SConscript('pulseaudio/SCsub');
SConscript('windows/SCsub');
SConscript('gles2/SCsub');
-SConscript('gles1/SCsub');
SConscript('gl_context/SCsub');
SConscript('openssl/SCsub');
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 9cee702c05..e167b647e7 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -971,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu - if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { + if (!(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { texture->has_alpha=true; } @@ -2525,7 +2525,7 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui void RasterizerGLES2::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) { ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?"); - ERR_FAIL_V(); + ERR_FAIL(); } Array RasterizerGLES2::mesh_get_surface_arrays(RID p_mesh,int p_surface) const { @@ -4038,8 +4038,16 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int glGenTextures(1, &rt->color); glBindTexture(GL_TEXTURE_2D, rt->color); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + if (rt->texture_ptr->flags&VS::TEXTURE_FLAG_FILTER) { + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); @@ -4108,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 @@ -4272,7 +4284,7 @@ void RasterizerGLES2::clear_viewport(const Color& p_color) { } glEnable(GL_SCISSOR_TEST); - glClearColor(p_color.r,p_color.g,p_color.b,1.0); + glClearColor(p_color.r,p_color.g,p_color.b,p_color.a); glClear(GL_COLOR_BUFFER_BIT); //should not clear if anything else cleared.. glDisable(GL_SCISSOR_TEST); }; @@ -4588,6 +4600,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const { enablers.push_back("#define USE_TEXPIXEL_SIZE\n"); } + if (vertex_flags.uses_worldvec) { + enablers.push_back("#define USE_WORLD_VEC\n"); + } canvas_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, light_code, fragment_globals,uniform_names,enablers); //postprocess_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, fragment_globals,uniform_names); @@ -5108,8 +5123,10 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material int texcoord=0; for (Map<StringName,Material::UniformData>::Element *E=p_material->shader_params.front();E;E=E->next()) { + if (E->get().index<0) continue; +// print_line(String(E->key())+": "+E->get().value); if (E->get().istexture) { //clearly a texture.. RID rid = E->get().value; @@ -5489,13 +5506,15 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia base = surf->array_local; glBindBuffer(GL_ARRAY_BUFFER, 0); bool can_copy_to_local=surf->local_stride * surf->array_len <= skinned_buffer_size; + if (p_morphs && surf->stride * surf->array_len > skinned_buffer_size) + can_copy_to_local=false; + + if (!can_copy_to_local) skeleton_valid=false; - /* compute morphs */ - if (p_morphs && surf->morph_target_count && can_copy_to_local) { @@ -6383,7 +6402,12 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans case VS::MATERIAL_BLEND_MODE_MIX: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } break; case VS::MATERIAL_BLEND_MODE_ADD: { @@ -6394,12 +6418,17 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans } break; case VS::MATERIAL_BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_SUBTRACT); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); glBlendFunc(GL_SRC_ALPHA,GL_ONE); } break; case VS::MATERIAL_BLEND_MODE_MUL: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } break; @@ -6666,7 +6695,12 @@ void RasterizerGLES2::_copy_to_texscreen() { #endif glDisable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); @@ -7140,7 +7174,12 @@ void RasterizerGLES2::end_scene() { current_depth_mask=true; texscreen_copied=false; glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } glDisable(GL_BLEND); current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; @@ -7157,7 +7196,12 @@ void RasterizerGLES2::end_scene() { } glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } glDisable(GL_BLEND); current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; material_shader.set_conditional(MaterialShaderGLES2::USE_GLOW,false); @@ -7794,7 +7838,12 @@ void RasterizerGLES2::canvas_begin() { #endif glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glLineWidth(1.0); glBindBuffer(GL_ARRAY_BUFFER,0); @@ -7809,8 +7858,10 @@ void RasterizerGLES2::canvas_begin() { //material_shader.unbind(); canvas_shader.unbind(); canvas_shader.set_custom_shader(0); + canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false); canvas_shader.bind(); canvas_shader.set_uniform(CanvasShaderGLES2::TEXTURE, 0); + canvas_use_modulate=false; _set_color_attrib(Color(1,1,1)); canvas_transform=Transform(); canvas_transform.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f); @@ -7825,10 +7876,10 @@ void RasterizerGLES2::canvas_begin() { canvas_opacity=1.0; canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; - canvas_texscreen_used=false; uses_texpixel_size=false; - canvas_last_shader=RID(); + + canvas_last_material=NULL; } @@ -7850,7 +7901,12 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) { case VS::MATERIAL_BLEND_MODE_MIX: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } break; case VS::MATERIAL_BLEND_MODE_ADD: { @@ -7861,7 +7917,7 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) { } break; case VS::MATERIAL_BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_SUBTRACT); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); glBlendFunc(GL_SRC_ALPHA,GL_ONE); } break; case VS::MATERIAL_BLEND_MODE_MUL: { @@ -8088,7 +8144,7 @@ void RasterizerGLES2::_draw_gui_primitive2(int p_points, const Vector2 *p_vertic _rinfo.ci_draw_commands++; } -void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip ) { +void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip, bool p_transpose ) { Vector2 texcoords[4]= { Vector2( p_src_region.pos.x/p_tex_size.width, @@ -8104,6 +8160,9 @@ void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_sr (p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height) }; + if (p_transpose) { + SWAP( texcoords[1], texcoords[3] ); + } if (p_h_flip) { SWAP( texcoords[0], texcoords[1] ); SWAP( texcoords[2], texcoords[3] ); @@ -8151,11 +8210,11 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R if (!(p_flags&CANVAS_RECT_REGION)) { Rect2 region = Rect2(0,0,texture->width,texture->height); - _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); + _draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE); } else { - _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V ); + _draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE); } } else { @@ -8310,13 +8369,739 @@ 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); -void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { + // 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) + return; + normal_flip=p_flip; + canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,normal_flip); +} + + +template<bool use_normalmap> +void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip) { + + int cc=p_item->commands.size(); + CanvasItem::Command **commands = p_item->commands.ptr(); + + + for(int i=0;i<cc;i++) { + + CanvasItem::Command *c=commands[i]; + + switch(c->type) { + case CanvasItem::Command::TYPE_LINE: { + + CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c); + canvas_draw_line(line->from,line->to,line->color,line->width); + } break; + case CanvasItem::Command::TYPE_RECT: { + + CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c); +// canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate); +#if 0 + int flags=0; + + if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) { + flags|=Rasterizer::CANVAS_RECT_REGION; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) { + flags|=Rasterizer::CANVAS_RECT_TILE; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) { + + flags|=Rasterizer::CANVAS_RECT_FLIP_H; + } + if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) { + + flags|=Rasterizer::CANVAS_RECT_FLIP_V; + } +#else + + int flags=rect->flags; +#endif + if (use_normalmap) + _canvas_normal_set_flip(Vector2((flags&CANVAS_RECT_FLIP_H)?-1:1,(flags&CANVAS_RECT_FLIP_V)?-1:1)); + canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate); + + } break; + case CanvasItem::Command::TYPE_STYLE: { + + CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c); + if (use_normalmap) + _canvas_normal_set_flip(Vector2(1,1)); + canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color); + + } break; + case CanvasItem::Command::TYPE_PRIMITIVE: { + + if (use_normalmap) + _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c); + canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width); + } break; + case CanvasItem::Command::TYPE_POLYGON: { + + if (use_normalmap) + _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c); + canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + + } break; + + case CanvasItem::Command::TYPE_POLYGON_PTR: { + + if (use_normalmap) + _canvas_normal_set_flip(Vector2(1,1)); + CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c); + canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false); + } break; + case CanvasItem::Command::TYPE_CIRCLE: { + + CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c); + static const int numpoints=32; + Vector2 points[numpoints+1]; + points[numpoints]=circle->pos; + int indices[numpoints*3]; + + for(int i=0;i<numpoints;i++) { + + points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius; + indices[i*3+0]=i; + indices[i*3+1]=(i+1)%numpoints; + indices[i*3+2]=numpoints; + } + canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); + //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); + } break; + case CanvasItem::Command::TYPE_TRANSFORM: { + + CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c); + canvas_set_transform(transform->xform); + } break; + case CanvasItem::Command::TYPE_BLEND_MODE: { + + CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c); + canvas_set_blend_mode(bm->blend_mode); + + } break; + case CanvasItem::Command::TYPE_CLIP_IGNORE: { + + CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c); + if (current_clip) { + + if (ci->ignore!=reclip) { + if (ci->ignore) { + + glDisable(GL_SCISSOR_TEST); + reclip=true; + } else { + + glEnable(GL_SCISSOR_TEST); + glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), + current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); + reclip=false; + } + } + } + + + + } break; + } + } + +} + +void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) { + + if (canvas_shader.bind()) + rebind_texpixel_size=true; + + if (material->shader_version!=shader->version) { + //todo optimize uniforms + material->shader_version=shader->version; + } + + if (shader->has_texscreen && framebuffer.active) { + + int x = viewport.x; + int y = window_size.height-(viewport.height+viewport.y); + + canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); + canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); + canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1); + glActiveTexture(GL_TEXTURE0+max_texture_units-1); + glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); + if (framebuffer.scale==1 && !canvas_texscreen_used) { +#ifdef GLEW_ENABLED + glReadBuffer(GL_COLOR_ATTACHMENT0); +#endif + glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); +// if (current_clip) { +// // print_line(" a clip "); +// } + + canvas_texscreen_used=true; + } + + glActiveTexture(GL_TEXTURE0); + + } + + if (shader->has_screen_uv) { + canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); + } + + + uses_texpixel_size=shader->uses_texpixel_size; + +} + +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=material->shader_param.find(E->key()); + + if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) { + + RID rid; + if (F) { + rid=F->get(); + } + + if (!rid.is_valid()) { + + Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key()); + if (DT) { + rid=DT->get(); + } + } + + if (rid.is_valid()) { + + int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic.. + + glActiveTexture(GL_TEXTURE0+tex_id); + Texture *t=texture_owner.get(rid); + if (!t) + glBindTexture(GL_TEXTURE_2D,white_tex); + else + glBindTexture(t->target,t->tex_id); + + glUniform1i(loc,tex_id); + tex_id++; + } + } else { + Variant &v=F?F->get():E->get().default_value; + canvas_shader.set_custom_uniform(idx,v); + } + + idx++; + } + + if (tex_id>1) { + glActiveTexture(GL_TEXTURE0); + } + + if (shader->uses_time) { + canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0)); + draw_next_frame=true; + } + //if uses TIME - draw_next_frame=true + + +} + +void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) { CanvasItem *current_clip=NULL; + Shader *shader_cache=NULL; + + bool rebind_shader=true; canvas_opacity=1.0; + canvas_use_modulate=p_modulate!=Color(1,1,1,1); + 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; @@ -8326,8 +9111,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { 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; + + } if (current_clip!=ci->final_clip_owner) { @@ -8348,98 +9140,26 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { //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) { + 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; } } + shader_cache=shader; + if (shader) { canvas_shader.set_custom_shader(shader->custom_code_id); - if (canvas_shader.bind()) - rebind_texpixel_size=true; - - if (shader_owner->shader_version!=shader->version) { - //todo optimize uniforms - shader_owner->shader_version=shader->version; - } - //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()); - Variant &v=F?F->get():E->get().default_value; - if (v.get_type()==Variant::_RID || v.get_type()==Variant::OBJECT) { - int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic.. - - glActiveTexture(GL_TEXTURE0+tex_id); - RID tex = v; - Texture *t=texture_owner.get(tex); - if (!t) - glBindTexture(GL_TEXTURE_2D,white_tex); - else - glBindTexture(t->target,t->tex_id); - - glUniform1i(loc,tex_id); - tex_id++; - - } else { - canvas_shader.set_custom_uniform(idx,v); - } - - idx++; - } - - - if (shader->has_texscreen && framebuffer.active) { - - int x = viewport.x; - int y = window_size.height-(viewport.height+viewport.y); - - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); - canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,tex_id); - glActiveTexture(GL_TEXTURE0+tex_id); - glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); - if (framebuffer.scale==1 && !canvas_texscreen_used) { -#ifdef GLEW_ENABLED - glReadBuffer(GL_COLOR_ATTACHMENT0); -#endif - glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); - if (current_clip) { - print_line(" a clip "); - } - - canvas_texscreen_used=true; - } - tex_id++; - - } - - if (tex_id>1) { - glActiveTexture(GL_TEXTURE0); - } - if (shader->has_screen_uv) { - canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); - } - - if (shader->uses_time) { - canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0)); - draw_next_frame=true; - } - //if uses TIME - draw_next_frame=true - - uses_texpixel_size=shader->uses_texpixel_size; - + _canvas_item_setup_shader_params(material,shader); } else { + shader_cache=NULL; canvas_shader.set_custom_shader(0); canvas_shader.bind(); uses_texpixel_size=false; @@ -8448,9 +9168,27 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform); - canvas_last_shader=shader_owner->shader; + if (canvas_use_modulate) + reset_modulate=true; + canvas_last_material=material; + rebind_shader=false; + } + + if (material && 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()); @@ -8463,7 +9201,12 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { case VS::MATERIAL_BLEND_MODE_MIX: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } break; case VS::MATERIAL_BLEND_MODE_ADD: { @@ -8474,7 +9217,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { } break; case VS::MATERIAL_BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_SUBTRACT); + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); glBlendFunc(GL_SRC_ALPHA,GL_ONE); } break; case VS::MATERIAL_BLEND_MODE_MUL: { @@ -8491,128 +9234,140 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { canvas_blend_mode=ci->blend_mode; } - int cc=ci->commands.size(); - CanvasItem::Command **commands = ci->commands.ptr(); - canvas_opacity = ci->final_opacity; - for(int i=0;i<cc;i++) { + _canvas_item_render_commands<false>(ci,current_clip,reclip); - CanvasItem::Command *c=commands[i]; + if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && (!material || !material->unshaded)) { - switch(c->type) { - case CanvasItem::Command::TYPE_LINE: { + CanvasLight *light = p_light; + bool light_used=false; + bool subtract=false; - CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c); - canvas_draw_line(line->from,line->to,line->color,line->width); - } break; - case CanvasItem::Command::TYPE_RECT: { - CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c); -// canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate); -#if 0 - int flags=0; + while(light) { - if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) { - flags|=Rasterizer::CANVAS_RECT_REGION; - } - if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) { - flags|=Rasterizer::CANVAS_RECT_TILE; - } - if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) { + if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) { + + //intersects this light + + if (!light_used || subtract!=light->subtract) { + + subtract=light->subtract; + + if (subtract) { + + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); - flags|=Rasterizer::CANVAS_RECT_FLIP_H; + } else { + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + } } - if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) { - flags|=Rasterizer::CANVAS_RECT_FLIP_V; + if (!light_used) { + + canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,true); + canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false); + light_used=true; + normal_flip=Vector2(1,1); + } -#else + canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,light->shadow_buffer.is_valid()); - int flags=rect->flags; -#endif - canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate); + bool light_rebind = canvas_shader.bind(); - } break; - case CanvasItem::Command::TYPE_STYLE: { + if (light_rebind) { - CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c); - canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color); + if (material && shader_cache) { + _canvas_item_setup_shader_params(material,shader_cache); + _canvas_item_setup_shader_uniforms(material,shader_cache); + } - } break; - case CanvasItem::Command::TYPE_PRIMITIVE: { + canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); + canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); + canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform); + 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); - CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c); - canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width); - } break; - case CanvasItem::Command::TYPE_POLYGON: { - CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c); - canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + } - } break; + canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform); + 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()) { - case CanvasItem::Command::TYPE_POLYGON_PTR: { + 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); - CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c); - canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false); - } break; - case CanvasItem::Command::TYPE_CIRCLE: { + 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); + + } - CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c); - static const int numpoints=32; - Vector2 points[numpoints+1]; - points[numpoints]=circle->pos; - int indices[numpoints*3]; - for(int i=0;i<numpoints;i++) { + 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); + if (!t) { + glBindTexture(GL_TEXTURE_2D,white_tex); + } else { - points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius; - indices[i*3+0]=i; - indices[i*3+1]=(i+1)%numpoints; - indices[i*3+2]=numpoints; + glBindTexture(t->target,t->tex_id); } - canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); - //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); - } break; - case CanvasItem::Command::TYPE_TRANSFORM: { - CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c); - canvas_set_transform(transform->xform); - } break; - case CanvasItem::Command::TYPE_BLEND_MODE: { + glActiveTexture(GL_TEXTURE0); + _canvas_item_render_commands<true>(ci,current_clip,reclip); //redraw using light - CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c); - canvas_set_blend_mode(bm->blend_mode); + } - } break; - case CanvasItem::Command::TYPE_CLIP_IGNORE: { + light=light->next_ptr; + } - CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c); - if (current_clip) { + if (light_used) { - if (ci->ignore!=reclip) { - if (ci->ignore) { - glDisable(GL_SCISSOR_TEST); - reclip=true; - } else { + 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); - glEnable(GL_SCISSOR_TEST); - glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), - current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); - reclip=false; - } - } - } + canvas_shader.bind(); + 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); + canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); + if (canvas_use_modulate) + canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); - } break; + glBlendEquation(GL_FUNC_ADD); + if (current_rt && current_rt_transparent) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } - } + } + if (reclip) { glEnable(GL_SCISSOR_TEST); @@ -8824,6 +9579,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; } @@ -9001,7 +9761,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); }; } @@ -9536,10 +10319,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 @@ -9561,9 +10346,6 @@ void RasterizerGLES2::init() { //glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - skinned_buffer_size = GLOBAL_DEF("rasterizer/skinned_buffer_size",DEFAULT_SKINNED_BUFFER_SIZE); - skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size ); - glGenTextures(1, &white_tex); unsigned char whitetexdata[8*8*3]; for(int i=0;i<8*8*3;i++) { @@ -9683,8 +10465,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(); @@ -9706,6 +10491,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); } @@ -9738,8 +10524,7 @@ void RasterizerGLES2::init() { void RasterizerGLES2::finish() { - - memdelete_arr(skinned_buffer); + free(canvas_shadow_blur); } int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) { @@ -10019,10 +10804,29 @@ RasterizerGLES2* RasterizerGLES2::get_singleton() { return _singleton; }; +int RasterizerGLES2::RenderList::max_elements=RenderList::DEFAULT_MAX_ELEMENTS; + RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) { _singleton = this; + RenderList::max_elements=GLOBAL_DEF("rasterizer/max_render_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS); + if (RenderList::max_elements>64000) + RenderList::max_elements=64000; + if (RenderList::max_elements<1024) + RenderList::max_elements=1024; + + opaque_render_list.init(); + alpha_render_list.init(); + + skinned_buffer_size = GLOBAL_DEF("rasterizer/skeleton_buffer_size_kb",DEFAULT_SKINNED_BUFFER_SIZE); + if (skinned_buffer_size<256) + skinned_buffer_size=256; + if (skinned_buffer_size>16384) + skinned_buffer_size=16384; + skinned_buffer_size*=1024; + skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size ); + keep_copies=p_keep_ram_copy; use_reload_hooks=p_use_reload_hooks; pack_arrays=p_compress_arrays; @@ -10066,6 +10870,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo RasterizerGLES2::~RasterizerGLES2() { + memdelete_arr(skinned_buffer); }; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 0f77d18dee..f09714f50c 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -51,6 +51,7 @@ #include "drivers/gles2/shaders/material.glsl.h" #include "drivers/gles2/shaders/canvas.glsl.h" +#include "drivers/gles2/shaders/canvas_shadow.glsl.h" #include "drivers/gles2/shaders/blur.glsl.h" #include "drivers/gles2/shaders/copy.glsl.h" #include "drivers/gles2/shader_compiler_gles2.h" @@ -65,7 +66,7 @@ class RasterizerGLES2 : public Rasterizer { MAX_SCENE_LIGHTS=2048, LIGHT_SPOT_BIT=0x80, - DEFAULT_SKINNED_BUFFER_SIZE = 2048 * 1024, // 10k vertices + DEFAULT_SKINNED_BUFFER_SIZE = 2048, // 10k vertices MAX_HW_LIGHTS = 1, }; @@ -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; @@ -827,15 +829,18 @@ class RasterizerGLES2 : public Rasterizer { GLuint gui_quad_buffer; + struct RenderList { enum { - MAX_ELEMENTS=4096, + DEFAULT_MAX_ELEMENTS=4096, MAX_LIGHTS=4, SORT_FLAG_SKELETON=1, SORT_FLAG_INSTANCING=2, }; + static int max_elements; + struct Element { @@ -868,8 +873,8 @@ class RasterizerGLES2 : public Rasterizer { }; - Element _elements[MAX_ELEMENTS]; - Element *elements[MAX_ELEMENTS]; + Element *_elements; + Element **elements; int element_count; void clear() { @@ -1004,17 +1009,28 @@ class RasterizerGLES2 : public Rasterizer { } _FORCE_INLINE_ Element* add_element() { - if (element_count>MAX_ELEMENTS) + if (element_count>=max_elements) return NULL; elements[element_count]=&_elements[element_count]; return elements[element_count++]; } - RenderList() { + void init() { element_count = 0; - for (int i=0;i<MAX_ELEMENTS;i++) + elements=memnew_arr(Element*,max_elements); + _elements=memnew_arr(Element,max_elements); + for (int i=0;i<max_elements;i++) elements[i]=&_elements[i]; // assign elements + + } + + RenderList() { + + } + ~RenderList() { + memdelete_arr(elements); + memdelete_arr(_elements); } }; @@ -1113,6 +1129,7 @@ class RasterizerGLES2 : public Rasterizer { bool active; int blur_size; + struct Blur { GLuint fbo; @@ -1145,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer { void _process_glow_and_bloom(); //void _update_blur_buffer(); + /*********/ /* FRAME */ /*********/ @@ -1163,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; @@ -1172,11 +1229,15 @@ class RasterizerGLES2 : public Rasterizer { GLuint white_tex; RID canvas_tex; float canvas_opacity; + Color canvas_modulate; + bool canvas_use_modulate; 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); _FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture); @@ -1208,17 +1269,19 @@ 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; void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1); _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs); _FORCE_INLINE_ void _draw_gui_primitive2(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs, const Vector2 *p_uvs2); - void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false ); + void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false, bool p_transpose=false ); void _draw_quad(const Rect2& p_rect); void _copy_screen_quad(); void _copy_to_texscreen(); @@ -1233,6 +1296,10 @@ class RasterizerGLES2 : public Rasterizer { GLuint tc0_id_cache; GLuint tc0_idx; + 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(CanvasItemMaterial *material,Shader* p_shader); + _FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* p_shader); public: /* TEXTURE API */ @@ -1548,7 +1615,18 @@ public: virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor); virtual void canvas_set_transform(const Matrix32& p_transform); - virtual void canvas_render_items(CanvasItem *p_item_list); + 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 */ @@ -1587,6 +1665,8 @@ public: virtual bool is_environment(const RID& p_rid) const; virtual bool is_shader(const RID& p_rid) const; + virtual bool is_canvas_light_occluder(const RID& p_rid) const; + virtual void free(const RID& p_rid); virtual void init(); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index f1ddcf8009..b2052c7cbb 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -226,6 +226,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a if (vnode->name==vname_var2_interp) { flags->use_var2_interp=true; } + if (vnode->name==vname_world_vec) { + uses_worldvec=true; + } } @@ -258,6 +261,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a uses_light=true; } + if (vnode->name==vname_normal) { + uses_normal=true; + } + + } if (vnode->name==vname_time) { @@ -307,13 +315,13 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a String mul_l=dump_node_code(onode->arguments[0],p_level,true); String mul_r=dump_node_code(onode->arguments[1],p_level); - code=mul_l+"=(vec4("+mul_l+",1.0,1.0)*("+mul_r+")).xy"; + code=mul_l+"=(vec4("+mul_l+",0.0,1.0)*("+mul_r+")).xy"; break; } else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { String mul_l=dump_node_code(onode->arguments[0],p_level,true); String mul_r=dump_node_code(onode->arguments[1],p_level); - code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",1.0,1.0)).xy"; + code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",0.0,1.0)).xy"; break; } else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT3) { String mul_l=dump_node_code(onode->arguments[0],p_level,true); @@ -343,11 +351,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a break; } else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { - code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",1.0,1.0)).xyz"; + code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",0.0,1.0)).xy"; break; } else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT4) { - code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",1.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xyz"; + code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",0.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xy"; break; } else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT3 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { @@ -599,6 +607,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT uses_normalmap=false; uses_normal=false; uses_texpixel_size=false; + uses_worldvec=false; vertex_code_writes_vertex=false; uniforms=r_uniforms; flags=&r_flags; @@ -632,8 +641,9 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT r_flags.uses_light=uses_light; r_flags.uses_time=uses_time; r_flags.uses_normalmap=uses_normalmap; - r_flags.uses_normal=uses_normalmap; + r_flags.uses_normal=uses_normal; r_flags.uses_texpixel_size=uses_texpixel_size; + r_flags.uses_worldvec=uses_worldvec; r_code_line=code; r_globals_line=global_code; @@ -774,6 +784,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { mode_replace_table[3]["SRC_VERTEX"]="src_vtx"; mode_replace_table[3]["VERTEX"]="outvec.xy"; + mode_replace_table[3]["WORLD_VERTEX"]="outvec.xy"; mode_replace_table[3]["UV"]="uv_interp"; mode_replace_table[3]["COLOR"]="color_interp"; mode_replace_table[3]["VAR1"]="var1_interp"; @@ -830,5 +841,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { vname_normalmap="NORMALMAP"; vname_normal="NORMAL"; vname_texpixel_size="TEXTURE_PIXEL_SIZE"; + vname_world_vec="WORLD_VERTEX"; } diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index a10fa6dfe0..87722602fd 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -53,6 +53,7 @@ private: bool uses_normalmap; bool uses_normal; bool uses_texpixel_size; + bool uses_worldvec; bool vertex_code_writes_vertex; Flags *flags; @@ -72,6 +73,7 @@ private: StringName vname_normalmap; StringName vname_normal; StringName vname_texpixel_size; + StringName vname_world_vec; Map<StringName,ShaderLanguage::Uniform> *uniforms; @@ -107,6 +109,7 @@ public: bool uses_time; bool uses_normal; bool uses_texpixel_size; + bool uses_worldvec; }; Error compile(const String& p_code, ShaderLanguage::ShaderType p_type, String& r_code_line, String& r_globals_line, Flags& r_flags, Map<StringName,ShaderLanguage::Uniform> *r_uniforms=NULL); diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index c665cf9036..9679223b16 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -3,6 +3,7 @@ Import('env') if env['BUILDERS'].has_key('GLSL120GLES'): env.GLSL120GLES('material.glsl'); env.GLSL120GLES('canvas.glsl'); + env.GLSL120GLES('canvas_shadow.glsl'); env.GLSL120GLES('blur.glsl'); env.GLSL120GLES('copy.glsl'); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 464cb9e188..9022f30d7f 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -26,7 +26,17 @@ uniform float time; #ifdef USE_LIGHTING uniform highp mat4 light_matrix; -varying vec4 light_tex_pos; +uniform vec2 light_pos; +varying vec4 light_uv_interp; + +#if defined(NORMAL_USED) +varying vec4 local_rot; +uniform vec2 normal_flip; +#endif + +#ifdef USE_SHADOWS +highp varying vec2 pos; +#endif #endif @@ -46,29 +56,42 @@ void main() { color_interp = color_attrib; uv_interp = uv_attrib; - highp vec4 outvec = vec4(vertex, 1.0); + highp vec4 outvec = vec4(vertex, 1.0); { - vec2 src_vtx=outvec.xy; + vec2 src_vtx=outvec.xy; VERTEX_SHADER_CODE } - outvec = extra_matrix * outvec; - outvec = modelview_matrix * outvec; +#if !defined(USE_WORLD_VEC) + outvec = extra_matrix * outvec; + outvec = modelview_matrix * outvec; +#endif + + + #ifdef USE_PIXEL_SNAP outvec.xy=floor(outvec.xy+0.5); #endif + gl_Position = projection_matrix * outvec; + #ifdef USE_LIGHTING - light_tex_pos.xy = light_matrix * outvec; - light_tex_pos.zw=outvec.xy - light_matrix[4].xy; //likely wrong + 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; + local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy )*normal_flip.y; #endif +#endif - gl_Position = projection_matrix * outvec; } [fragment] @@ -118,17 +141,37 @@ varying vec4 var2_interp; uniform float time; #endif +#ifdef USE_MODULATE + +uniform vec4 modulate; + +#endif #ifdef USE_LIGHTING uniform sampler2D light_texture; -varying vec4 light_tex_pos; +uniform vec4 light_color; +uniform float light_height; +varying vec4 light_uv_interp; + +#if defined(NORMAL_USED) +varying vec4 local_rot; +#endif #ifdef USE_SHADOWS 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 @@ -148,6 +191,7 @@ void main() { vec3 normal = vec3(0,0,1); #endif + color *= texture2D( texture, uv_interp ); #if defined(ENABLE_SCREEN_UV) vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; @@ -161,37 +205,141 @@ FRAGMENT_SHADER_CODE color = vec4(vec3(enc32),1.0); #endif +#ifdef USE_MODULATE + + color*=modulate; +#endif + + #ifdef USE_LIGHTING +#if defined(NORMAL_USED) + normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy; +#endif + float att=1.0; - vec3 light = texture2D(light_texture,light_tex_pos).rgb; + 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 #if defined(USE_LIGHT_SHADER_CODE) //light is written by the light shader { - vec2 light_dir = normalize(light_tex_pos.zw); - float light_distance = length(light_tex_pos.zw); + vec2 light_dir = normalize(light_uv_interp.zw); + float light_distance = length(light_uv_interp.zw); LIGHT_SHADER_CODE } + #else #if defined(NORMAL_USED) - vec2 light_normal = normalize(light_tex_pos.zw); - light = color.rgb * light * max(dot(light_normal,normal),0); + vec3 light_normal = normalize(vec3(light_uv_interp.zw,-light_height)); + light*=max(dot(-light_normal,normal),0); +#endif + + color*=light; +/* +#ifdef USE_NORMAL + color.xy=local_rot.xy;//normal.xy; + color.zw=vec2(0.0,1.0); #endif +*/ + if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) { + color.a=0.0; //invisible + } - color.rgb=light; //light shader code #endif diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..40cf321dce --- /dev/null +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -0,0 +1,62 @@ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision mediump float; +precision mediump int; +#endif + +uniform highp mat4 projection_matrix; +uniform highp mat4 light_matrix; +uniform highp mat4 world_matrix; + +attribute highp vec3 vertex; // attrib:0 + +#ifndef USE_DEPTH_SHADOWS + +varying vec4 position_interp; + +#endif + + +void main() { + + gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0))); + +#ifndef USE_DEPTH_SHADOWS + position_interp = gl_Position; +#endif + +} + +[fragment] + +#ifdef USE_GLES_OVER_GL +#define mediump +#define highp +#else +precision mediump float; +precision mediump int; +#endif + +#ifndef USE_DEPTH_SHADOWS + +varying vec4 position_interp; + +#endif + +void main() { + +#ifdef USE_DEPTH_SHADOWS + +#else + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias; + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + gl_FragColor = comp; +#endif + +} + diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 841160f941..ad0d4e00ea 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -50,11 +50,16 @@ #ifdef ANDROID_ENABLED #include "platform/android/ifaddrs_android.h" #else + #ifdef __FreeBSD__ + #include <sys/types.h> + #endif #include <ifaddrs.h> #endif #include <arpa/inet.h> #include <sys/socket.h> - + #ifdef __FreeBSD__ + #include <netinet/in.h> + #endif #endif IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 2de975e5d1..d51a7c74e8 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -44,7 +44,9 @@ #include "stream_peer_tcp_posix.h" #include "packet_peer_udp_posix.h" - +#ifdef __FreeBSD__ +#include <sys/param.h> +#endif #include <stdarg.h> #include <sys/time.h> #include <sys/wait.h> @@ -305,7 +307,17 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo args.push_back((char*)cs[i].get_data());// shitty C cast args.push_back(0); +#ifdef __FreeBSD__ + if(p_path.find("/")) { + // exec name contains path so use it + execv(p_path.utf8().get_data(),&args[0]); + }else{ + // use program name and search through PATH to find it + execvp(getprogname(),&args[0]); + } +#else execv(p_path.utf8().get_data(),&args[0]); +#endif // still alive? something failed.. fprintf(stderr,"**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n",p_path.utf8().get_data()); abort(); @@ -421,6 +433,12 @@ String OS_Unix::get_executable_path() const { return OS::get_executable_path(); } return b; +#elif defined(__FreeBSD__) + char resolved_path[MAXPATHLEN]; + + realpath(OS::get_executable_path().utf8().get_data(), resolved_path); + + return String(resolved_path); #else ERR_PRINT("Warning, don't know how to obtain executable path on this OS! Please override this function properly."); return OS::get_executable_path(); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index a6073cbb29..e24685432c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -28,14 +28,18 @@ /*************************************************************************/ #ifdef WINDOWS_ENABLED +#include <Windows.h> +#include "Shlwapi.h" #include "file_access_windows.h" + #include <sys/types.h> #include <sys/stat.h> #include <wchar.h> #include <tchar.h> #include "print_string.h" + #ifdef _MSC_VER #define S_ISREG(m) ((m)&_S_IFREG) #endif @@ -111,10 +115,20 @@ void FileAccessWindows::close() { //unlink(save_path.utf8().get_data()); //print_line("renaming.."); - _wunlink(save_path.c_str()); //unlink if exists - int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); + //_wunlink(save_path.c_str()); //unlink if exists + //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); + + + bool rename_error; + if (!PathFileExistsW(save_path.c_str())) { + //creating new file + rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str())!=0; + } else { + //atomic replace for existing file + rename_error = !ReplaceFileW(save_path.c_str(), (save_path+".tmp").c_str(), NULL, 2|4, NULL, NULL); + } save_path=""; - ERR_FAIL_COND( rename_error != 0); + ERR_FAIL_COND( rename_error ); } |