summaryrefslogtreecommitdiff
path: root/drivers/gles3
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2016-10-03 16:33:42 -0300
committerJuan Linietsky <reduzio@gmail.com>2016-10-03 21:35:16 +0200
commit22d83bc9f655d5ae7a1b49709c4c1b663725daf5 (patch)
treea817195c08d4713a70ca014a3f63f5937934fe36 /drivers/gles3
parent78d97b060a6873a454e710380cb9ef1bde5e4c65 (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/SCsub5
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp1461
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h102
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp266
-rw-r--r--drivers/gles3/rasterizer_gles3.h38
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp2045
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h445
-rw-r--r--drivers/gles3/shader_gles3.cpp754
-rw-r--r--drivers/gles3/shader_gles3.h377
-rw-r--r--drivers/gles3/shaders/SCsub7
-rw-r--r--drivers/gles3/shaders/canvas.glsl428
-rw-r--r--drivers/gles3/shaders/canvas_shadow.glsl49
-rw-r--r--drivers/gles3/shaders/copy.glsl52
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;
+}
+