summaryrefslogtreecommitdiff
path: root/drivers/gles3/rasterizer_canvas_gles3.cpp
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/rasterizer_canvas_gles3.cpp
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/rasterizer_canvas_gles3.cpp')
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp1461
1 files changed, 1461 insertions, 0 deletions
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()
+{
+
+}