diff options
author | Juan Linietsky <reduzio@gmail.com> | 2016-10-03 16:33:42 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2016-10-03 21:35:16 +0200 |
commit | 22d83bc9f655d5ae7a1b49709c4c1b663725daf5 (patch) | |
tree | a817195c08d4713a70ca014a3f63f5937934fe36 /drivers/gles3 | |
parent | 78d97b060a6873a454e710380cb9ef1bde5e4c65 (diff) |
Begining of GLES3 renderer:
-Most 2D drawing is implemented
-Missing shaders
-Missing all 3D
-Editor needs to be set on update always to be used, otherwise it does not refresh
-Large parts of editor not working
Diffstat (limited to 'drivers/gles3')
-rw-r--r-- | drivers/gles3/SCsub | 5 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.cpp | 1461 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.h | 102 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_gles3.cpp | 266 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_gles3.h | 38 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 2045 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.h | 445 | ||||
-rw-r--r-- | drivers/gles3/shader_gles3.cpp | 754 | ||||
-rw-r--r-- | drivers/gles3/shader_gles3.h | 377 | ||||
-rw-r--r-- | drivers/gles3/shaders/SCsub | 7 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 428 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_shadow.glsl | 49 | ||||
-rw-r--r-- | drivers/gles3/shaders/copy.glsl | 52 |
13 files changed, 6029 insertions, 0 deletions
diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub new file mode 100644 index 0000000000..a17335b41b --- /dev/null +++ b/drivers/gles3/SCsub @@ -0,0 +1,5 @@ +Import('env') + +env.add_source_files(env.drivers_sources,"*.cpp") + +SConscript("shaders/SCsub") diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp new file mode 100644 index 0000000000..f24560763f --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -0,0 +1,1461 @@ +#include "rasterizer_canvas_gles3.h" +#include "os/os.h" + +static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) { + + p_array[ 0]=p_mtx.elements[0][0]; + p_array[ 1]=p_mtx.elements[0][1]; + p_array[ 2]=0; + p_array[ 3]=0; + p_array[ 4]=p_mtx.elements[1][0]; + p_array[ 5]=p_mtx.elements[1][1]; + p_array[ 6]=0; + p_array[ 7]=0; + p_array[ 8]=0; + p_array[ 9]=0; + p_array[10]=1; + p_array[11]=0; + p_array[12]=p_mtx.elements[2][0]; + p_array[13]=p_mtx.elements[2][1]; + p_array[14]=0; + p_array[15]=1; +} + + +static _FORCE_INLINE_ void store_transform(const Transform& p_mtx, float* p_array) { + p_array[ 0]=p_mtx.basis.elements[0][0]; + p_array[ 1]=p_mtx.basis.elements[1][0]; + p_array[ 2]=p_mtx.basis.elements[2][0]; + p_array[ 3]=0; + p_array[ 4]=p_mtx.basis.elements[0][1]; + p_array[ 5]=p_mtx.basis.elements[1][1]; + p_array[ 6]=p_mtx.basis.elements[2][1]; + p_array[ 7]=0; + p_array[ 8]=p_mtx.basis.elements[0][2]; + p_array[ 9]=p_mtx.basis.elements[1][2]; + p_array[10]=p_mtx.basis.elements[2][2]; + p_array[11]=0; + p_array[12]=p_mtx.origin.x; + p_array[13]=p_mtx.origin.y; + p_array[14]=p_mtx.origin.z; + p_array[15]=1; +} + +static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_array) { + + for (int i=0;i<4;i++) { + for (int j=0;j<4;j++) { + + p_array[i*4+j]=p_mtx.matrix[i][j]; + } + } +} + + +RID RasterizerCanvasGLES3::light_internal_create() { + + LightInternal * li = memnew( LightInternal ); + + glGenBuffers(1, &li->ubo); + glBindBuffer(GL_UNIFORM_BUFFER, li->ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInternal::UBOData), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + return light_internal_owner.make_rid(li); +} + +void RasterizerCanvasGLES3::light_internal_update(RID p_rid, Light* p_light) { + + LightInternal * li = light_internal_owner.getornull(p_rid); + ERR_FAIL_COND(!li); + + store_matrix32(p_light->light_shader_xform,li->ubo_data.light_matrix); + store_matrix32(p_light->xform_cache.affine_inverse(),li->ubo_data.local_matrix); + store_camera(p_light->shadow_matrix_cache,li->ubo_data.shadow_matrix); + + for(int i=0;i<4;i++) { + + li->ubo_data.color[i]=p_light->color[i]*p_light->energy; + li->ubo_data.shadow_color[i]=p_light->shadow_color[i]; + } + + li->ubo_data.light_pos[0]=p_light->light_shader_pos.x; + li->ubo_data.light_pos[1]=p_light->light_shader_pos.y; + li->ubo_data.shadowpixel_size=1.0/p_light->shadow_buffer_size; + li->ubo_data.light_outside_alpha=p_light->mode==VS::CANVAS_LIGHT_MODE_MASK?1.0:0.0; + li->ubo_data.light_height=p_light->height; + if (p_light->radius_cache==0) + li->ubo_data.shadow_gradient=0; + else + li->ubo_data.shadow_gradient=p_light->shadow_gradient_length/(p_light->radius_cache*1.1);; + + li->ubo_data.shadow_distance_mult=(p_light->radius_cache*1.1); + + + glBindBuffer(GL_UNIFORM_BUFFER, li->ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(LightInternal::UBOData), &li->ubo_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + +} + +void RasterizerCanvasGLES3::light_internal_free(RID p_rid) { + + LightInternal * li = light_internal_owner.getornull(p_rid); + ERR_FAIL_COND(!li); + + glDeleteBuffers(1,&li->ubo); + light_internal_owner.free(p_rid); + memdelete(li); + +} + +void RasterizerCanvasGLES3::canvas_begin(){ + + /*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;*/ + + reset_canvas(); + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT,true); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD,false); + + + state.canvas_shader.bind(); + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,Color(1,1,1,1)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,Matrix32()); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Matrix32()); + + + + +// state.canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX,state.vp); + //state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,Transform()); + //state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Transform()); + + glBindBufferBase(GL_UNIFORM_BUFFER,0,state.canvas_item_ubo); + glBindVertexArray(data.canvas_quad_array); + state.using_texture_rect=true; + + +} + + +void RasterizerCanvasGLES3::canvas_end(){ + + + glBindVertexArray(0); + glBindBufferBase(GL_UNIFORM_BUFFER,0,0); + + state.using_texture_rect=false; + +} + + + +RasterizerStorageGLES3::Texture* RasterizerCanvasGLES3::_bind_canvas_texture(const RID& p_texture) { + + if (p_texture==state.current_tex) { + return state.current_tex_ptr; + } + + if (p_texture.is_valid()) { + + + RasterizerStorageGLES3::Texture*texture=storage->texture_owner.getornull(p_texture); + + if (!texture) { + state.current_tex=RID(); + state.current_tex_ptr=NULL; + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + return NULL; + } + + if (texture->render_target) + texture->render_target->used_in_frame=true; + + glBindTexture(GL_TEXTURE_2D,texture->tex_id); + state.current_tex=p_texture; + state.current_tex_ptr=texture; + + return texture; + + + } else { + + + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + state.current_tex=RID(); + state.current_tex_ptr=NULL; + } + + + return NULL; +} + +void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable) { + + if (state.using_texture_rect==p_enable) + return; + + if (p_enable) { + glBindVertexArray(data.canvas_quad_array); + + + } else { + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + + } + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT,p_enable); + state.canvas_shader.bind(); + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate); + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,state.extra_matrix); + + + state.using_texture_rect=p_enable; +} + + +void RasterizerCanvasGLES3::_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) { + + bool do_colors=false; + Color m; + if (p_singlecolor) { + m = *p_colors; + glVertexAttrib4f(VS::ARRAY_COLOR,m.r,m.g,m.b,m.a); + } else if (!p_colors) { + + glVertexAttrib4f(VS::ARRAY_COLOR,1,1,1,1); + } else + do_colors=true; + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(p_texture); + +#ifndef GLES_NO_CLIENT_ARRAYS + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(Vector2), p_vertices ); + if (do_colors) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer( VS::ARRAY_COLOR, 4 ,GL_FLOAT, false, sizeof(Color), p_colors ); + } else { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + } + + if (texture && p_uvs) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer( VS::ARRAY_TEX_UV, 2 ,GL_FLOAT, false, sizeof(Vector2), p_uvs ); + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + if (p_indices) { +#ifdef GLEW_ENABLED + glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices ); +#else + static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!! + ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices); + static uint16_t _draw_poly_indices[_max_draw_poly_indices]; + for (int i=0; i<p_vertex_count; i++) { + _draw_poly_indices[i] = p_indices[i]; + }; + glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, _draw_poly_indices ); +#endif + } else { + glDrawArrays(GL_TRIANGLES,0,p_vertex_count); + } + + +#else //WebGL specific impl. + glBindBuffer(GL_ARRAY_BUFFER, gui_quad_buffer); + float *b = GlobalVertexBuffer; + int ofs = 0; + if(p_vertex_count > MAX_POLYGON_VERTICES){ + print_line("Too many vertices to render"); + return; + } + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs ); + for(int i=0;i<p_vertex_count;i++) { + b[ofs++]=p_vertices[i].x; + b[ofs++]=p_vertices[i].y; + } + + if (p_colors && do_colors) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer( VS::ARRAY_COLOR, 4 ,GL_FLOAT, false, sizeof(float)*4, ((float*)0)+ofs ); + for(int i=0;i<p_vertex_count;i++) { + b[ofs++]=p_colors[i].r; + b[ofs++]=p_colors[i].g; + b[ofs++]=p_colors[i].b; + b[ofs++]=p_colors[i].a; + } + + } else { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + } + + + if (p_uvs) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer( VS::ARRAY_TEX_UV, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs ); + for(int i=0;i<p_vertex_count;i++) { + b[ofs++]=p_uvs[i].x; + b[ofs++]=p_uvs[i].y; + } + + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + glBufferSubData(GL_ARRAY_BUFFER,0,ofs*4,&b[0]); + + //bind the indices buffer. + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_buffer); + + static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!! + ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices); + static uint16_t _draw_poly_indices[_max_draw_poly_indices]; + for (int i=0; i<p_vertex_count; i++) { + _draw_poly_indices[i] = p_indices[i]; + //OS::get_singleton()->print("ind: %d ", p_indices[i]); + }; + + //copy the data to GPU. + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, p_vertex_count * sizeof(uint16_t), &_draw_poly_indices[0]); + + //draw the triangles. + glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, 0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#endif + + storage->frame.canvas_draw_commands++; + +} + +void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs) { + + + + static const GLenum prim[5]={GL_POINTS,GL_POINTS,GL_LINES,GL_TRIANGLES,GL_TRIANGLE_FAN}; + + + //#define GLES_USE_PRIMITIVE_BUFFER + +#ifndef GLES_NO_CLIENT_ARRAYS + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(Vector2), p_vertices ); + + if (p_colors) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer( VS::ARRAY_COLOR, 4 ,GL_FLOAT, false, sizeof(Color), p_colors ); + } else { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + } + + if (p_uvs) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer( VS::ARRAY_TEX_UV, 2 ,GL_FLOAT, false, sizeof(Vector2), p_uvs ); + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + glDrawArrays(prim[p_points],0,p_points); + +#else + + glBindBuffer(GL_ARRAY_BUFFER,gui_quad_buffer); + float b[32]; + int ofs=0; + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs ); + for(int i=0;i<p_points;i++) { + b[ofs++]=p_vertices[i].x; + b[ofs++]=p_vertices[i].y; + } + + if (p_colors) { + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer( VS::ARRAY_COLOR, 4 ,GL_FLOAT, false, sizeof(float)*4, ((float*)0)+ofs ); + for(int i=0;i<p_points;i++) { + b[ofs++]=p_colors[i].r; + b[ofs++]=p_colors[i].g; + b[ofs++]=p_colors[i].b; + b[ofs++]=p_colors[i].a; + } + + } else { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + } + + + if (p_uvs) { + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer( VS::ARRAY_TEX_UV, 2 ,GL_FLOAT, false, sizeof(float)*2, ((float*)0)+ofs ); + for(int i=0;i<p_points;i++) { + b[ofs++]=p_uvs[i].x; + b[ofs++]=p_uvs[i].y; + } + + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + glBufferSubData(GL_ARRAY_BUFFER,0,ofs*4,&b[0]); + glDrawArrays(prim[p_points],0,p_points); + glBindBuffer(GL_ARRAY_BUFFER,0); + + +#endif + + storage->frame.canvas_draw_commands++; +} + +void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item,Item *current_clip,bool &reclip) { + + int cc=p_item->commands.size(); + Item::Command **commands = p_item->commands.ptr(); + + + for(int i=0;i<cc;i++) { + + Item::Command *c=commands[i]; + + switch(c->type) { + case Item::Command::TYPE_LINE: { + + + Item::CommandLine* line = static_cast<Item::CommandLine*>(c); + _set_texture_rect_mode(false); + + + _bind_canvas_texture(RID()); + + glVertexAttrib4f(VS::ARRAY_COLOR,line->color.r,line->color.g,line->color.b,line->color.a); + + Vector2 verts[2]={ + Vector2(line->from.x,line->from.y), + Vector2(line->to.x,line->to.y) + }; + +#ifdef GLEW_ENABLED + if (line->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif + glLineWidth(line->width); + _draw_gui_primitive(2,verts,NULL,NULL); + +#ifdef GLEW_ENABLED + if (line->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif + + + } break; + case Item::Command::TYPE_RECT: { + + Item::CommandRect* rect = static_cast<Item::CommandRect*>(c); + + _set_texture_rect_mode(true); + + //set color + glVertexAttrib4f(VS::ARRAY_COLOR,rect->modulate.r,rect->modulate.g,rect->modulate.b,rect->modulate.a); + + RasterizerStorageGLES3::Texture* texture = _bind_canvas_texture(rect->texture); + + if ( texture ) { + + bool untile=false; + + if (rect->flags&CANVAS_RECT_TILE && !(texture->flags&VS::TEXTURE_FLAG_REPEAT)) { + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + untile=true; + } + + Size2 texpixel_size( 1.0/texture->width, 1.0/texture->height ); + Rect2 src_rect = (rect->flags&CANVAS_RECT_REGION) ? Rect2( rect->source.pos * texpixel_size, rect->source.size * texpixel_size ) : Rect2(0,0,1,1); + + if (rect->flags&CANVAS_RECT_FLIP_H) { + src_rect.size.x*=-1; + } + + if (rect->flags&CANVAS_RECT_FLIP_V) { + src_rect.size.x*=-1; + } + + if (rect->flags&CANVAS_RECT_TRANSPOSE) { + //err.. + } + + + glVertexAttrib4f(1,rect->rect.pos.x,rect->rect.pos.y,rect->rect.size.x,rect->rect.size.y); + glVertexAttrib4f(2,src_rect.pos.x,src_rect.pos.y,src_rect.size.x,src_rect.size.y); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + + if (untile) { + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + } + + } else { + + + glVertexAttrib4f(1,rect->rect.pos.x,rect->rect.pos.y,rect->rect.size.x,rect->rect.size.y); + glVertexAttrib4f(2,0,0,1,1); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + + } + + storage->frame.canvas_draw_commands++; + + } break; + + case Item::Command::TYPE_NINEPATCH: { + + Item::CommandNinePatch* np = static_cast<Item::CommandNinePatch*>(c); + + _set_texture_rect_mode(true); + + glVertexAttrib4f(VS::ARRAY_COLOR,np->color.r,np->color.g,np->color.b,np->color.a); + + + RasterizerStorageGLES3::Texture* texture = _bind_canvas_texture(np->texture); + + if ( !texture ) { + + glVertexAttrib4f(1,np->rect.pos.x,np->rect.pos.y,np->rect.size.x,np->rect.size.y); + glVertexAttrib4f(2,0,0,1,1); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + continue; + } + + + Size2 texpixel_size( 1.0/texture->width, 1.0/texture->height ); + +#define DSTRECT(m_x,m_y,m_w,m_h) glVertexAttrib4f(1,m_x,m_y,m_w,m_h) +#define SRCRECT(m_x,m_y,m_w,m_h) glVertexAttrib4f(2,(m_x)*texpixel_size.x,(m_y)*texpixel_size.y,(m_w)*texpixel_size.x,(m_h)*texpixel_size.y) + + //top left + DSTRECT(np->rect.pos.x,np->rect.pos.y,np->margin[MARGIN_LEFT],np->margin[MARGIN_TOP]); + SRCRECT(0,0,np->margin[MARGIN_LEFT],np->margin[MARGIN_TOP]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + //top right + DSTRECT(np->rect.pos.x+np->rect.size.x-np->margin[MARGIN_RIGHT],np->rect.pos.y,np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP]); + SRCRECT(texture->width-np->margin[MARGIN_RIGHT],0,np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + //bottom right + DSTRECT(np->rect.pos.x+np->rect.size.x-np->margin[MARGIN_RIGHT],np->rect.pos.y+np->rect.size.y-np->margin[MARGIN_BOTTOM],np->margin[MARGIN_RIGHT],np->margin[MARGIN_BOTTOM]); + SRCRECT(texture->width-np->margin[MARGIN_RIGHT],texture->height-np->margin[MARGIN_BOTTOM],np->margin[MARGIN_RIGHT],np->margin[MARGIN_BOTTOM]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + //bottom left + DSTRECT(np->rect.pos.x,np->rect.pos.y+np->rect.size.y-np->margin[MARGIN_BOTTOM],np->margin[MARGIN_LEFT],np->margin[MARGIN_BOTTOM]); + SRCRECT(0,texture->height-np->margin[MARGIN_BOTTOM],np->margin[MARGIN_LEFT],np->margin[MARGIN_BOTTOM]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + + //top + DSTRECT(np->rect.pos.x+np->margin[MARGIN_LEFT],np->rect.pos.y,np->rect.size.width-np->margin[MARGIN_LEFT]-np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP]); + SRCRECT(np->margin[MARGIN_LEFT],0,texture->width-np->margin[MARGIN_LEFT]-np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + //bottom + DSTRECT(np->rect.pos.x+np->margin[MARGIN_LEFT],np->rect.pos.y+np->rect.size.y-np->margin[MARGIN_BOTTOM],np->rect.size.width-np->margin[MARGIN_LEFT]-np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP]); + SRCRECT(np->margin[MARGIN_LEFT],texture->height-np->margin[MARGIN_BOTTOM],texture->width-np->margin[MARGIN_LEFT]-np->margin[MARGIN_LEFT],np->margin[MARGIN_TOP]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + + //left + DSTRECT(np->rect.pos.x,np->rect.pos.y+np->margin[MARGIN_TOP],np->margin[MARGIN_LEFT],np->rect.size.height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + SRCRECT(0,np->margin[MARGIN_TOP],np->margin[MARGIN_LEFT],texture->height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + //right + DSTRECT(np->rect.pos.x+np->rect.size.width-np->margin[MARGIN_RIGHT],np->rect.pos.y+np->margin[MARGIN_TOP],np->margin[MARGIN_RIGHT],np->rect.size.height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + SRCRECT(texture->width-np->margin[MARGIN_RIGHT],np->margin[MARGIN_TOP],np->margin[MARGIN_RIGHT],texture->height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + if (np->draw_center) { + + //center + DSTRECT(np->rect.pos.x+np->margin[MARGIN_LEFT],np->rect.pos.y+np->margin[MARGIN_TOP],np->rect.size.x-np->margin[MARGIN_LEFT]-np->margin[MARGIN_RIGHT],np->rect.size.height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + SRCRECT(np->margin[MARGIN_LEFT],np->margin[MARGIN_TOP],texture->width-np->margin[MARGIN_LEFT]-np->margin[MARGIN_RIGHT],texture->height-np->margin[MARGIN_TOP]-np->margin[MARGIN_BOTTOM]); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + } + +#undef SRCRECT +#undef DSTRECT + + storage->frame.canvas_draw_commands++; + } break; + + case Item::Command::TYPE_PRIMITIVE: { + + Item::CommandPrimitive* primitive = static_cast<Item::CommandPrimitive*>(c); + _set_texture_rect_mode(false); + + ERR_CONTINUE( primitive->points.size()<1); + + _bind_canvas_texture(primitive->texture); + + if (primitive->colors.size()==1 && primitive->points.size()>1) { + + Color c = primitive->colors[0]; + glVertexAttrib4f(VS::ARRAY_COLOR,c.r,c.g,c.b,c.a); + + } else if (primitive->colors.empty()) { + glVertexAttrib4f(VS::ARRAY_COLOR,1,1,1,1); + } + + _draw_gui_primitive(primitive->points.size(),primitive->points.ptr(),primitive->colors.ptr(),primitive->uvs.ptr()); + + } break; + case Item::Command::TYPE_POLYGON: { + + Item::CommandPolygon* polygon = static_cast<Item::CommandPolygon*>(c); + _set_texture_rect_mode(false); + _draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + + } break; + case Item::Command::TYPE_CIRCLE: { + + _set_texture_rect_mode(false); + + Item::CommandCircle* circle = static_cast<Item::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; + } + _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 Item::Command::TYPE_TRANSFORM: { + + Item::CommandTransform* transform = static_cast<Item::CommandTransform*>(c); + state.extra_matrix=transform->xform; + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,state.extra_matrix); + + } break; + case Item::Command::TYPE_CLIP_IGNORE: { + + Item::CommandClipIgnore* ci = static_cast<Item::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); + + int x = current_clip->final_clip_rect.pos.x; + int y = storage->frame.current_rt->height - ( current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y ); + int w = current_clip->final_clip_rect.size.x; + int h = current_clip->final_clip_rect.size.y; + + glScissor(x,y,w,h); + + reclip=false; + } + } + } + + + + } break; + } + } +} + +#if 0 +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 + if (current_rt) { + glReadBuffer(GL_COLOR_ATTACHMENT0); + } else { + glReadBuffer(GL_BACK); + } +#endif + if (current_rt) { + glCopyTexSubImage2D(GL_TEXTURE_2D,0,viewport.x,viewport.y,viewport.x,viewport.y,viewport.width,viewport.height); + canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(viewport.y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); + //window_size.height-(viewport.height+viewport.y) + } else { + 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; + +} + +#endif + +void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const Color& p_modulate,Light *p_light) { + + + if (storage->frame.clear_request) { + // a clear request may be pending, so do it + glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a ); + glClear(GL_COLOR_BUFFER_BIT); + storage->frame.clear_request=false; + + + } + + Item *current_clip=NULL; + RasterizerStorageGLES3::Shader *shader_cache=NULL; + + bool rebind_shader=true; + + Size2 rt_size = Size2(storage->frame.current_rt->width,storage->frame.current_rt->height); + + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD,false); + + glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.current_tex=RID(); + state.current_tex_ptr=NULL; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + + + RID canvas_last_material; + + bool prev_distance_field=false; + + while(p_item_list) { + + Item *ci=p_item_list; + + + if (prev_distance_field!=ci->distance_field) { + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD,ci->distance_field); + prev_distance_field=ci->distance_field; + rebind_shader=true; + } + + + if (current_clip!=ci->final_clip_owner) { + + current_clip=ci->final_clip_owner; + + //setup clip + if (current_clip) { + + glEnable(GL_SCISSOR_TEST); + glScissor(current_clip->final_clip_rect.pos.x,(rt_size.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); + + + } else { + + glDisable(GL_SCISSOR_TEST); + } + } +#if 0 + if (ci->copy_back_buffer && framebuffer.active && framebuffer.scale==1) { + + Rect2 rect; + int x,y; + + if (ci->copy_back_buffer->full) { + + x = viewport.x; + y = window_size.height-(viewport.height+viewport.y); + } else { + x = viewport.x+ci->copy_back_buffer->screen_rect.pos.x; + y = window_size.height-(viewport.y+ci->copy_back_buffer->screen_rect.pos.y+ci->copy_back_buffer->screen_rect.size.y); + } + glActiveTexture(GL_TEXTURE0+max_texture_units-1); + glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); + +#ifdef GLEW_ENABLED + if (current_rt) { + glReadBuffer(GL_COLOR_ATTACHMENT0); + } else { + glReadBuffer(GL_BACK); + } +#endif + if (current_rt) { + glCopyTexSubImage2D(GL_TEXTURE_2D,0,viewport.x,viewport.y,viewport.x,viewport.y,viewport.width,viewport.height); + //window_size.height-(viewport.height+viewport.y) + } else { + glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); + } + + canvas_texscreen_used=true; + glActiveTexture(GL_TEXTURE0); + + } + +#endif + + + //begin rect + Item *material_owner = ci->material_owner?ci->material_owner:ci; + + RID material = material_owner->material; + + if (material!=canvas_last_material || rebind_shader) { +#if 0 + Shader *shader = NULL; + 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); + _canvas_item_setup_shader_params(material,shader); + } else { + shader_cache=NULL; + canvas_shader.set_custom_shader(0); + canvas_shader.bind(); + uses_texpixel_size=false; + + } + + + canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX,canvas_transform); + if (canvas_use_modulate) + reset_modulate=true; + canvas_last_material=material; + rebind_shader=false; +#endif + } + + if (material.is_valid() && shader_cache) { +#if 0 + _canvas_item_setup_shader_uniforms(material,shader_cache); +#endif + } + + bool unshaded = false; //(material && material->shading_mode==VS::CANVAS_ITEM_SHADING_UNSHADED) || ci->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX; + bool reclip=false; +#if 0 + if (ci==p_item_list || ci->blend_mode!=canvas_blend_mode) { + + switch(ci->blend_mode) { + + case VS::MATERIAL_BLEND_MODE_MIX: { + 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); + } + + } break; + case VS::MATERIAL_BLEND_MODE_ADD: { + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + } break; + case VS::MATERIAL_BLEND_MODE_SUB: { + + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } break; + case VS::MATERIAL_BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_DST_COLOR,GL_ZERO); + } break; + case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA); + } break; + + } + + canvas_blend_mode=ci->blend_mode; + } +#endif + +// canvas_shader.set_uniform(CanvasShaderGLES3::CANVAS_MODULATE,unshaded ? Color(1,1,1,1) : p_modulate); + + state.canvas_item_modulate = unshaded ? ci->final_modulate : Color( + ci->final_modulate.r * p_modulate.r, + ci->final_modulate.g * p_modulate.g, + ci->final_modulate.b * p_modulate.b, + ci->final_modulate.a * p_modulate.a ); + + state.final_transform = ci->final_transform; + state.extra_matrix=Matrix32(); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate); + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,state.extra_matrix); + + + if (unshaded || (state.canvas_item_modulate.a>0.001 && (!material.is_valid() /*|| material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT*/) && !ci->light_masked )) + _canvas_item_render_commands(ci,current_clip,reclip); + + if (/*canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX &&*/ p_light && !unshaded) { + + Light *light = p_light; + bool light_used=false; + VS::CanvasLightMode mode=VS::CANVAS_LIGHT_MODE_ADD; + state.canvas_item_modulate=ci->final_modulate; // remove the canvas modulate + + + while(light) { + + + if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) { + + //intersects this light + + if (!light_used || mode!=light->mode) { + + mode=light->mode; + + switch(mode) { + + case VS::CANVAS_LIGHT_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + } break; + case VS::CANVAS_LIGHT_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } break; + case VS::CANVAS_LIGHT_MODE_MIX: + case VS::CANVAS_LIGHT_MODE_MASK: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + } break; + } + + } + + if (!light_used) { + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING,true); + light_used=true; + + } + + + bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask&light->item_shadow_mask; + + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS,has_shadow); + if (has_shadow) { + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT,light->shadow_gradient_length>0); + switch(light->shadow_filter) { + + case VS::CANVAS_LIGHT_FILTER_NONE: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST,true); break; + case VS::CANVAS_LIGHT_FILTER_PCF3: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3,true); break; + case VS::CANVAS_LIGHT_FILTER_PCF5: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5,true); break; + case VS::CANVAS_LIGHT_FILTER_PCF9: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9,true); break; + case VS::CANVAS_LIGHT_FILTER_PCF13: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13,true); break; + } + + + } + + bool light_rebind = state.canvas_shader.bind(); + + if (light_rebind) { +#if 0 + if (material && shader_cache) { + _canvas_item_setup_shader_params(material,shader_cache); + _canvas_item_setup_shader_uniforms(material,shader_cache); + } +#endif + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate); + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Matrix32()); + + } + + glBindBufferBase(GL_UNIFORM_BUFFER,1,static_cast<LightInternal*>(light->light_internal.get_data())->ubo); + + if (has_shadow) { + + RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); + glBindTexture(GL_TEXTURE_2D,cls->distance); + + /*canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_MATRIX,light->shadow_matrix_cache); + canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); + canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_SHADOW_COLOR,light->shadow_color);*/ + + } + + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); + RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(light->texture); + if (!t) { + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + } else { + + glBindTexture(t->target,t->tex_id); + } + + glActiveTexture(GL_TEXTURE0); + _canvas_item_render_commands(ci,current_clip,reclip); //redraw using light + + } + + light=light->next_ptr; + } + + if (light_used) { + + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9,false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13,false); + + + state.canvas_shader.bind(); +#if 0 + if (material && shader_cache) { + _canvas_item_setup_shader_params(material,shader_cache); + _canvas_item_setup_shader_uniforms(material,shader_cache); + } +#endif + + state.canvas_item_modulate = unshaded ? ci->final_modulate : Color( + ci->final_modulate.r * p_modulate.r, + ci->final_modulate.g * p_modulate.g, + ci->final_modulate.b * p_modulate.b, + ci->final_modulate.a * p_modulate.a ); + + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Matrix32()); + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate); + + + glBlendEquation(GL_FUNC_ADD); + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + //@TODO RESET canvas_blend_mode + } + + + } + + if (reclip) { + + glEnable(GL_SCISSOR_TEST); + glScissor(current_clip->final_clip_rect.pos.x,(rt_size.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); + + + } + + + + p_item_list=p_item_list->next; + } + + if (current_clip) { + glDisable(GL_SCISSOR_TEST); + } + +} + +void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light* p_lights_with_shadow){ + + Light* light=p_lights_with_shadow; + + canvas_begin(); //reset + glVertexAttrib4f(VS::ARRAY_COLOR,1,1,1,1); + int h = 10; + int w = storage->frame.current_rt->width; + int ofs = h; + glDisable(GL_BLEND); + + //print_line(" debug lights "); + while(light) { + + + // print_line("debug light"); + if (light->shadow_buffer.is_valid()) { + + // print_line("sb is valid"); + RasterizerStorageGLES3::CanvasLightShadow * sb = storage->canvas_light_shadow_owner.get(light->shadow_buffer); + if (sb) { + glBindTexture(GL_TEXTURE_2D,sb->distance); + //glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + draw_generic_textured_rect(Rect2(h,ofs,w-h*2,h),Rect2(0,0,1,1)); + ofs+=h*2; + + } + } + + light=light->shadows_next_ptr; + } +} + + +void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, LightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache) { + + RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); + ERR_FAIL_COND(!cls); + + + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DITHER); + glDisable(GL_CULL_FACE); + glDepthFunc(GL_LEQUAL); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + state.canvas_shadow_shader.bind(); + + glViewport(0, 0, cls->size,cls->height); + glClearDepth(1.0f); + glClearColor(1,1,1,1); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + VS::CanvasOccluderPolygonCullMode cull=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + + + for(int i=0;i<4;i++) { + + //make sure it remains orthogonal, makes easy to read angle later + + Transform light; + light.origin[0]=p_light_xform[2][0]; + light.origin[1]=p_light_xform[2][1]; + light.basis[0][0]=p_light_xform[0][0]; + light.basis[0][1]=p_light_xform[1][0]; + light.basis[1][0]=p_light_xform[0][1]; + light.basis[1][1]=p_light_xform[1][1]; + + //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + + /// p_near=1; + CameraMatrix projection; + { + real_t fov = 90; + real_t 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()); + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::PROJECTION_MATRIX,projection); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::LIGHT_MATRIX,light); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::DISTANCE_NORM,1.0/p_far); + + + if (i==0) + *p_xform_cache=projection; + + glViewport(0, (cls->height/4)*i, cls->size,cls->height/4); + + LightOccluderInstance *instance=p_occluders; + + while(instance) { + + RasterizerStorageGLES3::CanvasOccluder *cc = storage->canvas_occluder_owner.get(instance->polygon_buffer); + if (!cc || cc->len==0 || !(p_light_mask&instance->light_mask)) { + + instance=instance->next; + continue; + } + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::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); +} +void RasterizerCanvasGLES3::reset_canvas() { + + + if (storage->frame.current_rt) { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->front.fbo); + glColorMask(1,1,1,1); //don't touch alpha + } + + + glBindVertexArray(0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); +#ifdef GLEW_ENABLED + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + //glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glLineWidth(1.0); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + for(int i=0;i<VS::ARRAY_MAX;i++) { + glDisableVertexAttribArray(i); + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture( GL_TEXTURE_2D, storage->resources.white_tex ); + + + glVertexAttrib4f(VS::ARRAY_COLOR,1,1,1,1); + + Transform canvas_transform; + + if (storage->frame.current_rt) { + + float csy = 1.0; + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + csy = -1.0; + } + canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f); + canvas_transform.scale( Vector3( 2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f ) ); + } else { + Vector2 ssize = OS::get_singleton()->get_window_size(); + canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); + canvas_transform.scale( Vector3( 2.0f / ssize.width, -2.0f / ssize.height, 1.0f ) ); + + } + + state.vp=canvas_transform; + + store_transform(canvas_transform,state.canvas_item_ubo_data.projection_matrix); + + glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + + state.canvas_texscreen_used=false; + + +} + + +void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2& p_rect, const Rect2& p_src) { + + + glVertexAttrib4f(1,p_rect.pos.x,p_rect.pos.y,p_rect.size.x,p_rect.size.y); + glVertexAttrib4f(2,p_src.pos.x,p_src.pos.y,p_src.size.x,p_src.size.y); + glDrawArrays(GL_TRIANGLE_FAN,0,4); +} + +void RasterizerCanvasGLES3::initialize() { + + + { + //quad buffers + + glGenBuffers(1,&data.canvas_quad_vertices); + glBindBuffer(GL_ARRAY_BUFFER,data.canvas_quad_vertices); + { + const float qv[8]={ + 0,0, + 0,1, + 1,1, + 1,0 + }; + + glBufferData(GL_ARRAY_BUFFER,sizeof(float)*8,qv,GL_STATIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + + glGenVertexArrays(1,&data.canvas_quad_array); + glBindVertexArray(data.canvas_quad_array); + glBindBuffer(GL_ARRAY_BUFFER,data.canvas_quad_vertices); + glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,sizeof(float)*2,0); + glEnableVertexAttribArray(0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + } + + + store_transform(Transform(),state.canvas_item_ubo_data.projection_matrix); + + + + glGenBuffers(1, &state.canvas_item_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.canvas_shader.init(); + state.canvas_shadow_shader.init(); + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS,storage->config.use_rgba_2d_shadows); + state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS,storage->config.use_rgba_2d_shadows); + + +} + + +void RasterizerCanvasGLES3::finalize() { + + glDeleteBuffers(1,&data.canvas_quad_vertices); + glDeleteVertexArrays(1,&data.canvas_quad_array); +} + +RasterizerCanvasGLES3::RasterizerCanvasGLES3() +{ + +} diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h new file mode 100644 index 0000000000..1f72a8dbcf --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -0,0 +1,102 @@ +#ifndef RASTERIZERCANVASGLES3_H +#define RASTERIZERCANVASGLES3_H + +#include "servers/visual/rasterizer.h" +#include "rasterizer_storage_gles3.h" +#include "shaders/canvas_shadow.glsl.h" + +class RasterizerCanvasGLES3 : public RasterizerCanvas { +public: + + struct CanvasItemUBO { + + float projection_matrix[16]; + + }; + + struct Data { + + GLuint canvas_quad_vertices; + GLuint canvas_quad_array; + + } data; + + struct State { + CanvasItemUBO canvas_item_ubo_data; + GLuint canvas_item_ubo; + bool canvas_texscreen_used; + CanvasShaderGLES3 canvas_shader; + CanvasShadowShaderGLES3 canvas_shadow_shader; + + bool using_texture_rect; + + + RID current_tex; + RasterizerStorageGLES3::Texture *current_tex_ptr; + + Transform vp; + + Color canvas_item_modulate; + Matrix32 extra_matrix; + Matrix32 final_transform; + + } state; + + RasterizerStorageGLES3 *storage; + + struct LightInternal : public RID_Data { + + struct UBOData { + + float light_matrix[16]; + float local_matrix[16]; + float shadow_matrix[16]; + float color[4]; + float shadow_color[4]; + float light_pos[2]; + float shadowpixel_size; + float shadow_gradient; + float light_height; + float light_outside_alpha; + float shadow_distance_mult; + } ubo_data; + + GLuint ubo; + }; + + RID_Owner<LightInternal> light_internal_owner; + + virtual RID light_internal_create(); + virtual void light_internal_update(RID p_rid, Light* p_light); + virtual void light_internal_free(RID p_rid); + + + virtual void canvas_begin(); + virtual void canvas_end(); + + _FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable); + _FORCE_INLINE_ RasterizerStorageGLES3::Texture* _bind_canvas_texture(const RID& p_texture); + + _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_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); + _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item,Item *current_clip,bool &reclip); + + + virtual void canvas_render_items(Item *p_item_list,int p_z,const Color& p_modulate,Light *p_light); + virtual void canvas_debug_viewport_shadows(Light* p_lights_with_shadow); + + 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, LightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache); + + + virtual void reset_canvas(); + + void draw_generic_textured_rect(const Rect2& p_rect, const Rect2& p_src); + + + void initialize(); + void finalize(); + + RasterizerCanvasGLES3(); +}; + +#endif // RASTERIZERCANVASGLES3_H diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp new file mode 100644 index 0000000000..ba83a572e5 --- /dev/null +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -0,0 +1,266 @@ +#include "rasterizer_gles3.h" +#include "os/os.h" +#include "globals.h" +#include "gl_context/context_gl.h" +#include <string.h> +RasterizerStorage *RasterizerGLES3::get_storage() { + + return storage; +} + +RasterizerCanvas *RasterizerGLES3::get_canvas() { + + return canvas; +} + +RasterizerScene *RasterizerGLES3::get_scene() { + + return NULL; +} + + +static void _gl_debug_print(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam) +{ + + if (type==GL_DEBUG_TYPE_OTHER_ARB) + return; + + print_line("mesege"); + char debSource[256], debType[256], debSev[256]; + if(source == GL_DEBUG_SOURCE_API_ARB) + strcpy(debSource, "OpenGL"); + else if(source == GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) + strcpy(debSource, "Windows"); + else if(source == GL_DEBUG_SOURCE_SHADER_COMPILER_ARB) + strcpy(debSource, "Shader Compiler"); + else if(source == GL_DEBUG_SOURCE_THIRD_PARTY_ARB) + strcpy(debSource, "Third Party"); + else if(source == GL_DEBUG_SOURCE_APPLICATION_ARB) + strcpy(debSource, "Application"); + else if(source == GL_DEBUG_SOURCE_OTHER_ARB) + strcpy(debSource, "Other"); + + if(type == GL_DEBUG_TYPE_ERROR_ARB) + strcpy(debType, "Error"); + else if(type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB) + strcpy(debType, "Deprecated behavior"); + else if(type == GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB) + strcpy(debType, "Undefined behavior"); + else if(type == GL_DEBUG_TYPE_PORTABILITY_ARB) + strcpy(debType, "Portability"); + else if(type == GL_DEBUG_TYPE_PERFORMANCE_ARB) + strcpy(debType, "Performance"); + else if(type == GL_DEBUG_TYPE_OTHER_ARB) + strcpy(debType, "Other"); + + if(severity == GL_DEBUG_SEVERITY_HIGH_ARB) + strcpy(debSev, "High"); + else if(severity == GL_DEBUG_SEVERITY_MEDIUM_ARB) + strcpy(debSev, "Medium"); + else if(severity == GL_DEBUG_SEVERITY_LOW_ARB) + strcpy(debSev, "Low"); + + String output = String()+ "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; + + ERR_PRINTS(output); + +} + + +void RasterizerGLES3::initialize() { + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("Using GLES3 video driver"); + } + +#ifdef GLEW_ENABLED + GLuint res = glewInit(); + ERR_FAIL_COND(res!=GLEW_OK); + if (OS::get_singleton()->is_stdout_verbose()) { + print_line(String("GLES2: Using GLEW ") + (const char*) glewGetString(GLEW_VERSION)); + } + + // Check for GL 2.1 compatibility, if not bail out + if (!glewIsSupported("GL_VERSION_3_0")) { + ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 3.0+ / GLES 3.0, sorry :(\n" + "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault."); + OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 3.0+ / GLES 3.0, sorry :(\n" + "Godot Engine will self-destruct as soon as you acknowledge this error message.", + "Fatal error: Insufficient OpenGL / GLES drivers"); + // TODO: If it's even possible, we should stop the execution without segfault and memory leaks :) + } +#endif + + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageCallbackARB(_gl_debug_print, NULL); + glEnable(GL_DEBUG_OUTPUT); + + +/* glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_ERROR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PORTABILITY_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_PERFORMANCE_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB,GL_DEBUG_TYPE_OTHER_ARB,GL_DEBUG_SEVERITY_HIGH_ARB,0,NULL,GL_TRUE); + glDebugMessageInsertARB( + + GL_DEBUG_SOURCE_API_ARB, + GL_DEBUG_TYPE_OTHER_ARB, 1, + GL_DEBUG_SEVERITY_HIGH_ARB,5, "hello"); + +*/ + storage->initialize(); + canvas->initialize(); +} + +void RasterizerGLES3::begin_frame(){ + + +} +void RasterizerGLES3::set_current_render_target(RID p_render_target){ + + if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) { + //handle pending clear request, if the framebuffer was not cleared + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); + glClearColor( + storage->frame.clear_request_color.r, + storage->frame.clear_request_color.g, + storage->frame.clear_request_color.b, + storage->frame.clear_request_color.a ); + + glClear(GL_COLOR_BUFFER_BIT); + + } + + if (p_render_target.is_valid()) { + RasterizerStorageGLES3::RenderTarget * rt = storage->render_target_owner.getornull(p_render_target); + if (!rt) { + storage->frame.current_rt=NULL; + } + ERR_FAIL_COND(!rt); + storage->frame.current_rt=rt; + storage->frame.clear_request=false; + + glViewport(0,0,rt->width,rt->height); + + } else { + storage->frame.current_rt=NULL; + storage->frame.clear_request=false; + glViewport(0,0,OS::get_singleton()->get_window_size().width,OS::get_singleton()->get_window_size().height); + glBindFramebuffer(GL_FRAMEBUFFER,storage->config.system_fbo); + } +} + +void RasterizerGLES3::restore_render_target() { + + ERR_FAIL_COND(storage->frame.current_rt==NULL); + RasterizerStorageGLES3::RenderTarget * rt = storage->frame.current_rt; + glViewport(0,0,rt->width,rt->height); + +} + +void RasterizerGLES3::clear_render_target(const Color& p_color) { + + ERR_FAIL_COND(!storage->frame.current_rt); + + storage->frame.clear_request=true; + storage->frame.clear_request_color=p_color; + +} + +void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target,const Rect2& p_screen_rect,int p_screen){ + + ERR_FAIL_COND( storage->frame.current_rt ); + + RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + canvas->canvas_begin(); + glBindFramebuffer(GL_FRAMEBUFFER,storage->config.system_fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,rt->front.color); + canvas->draw_generic_textured_rect(p_screen_rect,Rect2(0,0,1,-1)); + glBindTexture(GL_TEXTURE_2D,0); + canvas->canvas_end(); +} + +void RasterizerGLES3::end_frame(){ + +#if 0 + canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + + float vtx[8]={0,0, + 0,1, + 1,1, + 1,0 + }; + + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, 0, vtx ); + + +// glBindBuffer(GL_ARRAY_BUFFER,canvas->data.canvas_quad_vertices); +// glEnableVertexAttribArray(VS::ARRAY_VERTEX); +// glVertexAttribPointer( VS::ARRAY_VERTEX, 2 ,GL_FLOAT, false, 0, 0 ); + + glBindVertexArray(canvas->data.canvas_quad_array); + + canvas->draw_generic_textured_rect(Rect2(0,0,15,15),Rect2(0,0,1,1)); +#endif + if (ContextGL::get_singleton()) + ContextGL::get_singleton()->swap_buffers(); +} + +void RasterizerGLES3::finalize(){ + + storage->finalize(); + canvas->finalize(); +} + + +Rasterizer *RasterizerGLES3::_create_current() { + + return memnew( RasterizerGLES3 ); +} + +void RasterizerGLES3::make_current() { + _create_func=_create_current; +} + + +void RasterizerGLES3::register_config() { + + GLOBAL_DEF("rendering/gles3/framebuffer_format",RasterizerStorageGLES3::FBO_FORMAT_FLOAT); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/framebuffer_format",PropertyInfo(Variant::INT,"",PROPERTY_HINT_ENUM,"16 Bits,32 Bits,Half Float")); + GLOBAL_DEF("rendering/gles3/lighting_technique",1); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/lighting_technique",PropertyInfo(Variant::INT,"",PROPERTY_HINT_ENUM,"Forward,Deferred")); + GLOBAL_DEF("rendering/gles3/use_nearest_mipmap_filter",false); + GLOBAL_DEF("rendering/gles3/anisotropic_filter_level",4.0); + + +} + +RasterizerGLES3::RasterizerGLES3() +{ + + storage = memnew( RasterizerStorageGLES3 ); + canvas = memnew( RasterizerCanvasGLES3 ); + canvas->storage=storage; + + +} + +RasterizerGLES3::~RasterizerGLES3() { + + memdelete(storage); + memdelete(canvas); +} diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h new file mode 100644 index 0000000000..d461664ea2 --- /dev/null +++ b/drivers/gles3/rasterizer_gles3.h @@ -0,0 +1,38 @@ +#ifndef RASTERIZERGLES3_H +#define RASTERIZERGLES3_H + +#include "servers/visual/rasterizer.h" +#include "rasterizer_storage_gles3.h" +#include "rasterizer_canvas_gles3.h" + + +class RasterizerGLES3 : public Rasterizer { + + static Rasterizer *_create_current(); + + RasterizerStorageGLES3 *storage; + RasterizerCanvasGLES3 *canvas; +public: + + virtual RasterizerStorage *get_storage(); + virtual RasterizerCanvas *get_canvas(); + virtual RasterizerScene *get_scene(); + + virtual void initialize(); + virtual void begin_frame(); + virtual void set_current_render_target(RID p_render_target); + virtual void restore_render_target(); + virtual void clear_render_target(const Color& p_color); + virtual void blit_render_target_to_screen(RID p_render_target,const Rect2& p_screen_rect,int p_screen=0); + virtual void end_frame(); + virtual void finalize(); + + static void make_current(); + + + static void register_config(); + RasterizerGLES3(); + ~RasterizerGLES3(); +}; + +#endif // RASTERIZERGLES3_H diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp new file mode 100644 index 0000000000..b29de876a4 --- /dev/null +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -0,0 +1,2045 @@ +#include "rasterizer_storage_gles3.h" +#include "globals.h" + +/* TEXTURE API */ + +#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 + +#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 + + +#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 + +#define _EXT_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define _EXT_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define _EXT_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define _EXT_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 + + +#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#define _EXT_ETC1_RGB8_OES 0x8D64 + + + +#define _EXT_SLUMINANCE_NV 0x8C46 +#define _EXT_SLUMINANCE_ALPHA_NV 0x8C44 +#define _EXT_SRGB8_NV 0x8C41 +#define _EXT_SLUMINANCE8_NV 0x8C47 +#define _EXT_SLUMINANCE8_ALPHA8_NV 0x8C45 + + +#define _EXT_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C +#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D +#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E +#define _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F + + + +#define _EXT_ATC_RGB_AMD 0x8C92 +#define _EXT_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define _EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE + + +#define _TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define _DECODE_EXT 0x8A49 +#define _SKIP_DECODE_EXT 0x8A4A + + +#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + + + +Image RasterizerStorageGLES3::_get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,GLenum& r_gl_internal_format,GLenum &r_gl_type,bool &r_compressed,bool &srgb) { + + + r_compressed=false; + r_gl_format=0; + Image image=p_image; + srgb=false; + + bool need_decompress=false; + + switch(p_format) { + + case Image::FORMAT_L8: { + r_gl_internal_format=GL_LUMINANCE; + r_gl_format=GL_LUMINANCE; + r_gl_type=GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_LA8: { + + r_gl_internal_format=GL_LUMINANCE_ALPHA; + r_gl_format=GL_LUMINANCE_ALPHA; + r_gl_type=GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_R8: { + + r_gl_internal_format=GL_R8; + r_gl_format=GL_RED; + r_gl_type=GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_RG8: { + + r_gl_internal_format=GL_RG8; + r_gl_format=GL_RG; + r_gl_type=GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_RGB8: { + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_SRGB8:GL_RGB8; + r_gl_format=GL_RGB; + r_gl_type=GL_UNSIGNED_BYTE; + srgb=true; + + } break; + case Image::FORMAT_RGBA8: { + + r_gl_format=GL_RGBA; + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_SRGB8_ALPHA8:GL_RGBA8; + r_gl_type=GL_UNSIGNED_BYTE; + srgb=true; + + } break; + case Image::FORMAT_RGB565: { + + r_gl_internal_format=GL_RGB565; + r_gl_format=GL_RGB; + r_gl_type=GL_UNSIGNED_SHORT_5_6_5; + + } break; + case Image::FORMAT_RGBA4444: { + + r_gl_internal_format=GL_RGBA4; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_SHORT_4_4_4_4; + + } break; + case Image::FORMAT_RGBA5551: { + + r_gl_internal_format=GL_RGB5_A1; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_SHORT_5_5_5_1; + + + } break; + case Image::FORMAT_RF: { + + + r_gl_internal_format=GL_R32F; + r_gl_format=GL_RED; + r_gl_type=GL_FLOAT; + + } break; + case Image::FORMAT_RGF: { + + r_gl_internal_format=GL_RG32F; + r_gl_format=GL_RG; + r_gl_type=GL_FLOAT; + + } break; + case Image::FORMAT_RGBF: { + + r_gl_internal_format=GL_RGB32F; + r_gl_format=GL_RGB; + r_gl_type=GL_FLOAT; + + } break; + case Image::FORMAT_RGBAF: { + + r_gl_internal_format=GL_RGBA32F; + r_gl_format=GL_RGBA; + r_gl_type=GL_FLOAT; + + } break; + case Image::FORMAT_RH: { + r_gl_internal_format=GL_R32F; + r_gl_format=GL_RED; + r_gl_type=GL_HALF_FLOAT; + } break; + case Image::FORMAT_RGH: { + r_gl_internal_format=GL_RG32F; + r_gl_format=GL_RG; + r_gl_type=GL_HALF_FLOAT; + + } break; + case Image::FORMAT_RGBH: { + r_gl_internal_format=GL_RGB32F; + r_gl_format=GL_RGB; + r_gl_type=GL_HALF_FLOAT; + + } break; + case Image::FORMAT_RGBAH: { + r_gl_internal_format=GL_RGBA32F; + r_gl_format=GL_RGBA; + r_gl_type=GL_HALF_FLOAT; + + } break; + case Image::FORMAT_DXT1: { + + if (config.s3tc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + } break; + case Image::FORMAT_DXT3: { + + + if (config.s3tc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + } break; + case Image::FORMAT_DXT5: { + + if (config.s3tc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV:_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + } break; + case Image::FORMAT_ATI1: { + + if (config.latc_supported) { + + + r_gl_internal_format=_EXT_COMPRESSED_LUMINANCE_LATC1_EXT; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + + } break; + case Image::FORMAT_ATI2: { + + if (config.latc_supported) { + + + r_gl_internal_format=_EXT_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + } else { + + need_decompress=true; + } + + } break; + case Image::FORMAT_BPTC_RGBA: { + + if (config.bptc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:GL_COMPRESSED_RGBA_BPTC_UNORM; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_BPTC_RGBF: { + + if (config.bptc_supported) { + + + r_gl_internal_format=GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; + r_gl_format=GL_RGB; + r_gl_type=GL_FLOAT; + r_compressed=true; + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_BPTC_RGBFU: { + if (config.bptc_supported) { + + + r_gl_internal_format=GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; + r_gl_format=GL_RGB; + r_gl_type=GL_FLOAT; + r_compressed=true; + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_PVRTC2: { + + if (config.pvrtc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT:_EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_PVRTC2A: { + + if (config.pvrtc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT:_EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + } break; + case Image::FORMAT_PVRTC4: { + + if (config.pvrtc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT:_EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + } break; + case Image::FORMAT_PVRTC4A: { + + if (config.pvrtc_supported) { + + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?_EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT:_EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + } else { + + need_decompress=true; + } + + + } break; + case Image::FORMAT_ETC: { + + if (config.etc_supported) { + + r_gl_internal_format=_EXT_ETC1_RGB8_OES; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + + } else { + + need_decompress=true; + } + + } break; + case Image::FORMAT_ETC2_R11: { + + if (config.etc2_supported) { + + r_gl_internal_format=GL_COMPRESSED_R11_EAC; + r_gl_format=GL_RED; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_R11S: { + + if (config.etc2_supported) { + + r_gl_internal_format=GL_COMPRESSED_SIGNED_R11_EAC; + r_gl_format=GL_RED; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_RG11: { + + if (config.etc2_supported) { + + r_gl_internal_format=GL_COMPRESSED_RG11_EAC; + r_gl_format=GL_RG; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_RG11S: { + if (config.etc2_supported) { + + r_gl_internal_format=GL_COMPRESSED_SIGNED_RG11_EAC; + r_gl_format=GL_RG; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + + } else { + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_RGB8: { + + if (config.etc2_supported) { + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_COMPRESSED_SRGB8_ETC2:GL_COMPRESSED_RGB8_ETC2; + r_gl_format=GL_RGB; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_RGBA8: { + + if (config.etc2_supported) { + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:GL_COMPRESSED_RGBA8_ETC2_EAC; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + + } else { + + need_decompress=true; + } + } break; + case Image::FORMAT_ETC2_RGB8A1: { + + if (config.etc2_supported) { + + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + r_gl_format=GL_RGBA; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=true; + srgb=true; + + + } else { + + need_decompress=true; + } + } break; + default: { + + ERR_FAIL_V(Image()); + } + } + + if (need_decompress) { + + if (!image.empty()) { + image.decompress(); + ERR_FAIL_COND_V(image.is_compressed(),image); + image.convert(Image::FORMAT_RGBA8); + } + + + r_gl_format=GL_RGBA; + r_gl_internal_format=(config.srgb_decode_supported || p_flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)?GL_SRGB8_ALPHA8:GL_RGBA8; + r_gl_type=GL_UNSIGNED_BYTE; + r_compressed=false; + srgb=true; + + return image; + + } + + + return image; +} + +static const GLenum _cube_side_enum[6]={ + + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + +}; + +RID RasterizerStorageGLES3::texture_create() { + + Texture *texture = memnew(Texture); + ERR_FAIL_COND_V(!texture,RID()); + glGenTextures(1, &texture->tex_id); + texture->active=false; + texture->total_data_size=0; + + return texture_owner.make_rid( texture ); + +} + +void RasterizerStorageGLES3::texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags) { + + int components; + GLenum format; + GLenum internal_format; + GLenum type; + + bool compressed; + bool srgb; + + if (p_flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + p_flags&=~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video + } + + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + texture->width=p_width; + texture->height=p_height; + texture->format=p_format; + texture->flags=p_flags; + texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + + _get_gl_image_and_format(Image(),texture->format,texture->flags,format,internal_format,type,compressed,srgb); + + texture->alloc_width = texture->width; + texture->alloc_height = texture->height; + + + texture->gl_format_cache=format; + texture->gl_type_cache=type; + texture->gl_internal_format_cache=internal_format; + texture->compressed=compressed; + texture->srgb=srgb; + texture->data_size=0; + texture->mipmaps=1; + + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + + if (p_flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + //prealloc if video + glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type,NULL); + } + + texture->active=true; +} + +void RasterizerStorageGLES3::texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(!texture->active); + ERR_FAIL_COND(texture->render_target); + ERR_FAIL_COND(texture->format != p_image.get_format() ); + ERR_FAIL_COND( p_image.empty() ); + + GLenum type; + GLenum format; + GLenum internal_format; + bool compressed; + bool srgb; + + + Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,internal_format,type,compressed,srgb); + + if (config.shrink_textures_x2 && (p_image.has_mipmaps() || !p_image.is_compressed()) && !(texture->flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { + + texture->alloc_height = MAX(1,texture->alloc_height/2); + texture->alloc_width = MAX(1,texture->alloc_width/2); + + if (texture->alloc_width == img.get_width()/2 && texture->alloc_height == img.get_height()/2) { + + img.shrink_x2(); + } else if (img.get_format() <= Image::FORMAT_RGB565) { + + img.resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); + + } + }; + + + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP)?_cube_side_enum[p_cube_side]:GL_TEXTURE_2D; + + texture->data_size=img.get_data().size(); + DVector<uint8_t>::Read read = img.get_data().read(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + texture->ignore_mipmaps = compressed && !img.has_mipmaps(); + + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,config.use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); + else { + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + } else { + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + } + } + + + if (config.srgb_decode_supported && srgb) { + + if (texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { + + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + } else { + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + } + } + + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering + + } else { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering + } + + if ((texture->flags&VS::TEXTURE_FLAG_REPEAT || texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) { + + if (texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT){ + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT ); + } + else{ + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + } + } else { + + //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + } + + if (config.use_anisotropic_filter) { + + if (texture->flags&VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) { + + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level); + } else { + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); + } + } + + int mipmaps= (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && img.has_mipmaps()) ? img.get_mipmap_count() +1: 1; + + + int w=img.get_width(); + int h=img.get_height(); + + int tsize=0; + for(int i=0;i<mipmaps;i++) { + + int size,ofs; + img.get_mipmap_offset_and_size(i,ofs,size); + + //print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h)); + + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glCompressedTexImage2D( blit_target, i, format,w,h,0,size,&read[ofs] ); + + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + glTexSubImage2D( blit_target, i, 0,0,w, h,format,type,&read[ofs] ); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type,&read[ofs]); + } + + } + tsize+=size; + + w = MAX(1,w>>1); + h = MAX(1,h>>1); + + } + + info.texture_mem-=texture->total_data_size; + texture->total_data_size=tsize; + info.texture_mem+=texture->total_data_size; + + //printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem); + + + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && mipmaps==1 && !texture->ignore_mipmaps) { + //generate mipmaps if they were requested and the image does not contain them + glGenerateMipmap(texture->target); + } + + texture->mipmaps=mipmaps; + + //texture_set_flags(p_texture,texture->flags); + + +} + +Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image()); + ERR_FAIL_COND_V(!texture->active,Image()); + ERR_FAIL_COND_V(texture->data_size==0,Image()); + ERR_FAIL_COND_V(texture->render_target,Image()); + +#ifdef GLEW_ENABLED + + DVector<uint8_t> data; + + int data_size = Image::get_image_data_size(texture->width,texture->height,texture->format,texture->mipmaps>1?-1:0); + + data.resize(data_size); + DVector<uint8_t>::Write wb = data.write(); + + glActiveTexture(GL_TEXTURE0); + + glBindTexture(texture->target,texture->tex_id); + + for(int i=0;i<texture->mipmaps;i++) { + + int ofs=0; + if (i>0) { + ofs=Image::get_image_data_size(texture->alloc_width,texture->alloc_height,texture->format,i-1); + } + + if (texture->compressed) { + + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glGetCompressedTexImage(texture->target,i,&wb[ofs]); + + } else { + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(texture->target,i,texture->gl_format_cache,texture->gl_type_cache,&wb[ofs]); + } + } + + + wb=DVector<uint8_t>::Write(); + + Image img(texture->alloc_width,texture->alloc_height,texture->mipmaps>1?true:false,texture->format,data); + + return img; +#else + + ERR_EXPLAIN("Sorry, It's not posible to obtain images back in OpenGL ES"); +#endif +} + +void RasterizerStorageGLES3::texture_set_flags(RID p_texture,uint32_t p_flags) { + + Texture *texture = texture_owner.get( p_texture ); + ERR_FAIL_COND(!texture); + if (texture->render_target) { + + p_flags&=VS::TEXTURE_FLAG_FILTER;//can change only filter + } + + bool had_mipmaps = texture->flags&VS::TEXTURE_FLAG_MIPMAPS; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; + texture->flags=p_flags|cube; // can't remove a cube from being a cube + + + if ((texture->flags&VS::TEXTURE_FLAG_REPEAT || texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) { + + if (texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT){ + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT ); + } + else { + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + } + } else { + //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + } + + + if (config.use_anisotropic_filter) { + + if (texture->flags&VS::TEXTURE_FLAG_ANISOTROPIC_FILTER) { + + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level); + } else { + glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); + } + } + + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) { + if (!had_mipmaps && texture->mipmaps==1) { + glGenerateMipmap(texture->target); + } + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,config.use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR); + + } else{ + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + } else { + glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + } + } + + + if (config.srgb_decode_supported && texture->srgb) { + + if (texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { + + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + } else { + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + } + } + + if (texture->flags&VS::TEXTURE_FLAG_FILTER) { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering + + } else { + + glTexParameteri(texture->target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // raw Filtering + } + +} +uint32_t RasterizerStorageGLES3::texture_get_flags(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->flags; + +} +Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,Image::FORMAT_L8); + + return texture->format; +} +uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->width; +} +uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture,0); + + return texture->height; +} + + +void RasterizerStorageGLES3::texture_set_size_override(RID p_texture,int p_width, int p_height) { + + Texture * texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(texture->render_target); + + ERR_FAIL_COND(p_width<=0 || p_width>16384); + ERR_FAIL_COND(p_height<=0 || p_height>16384); + //real texture size is in alloc width and height + texture->width=p_width; + texture->height=p_height; + +} + +void RasterizerStorageGLES3::texture_set_path(RID p_texture,const String& p_path) { + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND(!texture); + + texture->path=p_path; + +} + +String RasterizerStorageGLES3::texture_get_path(RID p_texture) const{ + + Texture * texture = texture_owner.get(p_texture); + ERR_FAIL_COND_V(!texture,String()); + return texture->path; +} +void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info){ + + List<RID> textures; + texture_owner.get_owned_list(&textures); + + for (List<RID>::Element *E=textures.front();E;E=E->next()) { + + Texture *t = texture_owner.get(E->get()); + if (!t) + continue; + VS::TextureInfo tinfo; + tinfo.path=t->path; + tinfo.format=t->format; + tinfo.size.x=t->alloc_width; + tinfo.size.y=t->alloc_height; + tinfo.bytes=t->total_data_size; + r_info->push_back(tinfo); + } + +} + +void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable) { + + config.shrink_textures_x2=p_enable; +} + + + +/* SHADER API */ + + +RID RasterizerStorageGLES3::shader_create(VS::ShaderMode p_mode){ + + return RID(); +} + +void RasterizerStorageGLES3::shader_set_mode(RID p_shader,VS::ShaderMode p_mode){ + + +} +VS::ShaderMode RasterizerStorageGLES3::shader_get_mode(RID p_shader) const { + + return VS::SHADER_SPATIAL; +} +void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String& p_code){ + + +} +String RasterizerStorageGLES3::shader_get_code(RID p_shader) const{ + + return String(); +} +void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const{ + + +} + +void RasterizerStorageGLES3::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture){ + + +} +RID RasterizerStorageGLES3::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{ + + return RID(); +} + + +/* COMMON MATERIAL API */ + +RID RasterizerStorageGLES3::material_create(){ + + return RID(); +} + +void RasterizerStorageGLES3::material_set_shader(RID p_shader_material, RID p_shader){ + + +} +RID RasterizerStorageGLES3::material_get_shader(RID p_shader_material) const{ + + return RID(); +} + +void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value){ + + +} +Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringName& p_param) const{ + + return Variant(); +} + +/* MESH API */ + +RID RasterizerStorageGLES3::mesh_create(){ + + return RID(); +} + +void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes){ + + +} + +void RasterizerStorageGLES3::mesh_set_morph_target_count(RID p_mesh,int p_amount){ + + +} +int RasterizerStorageGLES3::mesh_get_morph_target_count(RID p_mesh) const{ + + return 0; +} + + +void RasterizerStorageGLES3::mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode){ + + +} +VS::MorphTargetMode RasterizerStorageGLES3::mesh_get_morph_target_mode(RID p_mesh) const{ + + return VS::MORPH_MODE_NORMALIZED; +} + +void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material){ + + +} +RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{ + + return RID(); +} + +int RasterizerStorageGLES3::mesh_surface_get_array_len(RID p_mesh, int p_surface) const{ + + return 0; +} +int RasterizerStorageGLES3::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const{ + + + return 0; +} + +DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int p_surface) const{ + + return DVector<uint8_t>(); +} +DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh, int p_surface) const{ + + + return DVector<uint8_t>(); +} + + +uint32_t RasterizerStorageGLES3::mesh_surface_get_format(RID p_mesh, int p_surface) const{ + + return 0; +} +VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const{ + + return VS::PRIMITIVE_MAX; +} + +void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh,int p_index){ + + +} +int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const{ + + return 0; +} + +void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb){ + + +} +AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const{ + + return AABB(); +} + +AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh) const{ + + return AABB(); +} +void RasterizerStorageGLES3::mesh_clear(RID p_mesh){ + + +} + +/* MULTIMESH API */ + + +RID RasterizerStorageGLES3::multimesh_create(){ + + return RID(); +} + +void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb){ + + +} +int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const{ + + return 0; +} + +void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh,RID p_mesh){ + + +} +void RasterizerStorageGLES3::multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb){ + + +} +void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){ + + +} +void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform){ + + +} +void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color){ + + +} + +RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const{ + + + return RID(); +} +AABB RasterizerStorageGLES3::multimesh_get_custom_aabb(RID p_multimesh,const AABB& p_aabb) const{ + + return AABB(); +} + +Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh,int p_index) const{ + + return Transform(); +} +Matrix32 RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const{ + + + return Matrix32(); +} +Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p_index) const{ + + return Color(); +} + +void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh,int p_visible){ + + +} +int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const{ + + return 0; +} + +AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_mesh) const{ + + return AABB(); +} + +/* IMMEDIATE API */ + +RID RasterizerStorageGLES3::immediate_create(){ + + return RID(); +} +void RasterizerStorageGLES3::immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture){ + + +} +void RasterizerStorageGLES3::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + + +} +void RasterizerStorageGLES3::immediate_vertex_2d(RID p_immediate,const Vector3& p_vertex){ + + +} +void RasterizerStorageGLES3::immediate_normal(RID p_immediate,const Vector3& p_normal){ + + +} +void RasterizerStorageGLES3::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + + +} +void RasterizerStorageGLES3::immediate_color(RID p_immediate,const Color& p_color){ + + +} +void RasterizerStorageGLES3::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + + +} +void RasterizerStorageGLES3::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + + +} +void RasterizerStorageGLES3::immediate_end(RID p_immediate){ + + +} +void RasterizerStorageGLES3::immediate_clear(RID p_immediate){ + + +} +void RasterizerStorageGLES3::immediate_set_material(RID p_immediate,RID p_material){ + + +} +RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const{ + + return RID(); +} + +/* SKELETON API */ + +RID RasterizerStorageGLES3::skeleton_create(){ + + return RID(); +} +void RasterizerStorageGLES3::skeleton_allocate(RID p_skeleton,int p_bones,bool p_2d_skeleton){ + + +} +int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const{ + + return 0; +} +void RasterizerStorageGLES3::skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform){ + + +} +Transform RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton,int p_bone){ + + return Transform(); +} +void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton,int p_bone, const Matrix32& p_transform){ + + +} +Matrix32 RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton,int p_bone){ + + return Matrix32(); +} + +/* Light API */ + +RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ + + return RID(); +} + +void RasterizerStorageGLES3::light_set_color(RID p_light,const Color& p_color){ + + +} +void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param,float p_value){ + + +} +void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ + + +} +void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ + + +} +void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_texture){ + + +} +void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){ + + +} +void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){ + + +} +void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ + + +} + + +void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){ + + +} + +/* PROBE API */ + +RID RasterizerStorageGLES3::reflection_probe_create(){ + + return RID(); +} + +void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_clip(RID p_probe, float p_near, float p_far){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_min_blend_distance(RID p_probe, float p_distance){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3& p_extents){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_hide_skybox(RID p_probe, bool p_hide){ + + +} +void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers){ + + +} + + +/* ROOM API */ + +RID RasterizerStorageGLES3::room_create(){ + + return RID(); +} +void RasterizerStorageGLES3::room_add_bounds(RID p_room, const DVector<Vector2>& p_convex_polygon,float p_height,const Transform& p_transform){ + + +} +void RasterizerStorageGLES3::room_clear_bounds(){ + + +} + +/* PORTAL API */ + +// portals are only (x/y) points, forming a convex shape, which its clockwise +// order points outside. (z is 0); + +RID RasterizerStorageGLES3::portal_create(){ + + return RID(); +} +void RasterizerStorageGLES3::portal_set_shape(RID p_portal, const Vector<Point2>& p_shape){ + + +} +void RasterizerStorageGLES3::portal_set_enabled(RID p_portal, bool p_enabled){ + + +} +void RasterizerStorageGLES3::portal_set_disable_distance(RID p_portal, float p_distance){ + + +} +void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color& p_color){ + + +} + + +/* RENDER TARGET */ + + +void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { + + if (rt->front.fbo) { + glDeleteFramebuffers(1,&rt->front.fbo); + glDeleteTextures(1,&rt->front.color); + rt->front.fbo=0; + } + + if (rt->back.fbo) { + glDeleteFramebuffers(1,&rt->back.fbo); + glDeleteTextures(1,&rt->back.color); + rt->back.fbo=0; + } + + if (rt->deferred.fbo) { + glDeleteFramebuffers(1,&rt->deferred.fbo); + glDeleteFramebuffers(1,&rt->deferred.fbo_color); + glDeleteTextures(1,&rt->deferred.albedo_ao); + glDeleteTextures(1,&rt->deferred.normal_special); + glDeleteTextures(1,&rt->deferred.metal_rough_motion); + rt->deferred.fbo=0; + rt->deferred.fbo_color=0; + } + + if (rt->depth) { + glDeleteRenderbuffers(1,&rt->depth); + rt->depth=0; + } + +} + +void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ + + if (rt->width<=0 || rt->height<=0) + return; + + glGenFramebuffers(1, &rt->front.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->front.fbo); + + + glGenRenderbuffers(1, &rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->depth ); + if (config.fbo_format==FBO_FORMAT_16_BITS) { + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16, rt->width, rt->height); + } else { + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH24_STENCIL8, rt->width, rt->height); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, 0 ); + + + glGenTextures(1, &rt->front.color); + glBindTexture(GL_TEXTURE_2D, rt->front.color); + + + GLuint color_internal_format; + GLuint color_format; + GLuint color_type; + + + if (config.fbo_format==FBO_FORMAT_16_BITS) { + + if (rt->flags[RENDER_TARGET_TRANSPARENT]) { + color_internal_format=GL_RGB5_A1; + color_format=GL_RGBA; + color_type=GL_UNSIGNED_SHORT_5_5_5_1; + } else { + color_internal_format=GL_RGB565; + color_format=GL_RGB; + color_type=GL_UNSIGNED_SHORT_5_6_5; + } + + } else if (config.fbo_format==FBO_FORMAT_32_BITS) { + + if (rt->flags[RENDER_TARGET_TRANSPARENT]) { + color_internal_format=GL_RGBA8; + color_format=GL_RGBA; + color_type=GL_UNSIGNED_BYTE; + } else { + color_internal_format=GL_RGB10_A2; + color_format=GL_RGBA; + color_type=GL_UNSIGNED_INT_2_10_10_10_REV; + } + } else if (config.fbo_format==FBO_FORMAT_FLOAT) { + + color_internal_format=GL_RGBA16F; + color_format=GL_RGBA; + color_type=GL_HALF_FLOAT; + } + + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->front.color, 0); + + { + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + + ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); + } + + + if (!rt->flags[RENDER_TARGET_NO_SAMPLING]) { + + glGenFramebuffers(1, &rt->back.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->back.fbo); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + + glGenTextures(1, &rt->back.color); + glBindTexture(GL_TEXTURE_2D, rt->back.color); + + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->back.color, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + _render_target_clear(rt); + ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); + } + } + + + + if (config.fbo_deferred && !rt->flags[RENDER_TARGET_NO_3D]) { + + + //regular fbo + glGenFramebuffers(1, &rt->deferred.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->deferred.fbo); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + + glGenTextures(1, &rt->deferred.albedo_ao); + glBindTexture(GL_TEXTURE_2D, rt->deferred.albedo_ao); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 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); + 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->deferred.albedo_ao, 0); + + glGenTextures(1, &rt->deferred.metal_rough_motion); + glBindTexture(GL_TEXTURE_2D, rt->deferred.metal_rough_motion); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 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); + 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_ATTACHMENT1, GL_TEXTURE_2D, rt->deferred.metal_rough_motion, 0); + + glGenTextures(1, &rt->deferred.normal_special); + glBindTexture(GL_TEXTURE_2D, rt->deferred.normal_special); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 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); + 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_ATTACHMENT2, GL_TEXTURE_2D, rt->deferred.normal_special, 0); + + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + _render_target_clear(rt); + ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); + } + + //regular fbo with color attachment (needed for emission or objects rendered as forward) + + glGenFramebuffers(1, &rt->deferred.fbo_color); + glBindFramebuffer(GL_FRAMEBUFFER, rt->deferred.fbo_color); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->deferred.albedo_ao, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->deferred.metal_rough_motion, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->deferred.normal_special, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, rt->front.color, 0); + + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + _render_target_clear(rt); + ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); + } + } + + +} + + +RID RasterizerStorageGLES3::render_target_create(){ + + RenderTarget *rt = memnew( RenderTarget ); + return render_target_owner.make_rid(rt); +} + +void RasterizerStorageGLES3::render_target_set_size(RID p_render_target,int p_width, int p_height){ + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + if (rt->width==p_width && rt->height==p_height) + return; + + _render_target_clear(rt); + rt->width=p_width; + rt->height=p_height; + _render_target_allocate(rt); + +} + + +RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const{ + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt,RID()); + + + return RID(); +} +Image RasterizerStorageGLES3::render_target_get_image(RID p_render_target) const{ + + return Image(); +} +void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target,RenderTargetFlags p_flag,bool p_value) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->flags[p_flag]=p_value; + + switch(p_flag) { + case RENDER_TARGET_NO_3D: + case RENDER_TARGET_TRANSPARENT: { + //must reset for these formats + _render_target_clear(rt); + _render_target_allocate(rt); + + } break; + default: {} + } +} + +bool RasterizerStorageGLES3::render_target_renedered_in_frame(RID p_render_target){ + + return false; +} + +/* CANVAS SHADOW */ + + +RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { + + CanvasLightShadow *cls = memnew( CanvasLightShadow ); + if (p_width>config.max_texture_size) + p_width=config.max_texture_size; + + cls->size=p_width; + cls->height=16; + + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + glGenRenderbuffers(1, &cls->depth); + glBindRenderbuffer(GL_RENDERBUFFER, cls->depth ); + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24, cls->size, cls->height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); + glBindRenderbuffer(GL_RENDERBUFFER, 0 ); + + glGenTextures(1,&cls->distance); + glBindTexture(GL_TEXTURE_2D, cls->distance); + if (config.use_rgba_2d_shadows) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, NULL); + } + + + + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); + + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + + ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() ); + + return canvas_light_shadow_owner.make_rid(cls); +} + +/* LIGHT SHADOW MAPPING */ + + +RID RasterizerStorageGLES3::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 RasterizerStorageGLES3::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; + + } + +} + +bool RasterizerStorageGLES3::free(RID p_rid){ + + if (render_target_owner.owns(p_rid)) { + + RenderTarget *rt = render_target_owner.getornull(p_rid); + _render_target_clear(rt); + render_target_owner.free(p_rid); + memdelete(rt); + + } else if (texture_owner.owns(p_rid)) { + // delete the texture + Texture *texture = texture_owner.get(p_rid); + info.texture_mem-=texture->total_data_size; + texture_owner.free(p_rid); + memdelete(texture); + } 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->depth); + glDeleteTextures(1,&cls->distance); + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); + } else { + return false; + } + + return true; +} + +//////////////////////////////////////////// + + +void RasterizerStorageGLES3::initialize() { + + config.fbo_format=FBOFormat(int(Globals::get_singleton()->get("rendering/gles3/framebuffer_format"))); + config.fbo_deferred=int(Globals::get_singleton()->get("rendering/gles3/lighting_technique")); + + config.system_fbo=0; + + + //// extensions config + /// + + { + Vector<String> ext= String((const char*)glGetString( GL_EXTENSIONS )).split(" ",false); + for(int i=0;i<ext.size();i++) { + config.extensions.insert(ext[i]); + } + } + + config.shrink_textures_x2=false; + config.use_fast_texture_filter=int(Globals::get_singleton()->get("rendering/gles3/use_nearest_mipmap_filter")); + config.use_anisotropic_filter = config.extensions.has("GL_EXT_texture_filter_anisotropic"); + + config.s3tc_supported=config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); + config.etc_supported=config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); + config.latc_supported=config.extensions.has("GL_EXT_texture_compression_latc"); + config.bptc_supported=config.extensions.has("GL_ARB_texture_compression_bptc"); +#ifdef GLEW_ENABLED + config.etc2_supported=false; +#else + config.etc2_supported=true; +#endif + config.pvrtc_supported=config.extensions.has("GL_IMG_texture_compression_pvrtc"); + config.srgb_decode_supported=config.extensions.has("GL_EXT_texture_sRGB_decode"); + + + + config.anisotropic_level=1.0; + config.use_anisotropic_filter=config.extensions.has("GL_EXT_texture_filter_anisotropic"); + if (config.use_anisotropic_filter) { + glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&config.anisotropic_level); + config.anisotropic_level=MIN(int(Globals::get_singleton()->get("rendering/gles3/anisotropic_filter_level")),config.anisotropic_level); + } + + + frame.clear_request=false; + + shaders.copy.init(); + + { + //default textures + + + glGenTextures(1, &resources.white_tex); + unsigned char whitetexdata[8*8*3]; + for(int i=0;i<8*8*3;i++) { + whitetexdata[i]=255; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,resources.white_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE,whitetexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,0); + + glGenTextures(1, &resources.black_tex); + unsigned char blacktexdata[8*8*3]; + for(int i=0;i<8*8;i++) { + blacktexdata[i]=0; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,resources.black_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE,blacktexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,0); + + glGenTextures(1, &resources.normal_tex); + unsigned char normaltexdata[8*8*3]; + for(int i=0;i<8*8*3;i+=3) { + normaltexdata[i+0]=128; + normaltexdata[i+1]=128; + normaltexdata[i+2]=255; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,resources.normal_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE,normaltexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,0); + + } + + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&config.max_texture_image_units); + glGetIntegerv(GL_MAX_TEXTURE_SIZE,&config.max_texture_size); + +#ifdef GLEW_ENABLED + config.use_rgba_2d_shadows=false; +#else + config.use_rgba_2d_shadows=true; +#endif +} + +void RasterizerStorageGLES3::finalize() { + + glDeleteTextures(1, &resources.white_tex); + glDeleteTextures(1, &resources.black_tex); + glDeleteTextures(1, &resources.normal_tex); + +} + + +RasterizerStorageGLES3::RasterizerStorageGLES3() +{ + +} diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h new file mode 100644 index 0000000000..3b2d7d752c --- /dev/null +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -0,0 +1,445 @@ +#ifndef RASTERIZERSTORAGEGLES3_H +#define RASTERIZERSTORAGEGLES3_H + +#include "servers/visual/rasterizer.h" +#include "shader_gles3.h" +#include "shaders/copy.glsl.h" +#include "shaders/canvas.glsl.h" + + + + +class RasterizerStorageGLES3 : public RasterizerStorage { +public: + + enum FBOFormat { + FBO_FORMAT_16_BITS, + FBO_FORMAT_32_BITS, + FBO_FORMAT_FLOAT, + }; + + struct Config { + + FBOFormat fbo_format; + bool fbo_deferred; + GLuint system_fbo; //on some devices, such as apple, screen is rendered to yet another fbo. + + bool shrink_textures_x2; + bool use_fast_texture_filter; + bool use_anisotropic_filter; + + bool s3tc_supported; + bool latc_supported; + bool bptc_supported; + bool etc_supported; + bool etc2_supported; + bool pvrtc_supported; + + bool srgb_decode_supported; + + bool use_rgba_2d_shadows; + + float anisotropic_level; + + int max_texture_image_units; + int max_texture_size; + + Set<String> extensions; + } config; + + struct Shaders { + + CopyShaderGLES3 copy; + } shaders; + + struct Resources { + + GLuint white_tex; + GLuint black_tex; + GLuint normal_tex; + + } resources; + + struct Info { + + uint64_t texture_mem; + + } info; + + +///////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////DATA/////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + + + + + + + + + + + + + + + +///////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////API//////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + + + /* TEXTURE API */ + + struct RenderTarget; + + struct Texture : public RID_Data { + + String path; + uint32_t flags; + int width,height; + int alloc_width, alloc_height; + Image::Format format; + + GLenum target; + GLenum gl_format_cache; + GLenum gl_internal_format_cache; + GLenum gl_type_cache; + int data_size; //original data size, useful for retrieving back + bool compressed; + bool srgb; + int total_data_size; + bool ignore_mipmaps; + + int mipmaps; + + bool active; + GLuint tex_id; + + + RenderTarget *render_target; + + Texture() { + + ignore_mipmaps=false; + render_target=NULL; + flags=width=height=0; + tex_id=0; + data_size=0; + format=Image::FORMAT_L8; + active=false; + compressed=false; + total_data_size=0; + target=GL_TEXTURE_2D; + mipmaps=0; + + } + + ~Texture() { + + if (tex_id!=0) { + + glDeleteTextures(1,&tex_id); + } + } + }; + + mutable RID_Owner<Texture> texture_owner; + + Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags, GLenum& r_gl_format, GLenum& r_gl_internal_format, GLenum &r_type, bool &r_compressed, bool &srgb); + + virtual RID texture_create(); + virtual void texture_allocate(RID p_texture,int p_width, int p_height,Image::Format p_format,uint32_t p_flags=VS::TEXTURE_FLAGS_DEFAULT); + virtual void texture_set_data(RID p_texture,const Image& p_image,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT); + virtual Image texture_get_data(RID p_texture,VS::CubeMapSide p_cube_side=VS::CUBEMAP_LEFT) const; + virtual void texture_set_flags(RID p_texture,uint32_t p_flags); + virtual uint32_t texture_get_flags(RID p_texture) const; + virtual Image::Format texture_get_format(RID p_texture) const; + virtual uint32_t texture_get_width(RID p_texture) const; + virtual uint32_t texture_get_height(RID p_texture) const; + virtual void texture_set_size_override(RID p_texture,int p_width, int p_height); + + virtual void texture_set_path(RID p_texture,const String& p_path); + virtual String texture_get_path(RID p_texture) const; + + virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable); + + virtual void texture_debug_usage(List<VS::TextureInfo> *r_info); + + + /* SHADER API */ + + struct Shader : public RID_Data { + + + }; + + + virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_SPATIAL); + + virtual void shader_set_mode(RID p_shader,VS::ShaderMode p_mode); + virtual VS::ShaderMode shader_get_mode(RID p_shader) const; + + virtual void shader_set_code(RID p_shader, const String& p_code); + virtual String shader_get_code(RID p_shader) const; + virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const; + + virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture); + virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const; + + + /* COMMON MATERIAL API */ + + virtual RID material_create(); + + virtual void material_set_shader(RID p_shader_material, RID p_shader); + virtual RID material_get_shader(RID p_shader_material) const; + + virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value); + virtual Variant material_get_param(RID p_material, const StringName& p_param) const; + + /* MESH API */ + + virtual RID mesh_create(); + + virtual void mesh_add_surface(RID p_mesh,uint32_t p_format,VS::PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >()); + + virtual void mesh_set_morph_target_count(RID p_mesh,int p_amount); + virtual int mesh_get_morph_target_count(RID p_mesh) const; + + + virtual void mesh_set_morph_target_mode(RID p_mesh,VS::MorphTargetMode p_mode); + virtual VS::MorphTargetMode mesh_get_morph_target_mode(RID p_mesh) const; + + virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material); + virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; + + virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const; + virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const; + + virtual DVector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const; + virtual DVector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const; + + + virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; + virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; + + virtual void mesh_remove_surface(RID p_mesh,int p_index); + virtual int mesh_get_surface_count(RID p_mesh) const; + + virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb); + virtual AABB mesh_get_custom_aabb(RID p_mesh) const; + + virtual AABB mesh_get_aabb(RID p_mesh) const; + virtual void mesh_clear(RID p_mesh); + + /* MULTIMESH API */ + + + virtual RID multimesh_create(); + + virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true); + virtual int multimesh_get_instance_count(RID p_multimesh) const; + + virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh); + virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb); + virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform); + virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform); + virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color); + + virtual RID multimesh_get_mesh(RID p_multimesh) const; + virtual AABB multimesh_get_custom_aabb(RID p_multimesh,const AABB& p_aabb) const; + + virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const; + virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const; + virtual Color multimesh_instance_get_color(RID p_multimesh,int p_index) const; + + virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); + virtual int multimesh_get_visible_instances(RID p_multimesh) const; + + virtual AABB multimesh_get_aabb(RID p_mesh) const; + + /* IMMEDIATE API */ + + virtual RID immediate_create(); + virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID()); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_vertex_2d(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); + virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); + virtual void immediate_color(RID p_immediate,const Color& p_color); + virtual void immediate_uv(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_uv2(RID p_immediate,const Vector2& tex_uv); + virtual void immediate_end(RID p_immediate); + virtual void immediate_clear(RID p_immediate); + virtual void immediate_set_material(RID p_immediate,RID p_material); + virtual RID immediate_get_material(RID p_immediate) const; + + /* SKELETON API */ + + virtual RID skeleton_create(); + virtual void skeleton_allocate(RID p_skeleton,int p_bones,bool p_2d_skeleton=false); + virtual int skeleton_get_bone_count(RID p_skeleton) const; + virtual void skeleton_bone_set_transform(RID p_skeleton,int p_bone, const Transform& p_transform); + virtual Transform skeleton_bone_get_transform(RID p_skeleton,int p_bone); + virtual void skeleton_bone_set_transform_2d(RID p_skeleton,int p_bone, const Matrix32& p_transform); + virtual Matrix32 skeleton_bone_get_transform_2d(RID p_skeleton,int p_bone); + + /* Light API */ + + virtual RID light_create(VS::LightType p_type); + + virtual void light_set_color(RID p_light,const Color& p_color); + virtual void light_set_param(RID p_light,VS::LightParam p_param,float p_value); + virtual void light_set_shadow(RID p_light,bool p_enabled); + virtual void light_set_projector(RID p_light,RID p_texture); + virtual void light_set_attenuation_texure(RID p_light,RID p_texture); + virtual void light_set_negative(RID p_light,bool p_enable); + virtual void light_set_cull_mask(RID p_light,uint32_t p_mask); + virtual void light_set_shader(RID p_light,RID p_shader); + + + virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode); + + /* PROBE API */ + + virtual RID reflection_probe_create(); + + virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity); + virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far); + virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance); + virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents); + virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset); + virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable); + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); + virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide); + virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + + + /* ROOM API */ + + virtual RID room_create(); + virtual void room_add_bounds(RID p_room, const DVector<Vector2>& p_convex_polygon,float p_height,const Transform& p_transform); + virtual void room_clear_bounds(); + + /* PORTAL API */ + + // portals are only (x/y) points, forming a convex shape, which its clockwise + // order points outside. (z is 0); + + virtual RID portal_create(); + virtual void portal_set_shape(RID p_portal, const Vector<Point2>& p_shape); + virtual void portal_set_enabled(RID p_portal, bool p_enabled); + virtual void portal_set_disable_distance(RID p_portal, float p_distance); + virtual void portal_set_disabled_color(RID p_portal, const Color& p_color); + + + /* RENDER TARGET */ + + struct RenderTarget : public RID_Data { + + struct Color { + GLuint fbo; + GLuint color; + } front,back; + + GLuint depth; + + struct Deferred { + GLuint fbo; + GLuint fbo_color; + + GLuint albedo_ao; + GLuint metal_rough_motion; + GLuint normal_special; + } deferred; + + int width,height; + + bool flags[RENDER_TARGET_FLAG_MAX]; + + bool used_in_frame; + + RenderTarget() { + + width=0; + height=0; + depth=0; + front.fbo=0; + back.fbo=0; + deferred.fbo=0; + deferred.fbo_color=0; + used_in_frame=false; + + flags[RENDER_TARGET_VFLIP]=false; + flags[RENDER_TARGET_TRANSPARENT]=false; + flags[RENDER_TARGET_NO_3D]=false; + flags[RENDER_TARGET_NO_SAMPLING]=false; + } + }; + + mutable RID_Owner<RenderTarget> render_target_owner; + + void _render_target_clear(RenderTarget *rt); + void _render_target_allocate(RenderTarget *rt); + + virtual RID render_target_create(); + virtual void render_target_set_size(RID p_render_target,int p_width, int p_height); + virtual RID render_target_get_texture(RID p_render_target) const; + virtual Image render_target_get_image(RID p_render_target) const; + virtual void render_target_set_flag(RID p_render_target,RenderTargetFlags p_flag,bool p_value); + virtual bool render_target_renedered_in_frame(RID p_render_target); + + /* CANVAS SHADOW */ + + struct CanvasLightShadow : public RID_Data { + + int size; + int height; + GLuint fbo; + GLuint depth; + GLuint distance; //for older devices + }; + + RID_Owner<CanvasLightShadow> canvas_light_shadow_owner; + + virtual RID canvas_light_shadow_buffer_create(int p_width); + + /* LIGHT SHADOW MAPPING */ + + struct CanvasOccluder : public RID_Data { + + GLuint vertex_id; // 0 means, unconfigured + GLuint index_id; // 0 means, unconfigured + DVector<Vector2> lines; + int len; + }; + + RID_Owner<CanvasOccluder> canvas_occluder_owner; + + virtual RID canvas_light_occluder_create(); + virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines); + + virtual bool free(RID p_rid); + + + struct Frame { + + RenderTarget *current_rt; + + bool clear_request; + Color clear_request_color; + int canvas_draw_commands; + } frame; + + void initialize(); + void finalize(); + + + + RasterizerStorageGLES3(); +}; + + +#endif // RASTERIZERSTORAGEGLES3_H diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp new file mode 100644 index 0000000000..f8c0234943 --- /dev/null +++ b/drivers/gles3/shader_gles3.cpp @@ -0,0 +1,754 @@ +/*************************************************************************/ +/* shader_gles2.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "shader_gles3.h" + + +#include "print_string.h" + +//#define DEBUG_OPENGL + +#ifdef DEBUG_OPENGL + +#define DEBUG_TEST_ERROR(m_section)\ +{\ + uint32_t err = glGetError();\ + if (err) {\ + print_line("OpenGL Error #"+itos(err)+" at: "+m_section);\ + }\ +} +#else + +#define DEBUG_TEST_ERROR(m_section) + +#endif + +ShaderGLES3 *ShaderGLES3::active=NULL; + + + +//#define DEBUG_SHADER + +#ifdef DEBUG_SHADER + +#define DEBUG_PRINT(m_text) print_line(m_text); + +#else + +#define DEBUG_PRINT(m_text) + +#endif + + +void ShaderGLES3::bind_uniforms() { + + if (!uniforms_dirty) { + return; + }; + + // upload default uniforms + const Map<uint32_t,Variant>::Element *E =uniform_defaults.front(); + + while(E) { + int idx=E->key(); + int location=version->uniform_location[idx]; + + if (location<0) { + E=E->next(); + continue; + + } + + const Variant &v=E->value(); + _set_uniform_variant(location, v); + //print_line("uniform "+itos(location)+" value "+v+ " type "+Variant::get_type_name(v.get_type())); + E=E->next(); + }; + + const Map<uint32_t,CameraMatrix>::Element* C = uniform_cameras.front(); + while (C) { + + int location = version->uniform_location[C->key()]; + if (location<0) { + C=C->next(); + continue; + } + + glUniformMatrix4fv(location,1,false,&(C->get().matrix[0][0])); + C = C->next(); + }; + + uniforms_dirty = false; +}; + +GLint ShaderGLES3::get_uniform_location(int p_idx) const { + + ERR_FAIL_COND_V(!version, -1); + + return version->uniform_location[p_idx]; +}; + +bool ShaderGLES3::bind() { + + if (active!=this || !version || new_conditional_version.key!=conditional_version.key) { + conditional_version=new_conditional_version; + version = get_current_version(); + } else { + + return false; + } + + ERR_FAIL_COND_V(!version,false); + + glUseProgram( version->id ); + + DEBUG_TEST_ERROR("Use Program"); + + active=this; + uniforms_dirty = true; +/* + * why on earth is this code here? + for (int i=0;i<texunit_pair_count;i++) { + + glUniform1i(texunit_pairs[i].location, texunit_pairs[i].index); + DEBUG_TEST_ERROR("Uniform 1 i"); + } + +*/ + return true; +} + +void ShaderGLES3::unbind() { + + version=NULL; + glUseProgram(0); + uniforms_dirty = true; + active=NULL; +} + + +static void _display_error_with_code(const String& p_error,const Vector<const char*>& p_code) { + + + int line=1; + String total_code; + + for(int i=0;i<p_code.size();i++) { + total_code+=String(p_code[i]); + } + + Vector<String> lines = String(total_code).split("\n"); + + for(int j=0;j<lines.size();j++) { + + print_line(itos(line)+": "+lines[j]); + line++; + } + + ERR_PRINTS(p_error); + +} + +ShaderGLES3::Version* ShaderGLES3::get_current_version() { + + Version *_v=version_map.getptr(conditional_version); + + if (_v) { + + if (conditional_version.code_version!=0) { + CustomCode *cc=custom_code_map.getptr(conditional_version.code_version); + ERR_FAIL_COND_V(!cc,_v); + if (cc->version==_v->code_version) + return _v; + } else { + return _v; + } + + } + + + + if (!_v) + version_map[conditional_version]=Version(); + + + Version &v = version_map[conditional_version]; + + if (!_v) { + + v.uniform_location = memnew_arr( GLint, uniform_count ); + + } else { + if (v.ok) { + //bye bye shaders + glDeleteShader( v.vert_id ); + glDeleteShader( v.frag_id ); + glDeleteProgram( v.id ); + v.id=0; + } + + } + + v.ok=false; + /* SETUP CONDITIONALS */ + + Vector<const char*> strings; +#ifdef GLEW_ENABLED + //strings.push_back("#version 330\n"); + strings.push_back("#version 300 es\n"); +#else + strings.push_back("#version 300 es\n"); //ATI requieres this before anything +#endif + + + int define_line_ofs=1; + + for(int j=0;j<conditional_count;j++) { + + bool enable=((1<<j)&conditional_version.version); + strings.push_back(enable?conditional_defines[j]:""); + if (enable) + define_line_ofs++; + + if (enable) { + DEBUG_PRINT(conditional_defines[j]); + } + + } + + //keep them around during the function + CharString code_string; + CharString code_string2; + CharString code_globals; + + + //print_line("code version? "+itos(conditional_version.code_version)); + + CustomCode *cc=NULL; + + if ( conditional_version.code_version>0 ) { + //do custom code related stuff + + ERR_FAIL_COND_V( !custom_code_map.has( conditional_version.code_version ), NULL ); + cc=&custom_code_map[conditional_version.code_version]; + v.code_version=cc->version; + define_line_ofs+=2; + } + + + /* CREATE PROGRAM */ + + v.id = glCreateProgram(); + + ERR_FAIL_COND_V(v.id==0, NULL); + + /* VERTEX SHADER */ + + + if (cc) { + for(int i=0;i<cc->custom_defines.size();i++) { + + strings.push_back(cc->custom_defines[i]); + DEBUG_PRINT("CD #"+itos(i)+": "+String(cc->custom_defines[i])); + } + } + + int strings_base_size=strings.size(); + + //vertex precision is high + strings.push_back("precision highp float;\n"); + strings.push_back("precision highp int;\n"); + +#if 0 + if (cc) { + + String _code_string = "#define VERTEX_SHADER_CODE "+cc->vertex+"\n"; + String _code_globals = "#define VERTEX_SHADER_GLOBALS "+cc->vertex_globals+"\n"; + + code_string=_code_string.ascii(); + code_globals=_code_globals.ascii(); + DEBUG_PRINT( code_globals.get_data() ); + DEBUG_PRINT( code_string.get_data() ); + strings.push_back(code_globals); + strings.push_back(code_string); + } +#endif + + + strings.push_back(vertex_code0.get_data()); + if (cc) { + code_globals=cc->vertex_globals.ascii(); + strings.push_back(code_globals.get_data()); + } + strings.push_back(vertex_code1.get_data()); + + if (cc) { + code_string=cc->vertex.ascii(); + strings.push_back(code_string.get_data()); + } + + strings.push_back(vertex_code2.get_data()); +#ifdef DEBUG_SHADER + + DEBUG_PRINT("\nVertex Code:\n\n"+String(code_string.get_data())); + for(int i=0;i<strings.size();i++) { + + //print_line("vert strings "+itos(i)+":"+String(strings[i])); + } +#endif + + + v.vert_id = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(v.vert_id,strings.size(),&strings[0],NULL); + glCompileShader(v.vert_id); + + GLint status; + + glGetShaderiv(v.vert_id,GL_COMPILE_STATUS,&status); + if (status==GL_FALSE) { + // error compiling + GLsizei iloglen; + glGetShaderiv(v.vert_id,GL_INFO_LOG_LENGTH,&iloglen); + + if (iloglen<0) { + + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + + ERR_PRINT("NO LOG, WTF"); + } else { + + if (iloglen==0) { + + iloglen = 4096; //buggy driver (Adreno 220+....) + } + + + char *ilogmem = (char*)Memory::alloc_static(iloglen+1); + ilogmem[iloglen]=0; + glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); + + String err_string=get_shader_name()+": Vertex Program Compilation Failed:\n"; + + err_string+=ilogmem; + _display_error_with_code(err_string,strings); + Memory::free_static(ilogmem); + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + + } + + ERR_FAIL_V(NULL); + } + + /* FRAGMENT SHADER */ + + strings.resize(strings_base_size); + //fragment precision is medium + strings.push_back("precision mediump float;\n"); + strings.push_back("precision mediump int;\n"); + +#if 0 + if (cc) { + + String _code_string = "#define FRAGMENT_SHADER_CODE "+cc->fragment+"\n"; + String _code_globals = "#define FRAGMENT_SHADER_GLOBALS "+cc->fragment_globals+"\n"; + + code_string=_code_string.ascii(); + code_globals=_code_globals.ascii(); + DEBUG_PRINT( code_globals.get_data() ); + DEBUG_PRINT( code_string.get_data() ); + strings.push_back(code_globals); + strings.push_back(code_string); + } +#endif + + + strings.push_back(fragment_code0.get_data()); + if (cc) { + code_globals=cc->fragment_globals.ascii(); + strings.push_back(code_globals.get_data()); + } + strings.push_back(fragment_code1.get_data()); + + if (cc) { + code_string=cc->fragment.ascii(); + strings.push_back(code_string.get_data()); + } + + strings.push_back(fragment_code2.get_data()); + + if (cc) { + code_string2=cc->light.ascii(); + strings.push_back(code_string2.get_data()); + } + + strings.push_back(fragment_code3.get_data()); + +#ifdef DEBUG_SHADER + DEBUG_PRINT("\nFragment Code:\n\n"+String(code_string.get_data())); + for(int i=0;i<strings.size();i++) { + + //print_line("frag strings "+itos(i)+":"+String(strings[i])); + } +#endif + + v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(v.frag_id,strings.size(),&strings[0],NULL); + glCompileShader(v.frag_id); + + glGetShaderiv(v.frag_id,GL_COMPILE_STATUS,&status); + if (status==GL_FALSE) { + // error compiling + GLsizei iloglen; + glGetShaderiv(v.frag_id,GL_INFO_LOG_LENGTH,&iloglen); + + if (iloglen<0) { + + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + ERR_PRINT("NO LOG, WTF"); + } else { + + if (iloglen==0) { + + iloglen = 4096; //buggy driver (Adreno 220+....) + } + + char *ilogmem = (char*)Memory::alloc_static(iloglen+1); + ilogmem[iloglen]=0; + glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); + + String err_string=get_shader_name()+": Fragment Program Compilation Failed:\n"; + + err_string+=ilogmem; + _display_error_with_code(err_string,strings); + ERR_PRINT(err_string.ascii().get_data()); + Memory::free_static(ilogmem); + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + + } + + ERR_FAIL_V( NULL ); + } + + glAttachShader(v.id,v.frag_id); + glAttachShader(v.id,v.vert_id); + + // bind attributes before linking + for (int i=0;i<attribute_pair_count;i++) { + + glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name ); + } + + glLinkProgram(v.id); + + glGetProgramiv(v.id, GL_LINK_STATUS, &status); + + if (status==GL_FALSE) { + // error linking + GLsizei iloglen; + glGetProgramiv(v.id,GL_INFO_LOG_LENGTH,&iloglen); + + if (iloglen<0) { + + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + ERR_FAIL_COND_V(iloglen<=0, NULL); + } + + if (iloglen==0) { + + iloglen = 4096; //buggy driver (Adreno 220+....) + } + + + char *ilogmem = (char*)Memory::alloc_static(iloglen+1); + ilogmem[iloglen]=0; + glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); + + String err_string=get_shader_name()+": Program LINK FAILED:\n"; + + err_string+=ilogmem; + _display_error_with_code(err_string,strings); + ERR_PRINT(err_string.ascii().get_data()); + Memory::free_static(ilogmem); + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram( v.id ); + v.id=0; + + ERR_FAIL_V(NULL); + } + + /* UNIFORMS */ + + glUseProgram(v.id); + + + //print_line("uniforms: "); + for(int j=0;j<uniform_count;j++) { + + + v.uniform_location[j]=glGetUniformLocation(v.id,uniform_names[j]); + // print_line("uniform "+String(uniform_names[j])+" location "+itos(v.uniform_location[j])); + } + + // set texture uniforms + for (int i=0;i<texunit_pair_count;i++) { + + GLint loc = glGetUniformLocation(v.id,texunit_pairs[i].name); + if (loc>=0) { + if (texunit_pairs[i].index<0) { + glUniform1i(loc,max_image_units+texunit_pairs[i].index); //negative, goes down + } else { + + glUniform1i(loc,texunit_pairs[i].index); + } + } + } + + // assign uniform block bind points + for (int i=0;i<ubo_count;i++) { + + GLint loc = glGetUniformBlockIndex(v.id,ubo_pairs[i].name); + if (loc>=0) + glUniformBlockBinding(v.id,loc,ubo_pairs[i].index); + } + + if ( cc ) { + + v.custom_uniform_locations.resize(cc->custom_uniforms.size()); + for(int i=0;i<cc->custom_uniforms.size();i++) { + + v.custom_uniform_locations[i]=glGetUniformLocation(v.id,String(cc->custom_uniforms[i]).ascii().get_data()); + } + } + + glUseProgram(0); + + + v.ok=true; + + return &v; +} + +GLint ShaderGLES3::get_uniform_location(const String& p_name) const { + + ERR_FAIL_COND_V(!version,-1); + return glGetUniformLocation(version->id,p_name.ascii().get_data()); +} + + +void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start) { + + ERR_FAIL_COND(version); + conditional_version.key=0; + new_conditional_version.key=0; + uniform_count=p_uniform_count; + conditional_count=p_conditional_count; + conditional_defines=p_conditional_defines; + uniform_names=p_uniform_names; + vertex_code=p_vertex_code; + fragment_code=p_fragment_code; + texunit_pairs=p_texunit_pairs; + texunit_pair_count=p_texunit_pair_count; + vertex_code_start=p_vertex_code_start; + fragment_code_start=p_fragment_code_start; + attribute_pairs=p_attribute_pairs; + attribute_pair_count=p_attribute_count; + ubo_pairs=p_ubo_pairs; + ubo_count=p_ubo_pair_count; + + //split vertex and shader code (thank you, retarded shader compiler programmers from you know what company). + { + String globals_tag="\nVERTEX_SHADER_GLOBALS"; + String code_tag="\nVERTEX_SHADER_CODE"; + String code = vertex_code; + int cpos = code.find(globals_tag); + if (cpos==-1) { + vertex_code0=code.ascii(); + } else { + vertex_code0=code.substr(0,cpos).ascii(); + code = code.substr(cpos+globals_tag.length(),code.length()); + + cpos = code.find(code_tag); + + if (cpos==-1) { + vertex_code1=code.ascii(); + } else { + + vertex_code1=code.substr(0,cpos).ascii(); + vertex_code2=code.substr(cpos+code_tag.length(),code.length()).ascii(); + } + } + } + + { + String globals_tag="\nFRAGMENT_SHADER_GLOBALS"; + String code_tag="\nFRAGMENT_SHADER_CODE"; + String light_code_tag="\nLIGHT_SHADER_CODE"; + String code = fragment_code; + int cpos = code.find(globals_tag); + if (cpos==-1) { + fragment_code0=code.ascii(); + } else { + fragment_code0=code.substr(0,cpos).ascii(); + code = code.substr(cpos+globals_tag.length(),code.length()); + + cpos = code.find(code_tag); + + if (cpos==-1) { + fragment_code1=code.ascii(); + } else { + + fragment_code1=code.substr(0,cpos).ascii(); + String code2 = code.substr(cpos+code_tag.length(),code.length()); + + cpos = code2.find(light_code_tag); + if (cpos==-1) { + fragment_code2=code2.ascii(); + } else { + + fragment_code2=code2.substr(0,cpos).ascii(); + fragment_code3 = code2.substr(cpos+light_code_tag.length(),code2.length()).ascii(); + } + } + } + } + +} + +void ShaderGLES3::finish() { + + const VersionKey *V=NULL; + while((V=version_map.next(V))) { + + Version &v=version_map[*V]; + glDeleteShader( v.vert_id ); + glDeleteShader( v.frag_id ); + glDeleteProgram( v.id ); + memdelete_arr( v.uniform_location ); + + } + +} + + +void ShaderGLES3::clear_caches() { + + const VersionKey *V=NULL; + while((V=version_map.next(V))) { + + Version &v=version_map[*V]; + glDeleteShader( v.vert_id ); + glDeleteShader( v.frag_id ); + glDeleteProgram( v.id ); + memdelete_arr( v.uniform_location ); + } + + version_map.clear(); + + custom_code_map.clear(); + version=NULL; + last_custom_code=1; + uniforms_dirty = true; + +} + +uint32_t ShaderGLES3::create_custom_shader() { + + custom_code_map[last_custom_code]=CustomCode(); + custom_code_map[last_custom_code].version=1; + return last_custom_code++; +} + +void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String& p_vertex, const String& p_vertex_globals,const String& p_fragment,const String& p_light, const String& p_fragment_globals,const Vector<StringName>& p_uniforms,const Vector<const char*> &p_custom_defines) { + + ERR_FAIL_COND(!custom_code_map.has(p_code_id)); + CustomCode *cc=&custom_code_map[p_code_id]; + + cc->vertex=p_vertex; + cc->vertex_globals=p_vertex_globals; + cc->fragment=p_fragment; + cc->fragment_globals=p_fragment_globals; + cc->light=p_light; + cc->custom_uniforms=p_uniforms; + cc->custom_defines=p_custom_defines; + cc->version++; +} + +void ShaderGLES3::set_custom_shader(uint32_t p_code_id) { + + new_conditional_version.code_version=p_code_id; +} + +void ShaderGLES3::free_custom_shader(uint32_t p_code_id) { + + /* if (! custom_code_map.has( p_code_id )) { + print_line("no code id "+itos(p_code_id)); + } else { + print_line("freed code id "+itos(p_code_id)); + + }*/ + + ERR_FAIL_COND(! custom_code_map.has( p_code_id )); + if (conditional_version.code_version==p_code_id) + conditional_version.code_version=0; //bye + + custom_code_map.erase(p_code_id); + +} + + + +ShaderGLES3::ShaderGLES3() { + version=NULL; + last_custom_code=1; + uniforms_dirty = true; + + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&max_image_units); +} + + +ShaderGLES3::~ShaderGLES3() { + + finish(); +} + + + diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h new file mode 100644 index 0000000000..7aaf65d450 --- /dev/null +++ b/drivers/gles3/shader_gles3.h @@ -0,0 +1,377 @@ +/*************************************************************************/ +/* shader_gles2.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef SHADER_GLES3_H +#define SHADER_GLES3_H + + +#include "platform_config.h" +#ifndef GLES3_INCLUDE_H +#include <GLES3/gl3.h> +#else +#include GLES3_INCLUDE_H +#endif + +#include "hash_map.h" +#include "map.h" +#include "variant.h" +#include "camera_matrix.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + + +class ShaderGLES3 { +protected: + + struct Enum { + + uint64_t mask; + uint64_t shift; + const char *defines[16]; + }; + + struct EnumValue { + + uint64_t set_mask; + uint64_t clear_mask; + }; + + struct AttributePair { + + const char *name; + int index; + }; + + struct UniformPair { + const char* name; + Variant::Type type_hint; + }; + + struct TexUnitPair { + + const char *name; + int index; + }; + + struct UBOPair { + + const char *name; + int index; + }; + + bool uniforms_dirty; +private: + + //@TODO Optimize to a fixed set of shader pools and use a LRU + int uniform_count; + int texunit_pair_count; + int conditional_count; + int ubo_count; + int vertex_code_start; + int fragment_code_start; + int attribute_pair_count; + + struct CustomCode { + + String vertex; + String vertex_globals; + String fragment; + String fragment_globals; + String light; + uint32_t version; + Vector<StringName> custom_uniforms; + Vector<const char*> custom_defines; + + }; + + + struct Version { + + GLuint id; + GLuint vert_id; + GLuint frag_id; + GLint *uniform_location; + Vector<GLint> custom_uniform_locations; + uint32_t code_version; + bool ok; + Version() { code_version=0; ok=false; uniform_location=NULL; } + }; + + Version *version; + + union VersionKey { + + struct { + uint32_t version; + uint32_t code_version; + }; + uint64_t key; + bool operator==(const VersionKey& p_key) const { return key==p_key.key; } + bool operator<(const VersionKey& p_key) const { return key<p_key.key; } + + }; + + struct VersionKeyHash { + + static _FORCE_INLINE_ uint32_t hash( const VersionKey& p_key) { return HashMapHahserDefault::hash(p_key.key); }; + }; + + //this should use a way more cachefriendly version.. + HashMap<VersionKey,Version,VersionKeyHash> version_map; + + HashMap<uint32_t,CustomCode> custom_code_map; + uint32_t last_custom_code; + + + VersionKey conditional_version; + VersionKey new_conditional_version; + + virtual String get_shader_name() const=0; + + const char** conditional_defines; + const char** uniform_names; + const AttributePair *attribute_pairs; + const TexUnitPair *texunit_pairs; + const UBOPair *ubo_pairs; + const char* vertex_code; + const char* fragment_code; + CharString fragment_code0; + CharString fragment_code1; + CharString fragment_code2; + CharString fragment_code3; + + CharString vertex_code0; + CharString vertex_code1; + CharString vertex_code2; + + Version * get_current_version(); + + static ShaderGLES3 *active; + + int max_image_units; + + _FORCE_INLINE_ void _set_uniform_variant(GLint p_uniform,const Variant& p_value) { + + if (p_uniform<0) + return; // do none + switch(p_value.get_type()) { + + case Variant::BOOL: + case Variant::INT: { + + int val=p_value; + glUniform1i( p_uniform, val ); + } break; + case Variant::REAL: { + + real_t val=p_value; + glUniform1f( p_uniform, val ); + } break; + case Variant::COLOR: { + + Color val=p_value; + glUniform4f( p_uniform, val.r, val.g,val.b,val.a ); + } break; + case Variant::VECTOR2: { + + Vector2 val=p_value; + glUniform2f( p_uniform, val.x,val.y ); + } break; + case Variant::VECTOR3: { + + Vector3 val=p_value; + glUniform3f( p_uniform, val.x,val.y,val.z ); + } break; + case Variant::PLANE: { + + Plane val=p_value; + glUniform4f( p_uniform, val.normal.x,val.normal.y,val.normal.z,val.d ); + } break; + case Variant::QUAT: { + + Quat val=p_value; + glUniform4f( p_uniform, val.x,val.y,val.z,val.w ); + } break; + + case Variant::MATRIX32: { + + Matrix32 tr=p_value; + GLfloat matrix[16]={ /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + 0, + 0, + tr.elements[1][0], + tr.elements[1][1], + 0, + 0, + 0, + 0, + 1, + 0, + tr.elements[2][0], + tr.elements[2][1], + 0, + 1 + }; + + glUniformMatrix4fv(p_uniform,1,false,matrix); + + } break; + case Variant::MATRIX3: + case Variant::TRANSFORM: { + + Transform tr=p_value; + GLfloat matrix[16]={ /* build a 16x16 matrix */ + tr.basis.elements[0][0], + tr.basis.elements[1][0], + tr.basis.elements[2][0], + 0, + tr.basis.elements[0][1], + tr.basis.elements[1][1], + tr.basis.elements[2][1], + 0, + tr.basis.elements[0][2], + tr.basis.elements[1][2], + tr.basis.elements[2][2], + 0, + tr.origin.x, + tr.origin.y, + tr.origin.z, + 1 + }; + + + glUniformMatrix4fv(p_uniform,1,false,matrix); + } break; + default: { ERR_FAIL(); } // do nothing + + } + } + + Map<uint32_t,Variant> uniform_defaults; + Map<uint32_t,CameraMatrix> uniform_cameras; + + +protected: + + _FORCE_INLINE_ int _get_uniform(int p_which) const; + _FORCE_INLINE_ void _set_conditional(int p_which, bool p_value); + + void setup(const char** p_conditional_defines, int p_conditional_count,const char** p_uniform_names,int p_uniform_count, const AttributePair* p_attribute_pairs, int p_attribute_count, const TexUnitPair *p_texunit_pairs, int p_texunit_pair_count, const UBOPair *p_ubo_pairs, int p_ubo_pair_count,const char*p_vertex_code, const char *p_fragment_code,int p_vertex_code_start,int p_fragment_code_start); + + ShaderGLES3(); +public: + + enum { + CUSTOM_SHADER_DISABLED=0 + }; + + GLint get_uniform_location(const String& p_name) const; + GLint get_uniform_location(int p_uniform) const; + + static _FORCE_INLINE_ ShaderGLES3 *get_active() { return active; }; + bool bind(); + void unbind(); + void bind_uniforms(); + + + inline GLuint get_program() const { return version?version->id:0; } + + void clear_caches(); + + uint32_t create_custom_shader(); + void set_custom_shader_code(uint32_t p_id,const String& p_vertex, const String& p_vertex_globals,const String& p_fragment,const String& p_p_light,const String& p_fragment_globals,const Vector<StringName>& p_uniforms,const Vector<const char*> &p_custom_defines); + void set_custom_shader(uint32_t p_id); + void free_custom_shader(uint32_t p_id); + + void set_uniform_default(int p_idx, const Variant& p_value) { + + if (p_value.get_type()==Variant::NIL) { + + uniform_defaults.erase(p_idx); + } else { + + uniform_defaults[p_idx]=p_value; + } + uniforms_dirty = true; + } + + uint32_t get_version() const { return new_conditional_version.version; } + + void set_uniform_camera(int p_idx, const CameraMatrix& p_mat) { + + uniform_cameras[p_idx] = p_mat; + uniforms_dirty = true; + }; + + _FORCE_INLINE_ void set_custom_uniform(int p_idx, const Variant& p_value) { + + ERR_FAIL_COND(!version); + ERR_FAIL_INDEX(p_idx,version->custom_uniform_locations.size()); + _set_uniform_variant( version->custom_uniform_locations[p_idx], p_value ); + } + + _FORCE_INLINE_ GLint get_custom_uniform_location(int p_idx) { + + ERR_FAIL_COND_V(!version,-1); + ERR_FAIL_INDEX_V(p_idx,version->custom_uniform_locations.size(),-1); + return version->custom_uniform_locations[p_idx]; + } + + virtual void init()=0; + void finish(); + + virtual ~ShaderGLES3(); + +}; + + +// called a lot, made inline + + +int ShaderGLES3::_get_uniform(int p_which) const { + + ERR_FAIL_INDEX_V( p_which, uniform_count,-1 ); + ERR_FAIL_COND_V( !version, -1 ); + return version->uniform_location[p_which]; +} + +void ShaderGLES3::_set_conditional(int p_which, bool p_value) { + + ERR_FAIL_INDEX(p_which,conditional_count); + if (p_value) + new_conditional_version.version|=(1<<p_which); + else + new_conditional_version.version&=~(1<<p_which); +} + +#endif + diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub new file mode 100644 index 0000000000..628fa14e4e --- /dev/null +++ b/drivers/gles3/shaders/SCsub @@ -0,0 +1,7 @@ +Import('env') + +if env['BUILDERS'].has_key('GLES3_GLSL'): + env.GLES3_GLSL('copy.glsl'); + env.GLES3_GLSL('canvas.glsl'); + env.GLES3_GLSL('canvas_shadow.glsl'); + diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl new file mode 100644 index 0000000000..eed2239ec9 --- /dev/null +++ b/drivers/gles3/shaders/canvas.glsl @@ -0,0 +1,428 @@ +[vertex] + + +layout(location=0) in highp vec3 vertex; +layout(location=3) in vec4 color_attrib; + +#ifdef USE_TEXTURE_RECT + +layout(location=1) in highp vec4 dst_rect; +layout(location=2) in highp vec4 src_rect; + +#else + +layout(location=4) in highp vec2 uv_attrib; + +//skeletn +#endif + + +layout(std140) uniform CanvasItemData { //ubo:0 + + highp mat4 projection_matrix; +}; + +uniform highp mat4 modelview_matrix; +uniform highp mat4 extra_matrix; + + +out mediump vec2 uv_interp; +out mediump vec4 color_interp; + +#if defined(USE_TIME) +uniform float time; +#endif + +#ifdef USE_LIGHTING + +layout(std140) uniform LightData { //ubo:1 + + //light matrices + highp mat4 light_matrix; + highp mat4 light_local_matrix; + highp mat4 shadow_matrix; + highp vec4 light_color; + highp vec4 light_shadow_color; + highp vec2 light_pos; + highp float shadowpixel_size; + highp float shadow_gradient; + highp float light_height; + highp float light_outside_alpha; + highp float shadow_distance_mult; +}; + +out vec4 light_uv_interp; + +#if defined(NORMAL_USED) +out vec4 local_rot; +#endif + +#ifdef USE_SHADOWS +out highp vec2 pos; +#endif + +#endif + + +VERTEX_SHADER_GLOBALS + +void main() { + + color_interp = color_attrib; + + +#ifdef USE_TEXTURE_RECT + + + uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.xy; + highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex.xy,vec2(1.0,1.0)-vertex.xy,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0); + +#else + uv_interp = uv_attrib; + highp vec4 outvec = vec4(vertex, 1.0); +#endif + + +{ + vec2 src_vtx=outvec.xy; + +VERTEX_SHADER_CODE + +} + +#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_uv_interp.xy = (light_matrix * outvec).xy; + light_uv_interp.zw =(light_local_matrix * outvec).xy; +#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 ); + local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy ); +#ifdef USE_TEXTURE_RECT + local_rot.xy*=sign(src_rect.z); + local_rot.zw*=sign(src_rect.w); +#endif + +#endif + +#endif + +} + +[fragment] + + + +uniform mediump sampler2D color_texture; // texunit:0 + +in mediump vec2 uv_interp; +in mediump vec4 color_interp; + + +#if defined(ENABLE_TEXSCREEN) + +uniform sampler2D texscreen_tex; // texunit:-3 + +#endif + +#if defined(USE_TIME) +uniform float time; +#endif + +#ifdef USE_LIGHTING + +layout(std140) uniform LightData { + + highp mat4 light_matrix; + highp mat4 light_local_matrix; + highp mat4 shadow_matrix; + highp vec4 light_color; + highp vec4 light_shadow_color; + highp vec2 light_pos; + highp float shadowpixel_size; + highp float shadow_gradient; + highp float light_height; + highp float light_outside_alpha; + highp float shadow_distance_mult; +}; + +uniform lowp sampler2D light_texture; // texunit:-1 +in vec4 light_uv_interp; + + +#if defined(NORMAL_USED) +in vec4 local_rot; +#endif + +#ifdef USE_SHADOWS + +uniform highp sampler2D shadow_texture; // texunit:-2 +in highp vec2 pos; + +#endif + +#endif + +uniform mediump vec4 final_modulate; + +FRAGMENT_SHADER_GLOBALS + + +layout(location=0) out mediump vec4 frag_color; + +void main() { + + vec4 color = color_interp; +#if defined(NORMAL_USED) + vec3 normal = vec3(0.0,0.0,1.0); +#endif + +#ifdef USE_DISTANCE_FIELD + const float smoothing = 1.0/32.0; + float distance = texture(color_texture, uv_interp).a; + color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a; +#else + color *= texture( color_texture, uv_interp ); + +#endif + + +#if defined(ENABLE_SCREEN_UV) + vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; +#endif + + +{ +#if defined(USE_NORMALMAP) + vec3 normal_map=vec3(0.0,0.0,1.0); + float normal_depth=1.0; +#endif + +FRAGMENT_SHADER_CODE + +#if defined(USE_NORMALMAP) + normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth ); +#endif + +} +#ifdef DEBUG_ENCODED_32 + highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) ); + color = vec4(vec3(enc32),1.0); +#endif + + + color*=final_modulate; + + + + +#ifdef USE_LIGHTING + + vec2 light_vec = light_uv_interp.zw;; //for shadow and normal mapping + +#if defined(NORMAL_USED) + normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy; +#endif + + float att=1.0; + + vec2 light_uv = light_uv_interp.xy; + vec4 light = texture(light_texture,light_uv) * light_color; +#if defined(USE_OUTPUT_SHADOW_COLOR) + vec4 shadow_color=vec4(0.0,0.0,0.0,0.0); +#endif + + if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) { + color.a*=light_outside_alpha; //invisible + + } else { + +#if defined(USE_LIGHT_SHADER_CODE) +//light is written by the light shader + { + vec4 light_out=light*color; +LIGHT_SHADER_CODE + color=light_out; + } + +#else + +#if defined(NORMAL_USED) + vec3 light_normal = normalize(vec3(light_vec,-light_height)); + light*=max(dot(-light_normal,normal),0.0); +#endif + + color*=light; +/* +#ifdef USE_NORMAL + color.xy=local_rot.xy;//normal.xy; + color.zw=vec2(0.0,1.0); +#endif +*/ + +//light shader code +#endif + + +#ifdef USE_SHADOWS + + float angle_to_light = -atan(light_vec.x,light_vec.y); + float PI = 3.14159265358979323846264; + /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays + float ang*/ + + float su,sz; + + float abs_angle = abs(angle_to_light); + vec2 point; + float sh; + if (abs_angle<45.0*PI/180.0) { + point = light_vec; + sh=0.0+(1.0/8.0); + } else if (abs_angle>135.0*PI/180.0) { + point = -light_vec; + sh = 0.5+(1.0/8.0); + } else if (angle_to_light>0.0) { + + point = vec2(light_vec.y,-light_vec.x); + sh = 0.25+(1.0/8.0); + } else { + + point = vec2(-light_vec.y,light_vec.x); + sh = 0.75+(1.0/8.0); + + } + + + highp vec4 s = shadow_matrix * vec4(point,0.0,1.0); + s.xyz/=s.w; + su=s.x*0.5+0.5; + sz=s.z*0.5+0.5; + //sz=lightlength(light_vec); + + highp float shadow_attenuation=0.0; + +#ifdef USE_RGBA_SHADOWS + +#define SHADOW_DEPTH(m_tex,m_uv) dot(texture2D((m_tex),(m_uv)),vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) ) + +#else + +#define SHADOW_DEPTH(m_tex,m_uv) (texture2D((m_tex),(m_uv)).r) + +#endif + + + +#ifdef SHADOW_USE_GRADIENT + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=1.0-smoothstep(sd,sd+shadow_gradient,sz); } + +#else + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=step(sz,sd); } + +#endif + + +#ifdef SHADOW_FILTER_NEAREST + + SHADOW_TEST(su+shadowpixel_size); + +#endif + + +#ifdef SHADOW_FILTER_PCF3 + + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + shadow_attenuation/=3.0; + +#endif + + +#ifdef SHADOW_FILTER_PCF5 + + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + shadow_attenuation/=5.0; + +#endif + + +#ifdef SHADOW_FILTER_PCF9 + + SHADOW_TEST(su+shadowpixel_size*4.0); + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + SHADOW_TEST(su-shadowpixel_size*4.0); + shadow_attenuation/=9.0; + +#endif + +#ifdef SHADOW_FILTER_PCF13 + + SHADOW_TEST(su+shadowpixel_size*6.0); + SHADOW_TEST(su+shadowpixel_size*5.0); + SHADOW_TEST(su+shadowpixel_size*4.0); + SHADOW_TEST(su+shadowpixel_size*3.0); + SHADOW_TEST(su+shadowpixel_size*2.0); + SHADOW_TEST(su+shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su-shadowpixel_size); + SHADOW_TEST(su-shadowpixel_size*2.0); + SHADOW_TEST(su-shadowpixel_size*3.0); + SHADOW_TEST(su-shadowpixel_size*4.0); + SHADOW_TEST(su-shadowpixel_size*5.0); + SHADOW_TEST(su-shadowpixel_size*6.0); + shadow_attenuation/=13.0; + +#endif + + +#if defined(USE_OUTPUT_SHADOW_COLOR) + color=mix(shadow_color,color,shadow_attenuation); +#else + //color*=shadow_attenuation; + color=mix(light_shadow_color,color,shadow_attenuation); +#endif +//use shadows +#endif + } + +//use lighting +#endif +// color.rgb*=color.a; + frag_color = color; + +} + diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..c757990de0 --- /dev/null +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -0,0 +1,49 @@ +[vertex] + + + +uniform highp mat4 projection_matrix; +uniform highp mat4 light_matrix; +uniform highp mat4 world_matrix; +uniform highp float distance_norm; + +layout(location=0) in highp vec3 vertex; + +out highp vec4 position_interp; + +void main() { + + gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0))); + position_interp=gl_Position; +} + +[fragment] + +in highp vec4 position_interp; + +#ifdef USE_RGBA_SHADOWS + +layout(location=0) out lowp vec4 distance_buf; + +#else + +layout(location=0) out highp float distance_buf; + +#endif + +void main() { + + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias; + +#ifdef USE_RGBA_SHADOWS + + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + distance_buf=comp; +#else + + distance_buf=depth; + +#endif +} + diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl new file mode 100644 index 0000000000..aba280186a --- /dev/null +++ b/drivers/gles3/shaders/copy.glsl @@ -0,0 +1,52 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +#ifdef USE_CUBEMAP +layout(location=4) in vec3 cube_in; +#else +layout(location=4) in vec2 uv_in; // attrib:4 +#endif +layout(location=5) in vec2 uv2_in; // attrib:5 + +#ifdef USE_CUBEMAP +out vec3 cube_interp; +#else +out vec2 uv_interp; +#endif + +out vec2 uv2_interp; + +void main() { + +#ifdef USE_CUBEMAP + cube_interp = cube_in; +#else + uv_interp = uv_in; +#endif + uv2_interp = uv2_in; + gl_Position = vertex_attrib; +} + +[fragment] + + +#ifdef USE_CUBEMAP +in vec3 cube_interp; +uniform samplerCube source_cube; +#else +in vec2 uv_interp; +uniform sampler2D source; +#endif + +in vec2 uv2_interp; + +layout(location = 0) vec4 frag_color; //color:0 + +void main() { + + //vec4 color = color_interp; + + frag_color = color; +} + |