diff options
-rw-r--r-- | drivers/gles2/rasterizer_canvas_gles2.cpp | 947 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_canvas_gles2.h | 46 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_gles2.cpp | 5 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.h | 4 | ||||
-rw-r--r-- | drivers/gles2/shader_gles2.cpp | 14 | ||||
-rw-r--r-- | drivers/gles2/shader_gles2.h | 1 | ||||
-rw-r--r-- | drivers/gles2/shaders/canvas.glsl | 33 |
7 files changed, 596 insertions, 454 deletions
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 3d388c031a..c35d9bac98 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -64,9 +64,13 @@ void RasterizerCanvasGLES2::_set_uniforms() { state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); } + + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, state.uniforms.texpixel_size); } void RasterizerCanvasGLES2::canvas_begin() { + data.primitive = GL_TRIANGLES; + data.texture = GL_NONE; state.canvas_shader.bind(); if (storage->frame.current_rt) { @@ -94,6 +98,7 @@ void RasterizerCanvasGLES2::canvas_begin() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + data.texture = storage->resources.white_tex; glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); glDisableVertexAttribArray(VS::ARRAY_COLOR); @@ -124,7 +129,7 @@ void RasterizerCanvasGLES2::canvas_begin() { state.uniforms.extra_matrix = Transform2D(); _set_uniforms(); - _bind_quad_buffer(); + state.prev_uniforms = state.uniforms; } void RasterizerCanvasGLES2::canvas_end() { @@ -142,6 +147,7 @@ void RasterizerCanvasGLES2::canvas_end() { RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { RasterizerStorageGLES2::Texture *tex_return = NULL; + GLuint newtexid; if (p_texture.is_valid()) { @@ -151,8 +157,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con state.current_tex = RID(); state.current_tex_ptr = NULL; - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + newtexid = storage->resources.white_tex; } else { @@ -166,8 +171,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con texture->render_target->used_in_frame = true; } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); + newtexid = texture->tex_id; state.current_tex = p_texture; state.current_tex_ptr = texture; @@ -178,8 +182,15 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con state.current_tex = RID(); state.current_tex_ptr = NULL; + newtexid = storage->resources.white_tex; + } + + if (data.texture != newtexid) { + _flush(); + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + glBindTexture(GL_TEXTURE_2D, newtexid); + data.texture = newtexid; } return tex_return; @@ -189,217 +200,154 @@ void RasterizerCanvasGLES2::_set_texture_rect_mode(bool p_enable, bool p_ninepat } void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { + _begin(GL_TRIANGLES); + _prepare(p_vertex_count, p_index_count); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - uint32_t buffer_ofs = 0; - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); - buffer_ofs += sizeof(Vector2) * p_vertex_count; + bool single; + Color color; if (p_singlecolor) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + single = true; + color = *p_colors; } else if (!p_colors) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - - if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); - buffer_ofs += sizeof(Vector2) * p_vertex_count; + single = true; + color = Color(1, 1, 1, 1); } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + single = false; } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} + const bool use_single_color = single; + const Color single_color = color; -void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { + for (int i = 0; i < p_vertex_count; ++i) { + v->v = p_vertices[i]; - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + if (use_single_color) + v->c = single_color; + else + v->c = p_colors[i]; - uint32_t buffer_ofs = 0; + if (p_uvs) + v->uv = p_uvs[i]; + else + v->uv = Vector2(); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), (uint8_t *)0); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - if (p_singlecolor) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); - buffer_ofs += sizeof(Color) * p_vertex_count; + ++v; } - if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); - } else { - glDisableVertexAttribArray(VS::ARRAY_TEX_UV); - } + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, p_indices, p_index_count * sizeof(int)); - glDrawArrays(p_primitive, 0, p_vertex_count); - - glBindBuffer(GL_ARRAY_BUFFER, 0); + _commit(p_vertex_count, p_index_count); } -void RasterizerCanvasGLES2::_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 }; - - int color_offset = 0; - int uv_offset = 0; - int stride = 2; - - if (p_colors) { - color_offset = stride; - stride += 4; - } +void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { - if (p_uvs) { - uv_offset = stride; - stride += 2; - } + int command_count = p_item->commands.size(); + Item::Command **commands = p_item->commands.ptrw(); - float buffer_data[(2 + 2 + 4) * 4]; + for (int i = 0; i < command_count; i++) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + 0] = p_vertices[i].x; - buffer_data[stride * i + 1] = p_vertices[i].y; - } + Item::Command *command = commands[i]; - if (p_colors) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + color_offset + 0] = p_colors[i].r; - buffer_data[stride * i + color_offset + 1] = p_colors[i].g; - buffer_data[stride * i + color_offset + 2] = p_colors[i].b; - buffer_data[stride * i + color_offset + 3] = p_colors[i].a; + if (command->type != Item::Command::TYPE_RECT && state.tiled) { + _flush(); + _untile(); } - } - if (p_uvs) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x; - buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y; - } - } + switch (command->type) { - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data); + case Item::Command::TYPE_LINE: { + const Item::CommandLine *line = static_cast<Item::CommandLine *>(command); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL); + if (line->width <= 1) { + const int p_vertex_count = 2; + const int p_index_count = 2; - if (p_colors) { - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + color_offset * sizeof(float)); - glEnableVertexAttribArray(VS::ARRAY_COLOR); - } + _begin(GL_LINES); + _prepare(p_vertex_count, p_index_count); - if (p_uvs) { - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + uv_offset * sizeof(float)); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - } + _bind_shader(p_material); + _bind_canvas_texture(RID(), RID()); - glDrawArrays(prim[p_points], 0, p_points); + Vertex vertices[p_vertex_count]; - glBindBuffer(GL_ARRAY_BUFFER, 0); -} + vertices[0].v = Vector2(line->from.x, line->from.y); + vertices[0].c = line->color; + vertices[0].uv = Vector2(); -void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { + vertices[1].v = Vector2(line->to.x, line->to.y); + vertices[1].c = line->color; + vertices[1].uv = Vector2(); - int command_count = p_item->commands.size(); - Item::Command **commands = p_item->commands.ptrw(); + memcpy(data.mem_vertex_buffer + data.mem_vertex_buffer_offset, vertices, sizeof(vertices)); - for (int i = 0; i < command_count; i++) { + const int indices[p_index_count] = { 0, 1 }; - Item::Command *command = commands[i]; + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); - switch (command->type) { + _commit(p_vertex_count, p_index_count); + } else { + const int p_vertex_count = 4; + const int p_index_count = 6; - case Item::Command::TYPE_LINE: { + _begin(GL_TRIANGLES); + _prepare(p_vertex_count, p_index_count); - Item::CommandLine *line = static_cast<Item::CommandLine *>(command); + _bind_shader(p_material); + _bind_canvas_texture(RID(), RID()); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - _bind_canvas_texture(RID(), RID()); + Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4fv(VS::ARRAY_COLOR, line->color.components); + v[0].v = line->from - t; + v[0].c = line->color; + v[0].uv = Vector2(); - state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + v[1].v = line->from + t; + v[1].c = line->color; + v[1].uv = Vector2(); - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; + v[2].v = line->to + t; + v[2].c = line->color; + v[2].uv = Vector2(); - _draw_gui_primitive(2, verts, NULL, NULL); - } else { - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; + v[3].v = line->to - t; + v[3].c = line->color; + v[3].uv = Vector2(); - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t + const int indices[p_index_count] = { + 0, 1, 2, + 2, 3, 0 }; - _draw_gui_primitive(4, verts, NULL, NULL); + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); + + _commit(p_vertex_count, p_index_count); } + } break; case Item::Command::TYPE_RECT: { + const int p_vertex_count = 4; + const int p_index_count = 6; - Item::CommandRect *r = static_cast<Item::CommandRect *>(command); + _begin(GL_TRIANGLES); + _prepare(p_vertex_count, p_index_count); - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components); + Item::CommandRect *r = static_cast<Item::CommandRect *>(command); - _bind_quad_buffer(); + _bind_shader(p_material); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + Rect2 src_rect; + Rect2 dst_rect; RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); if (!tex) { - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + dst_rect = Rect2(r->rect.position, r->rect.size); if (dst_rect.size.width < 0) { dst_rect.position.x += dst_rect.size.width; @@ -410,24 +358,28 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur dst_rect.size.height *= -1; } - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1)); + src_rect = Rect2(0, 0, 1, 1); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } else { - bool untile = false; + const bool tiled = r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT); - if (r->flags & CANVAS_RECT_TILE && !(tex->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; + if (tiled != state.tiled) { + _flush(); + + if (tiled) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + state.tiled = true; + } else { + _untile(); + } } Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + dst_rect = Rect2(r->rect.position, r->rect.size); if (dst_rect.size.width < 0) { dst_rect.position.x += dst_rect.size.width; @@ -440,48 +392,61 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (r->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; + src_rect.position.x -= src_rect.size.width; } - if (r->flags & CANVAS_RECT_FLIP_V) { src_rect.size.y *= -1; + src_rect.position.y -= src_rect.size.height; } - if (r->flags & CANVAS_RECT_TRANSPOSE) { dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform } - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + state.uniforms.texpixel_size = texpixel_size; + } - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + // 0,0 + v[0].v = dst_rect.position; + v[0].c = r->modulate; + v[0].uv = src_rect.position; - 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); - } - } + // 0,1 + v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y); + v[1].c = r->modulate; + v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + src_rect.size.y); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + // 1,1 + v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y); + v[2].c = r->modulate; + v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y); + // 1,0 + v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y); + v[3].c = r->modulate; + v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y); + + const int indices[p_index_count] = { + 0, 1, 2, + 2, 3, 0 + }; + + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(int) * p_index_count); + + _commit(p_vertex_count, p_index_count); } break; case Item::Command::TYPE_NINEPATCH: { + const int p_vertex_count = 16; + const int p_index_count = 54; - Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command); + _begin(GL_TRIANGLES); + _prepare(p_vertex_count, p_index_count); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - glDisableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttrib4fv(VS::ARRAY_COLOR, np->color.components); + Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command); + _bind_shader(p_material); RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map); if (!tex) { @@ -491,8 +456,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - // state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + state.uniforms.texpixel_size = texpixel_size; Rect2 source = np->source; if (source.size.x == 0 && source.size.y == 0) { @@ -504,255 +468,334 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur // this buffer contains [ POS POS UV UV ] * - float buffer[16 * 2 + 16 * 2]; + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - { + v[0].v = np->rect.position; + v[0].c = np->color; + v[0].uv = source.position * texpixel_size; - // first row + v[1].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], 0); + v[1].c = np->color; + v[1].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], 0)) * texpixel_size; - buffer[(0 * 4 * 4) + 0] = np->rect.position.x; - buffer[(0 * 4 * 4) + 1] = np->rect.position.y; + v[2].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], 0); + v[2].c = np->color; + v[2].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], 0)) * texpixel_size; - buffer[(0 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(0 * 4 * 4) + 3] = source.position.y * texpixel_size.y; + v[3].v = np->rect.position + Vector2(np->rect.size.x, 0); + v[3].c = np->color; + v[3].uv = (source.position + Vector2(source.size.x, 0)) * texpixel_size; - buffer[(0 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; - buffer[(0 * 4 * 4) + 5] = np->rect.position.y; + v[4].v = np->rect.position + Vector2(0, np->margin[MARGIN_TOP]); + v[4].c = np->color; + v[4].uv = (source.position + Vector2(0, np->margin[MARGIN_TOP])) * texpixel_size; - buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(0 * 4 * 4) + 7] = source.position.y * texpixel_size.y; + v[5].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP]); + v[5].c = np->color; + v[5].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP])) * texpixel_size; - buffer[(0 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; - buffer[(0 * 4 * 4) + 9] = np->rect.position.y; + v[6].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP]); + v[6].c = np->color; + v[6].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP])) * texpixel_size; - buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(0 * 4 * 4) + 11] = source.position.y * texpixel_size.y; + v[7].v = np->rect.position + Vector2(np->rect.size.x, np->margin[MARGIN_TOP]); + v[7].c = np->color; + v[7].uv = (source.position + Vector2(source.size.x, np->margin[MARGIN_TOP])) * texpixel_size; - buffer[(0 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(0 * 4 * 4) + 13] = np->rect.position.y; + v[8].v = np->rect.position + Vector2(0, np->rect.size.y - np->margin[MARGIN_BOTTOM]); + v[8].c = np->color; + v[8].uv = (source.position + Vector2(0, source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size; - buffer[(0 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(0 * 4 * 4) + 15] = source.position.y * texpixel_size.y; + v[9].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y - np->margin[MARGIN_BOTTOM]); + v[9].c = np->color; + v[9].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size; - // second row + v[10].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM]); + v[10].c = np->color; + v[10].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM])) * texpixel_size; - buffer[(1 * 4 * 4) + 0] = np->rect.position.x; - buffer[(1 * 4 * 4) + 1] = np->rect.position.y + np->margin[MARGIN_TOP]; + v[11].v = np->rect.position + np->rect.size - Vector2(0, np->margin[MARGIN_BOTTOM]); + v[11].c = np->color; + v[11].uv = (source.position + source.size - Vector2(0, np->margin[MARGIN_BOTTOM])) * texpixel_size; - buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; + v[12].v = np->rect.position + Vector2(0, np->rect.size.y); + v[12].c = np->color; + v[12].uv = (source.position + Vector2(0, source.size.y)) * texpixel_size; - buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; - buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[MARGIN_TOP]; + v[13].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y); + v[13].c = np->color; + v[13].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y)) * texpixel_size; - buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; + v[14].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], 0); + v[14].c = np->color; + v[14].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], 0)) * texpixel_size; - buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; - buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[MARGIN_TOP]; + v[15].v = np->rect.position + np->rect.size; + v[15].c = np->color; + v[15].uv = (source.position + source.size) * texpixel_size; - buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, data.ninepatch_elements, sizeof(data.ninepatch_elements)); - buffer[(1 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(1 * 4 * 4) + 13] = np->rect.position.y + np->margin[MARGIN_TOP]; + _commit(p_vertex_count, p_index_count - (np->draw_center ? 0 : 6)); + } break; - buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; + case Item::Command::TYPE_CIRCLE: { + Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command); - // thrid row + _bind_shader(p_material); - buffer[(2 * 4 * 4) + 0] = np->rect.position.x; - buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; + const int num_points = 32; - buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; + Vector2 points[num_points + 1]; + points[num_points] = circle->pos; - buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; - buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; + int indices[num_points * 3]; - buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; + for (int i = 0; i < num_points; i++) { + points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius; + indices[i * 3 + 0] = i; + indices[i * 3 + 1] = (i + 1) % num_points; + indices[i * 3 + 2] = num_points; + } - buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; - buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; + _bind_canvas_texture(RID(), RID()); - buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; + _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); + } break; - buffer[(2 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(2 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; + case Item::Command::TYPE_POLYGON: { + Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command); - buffer[(2 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(2 * 4 * 4) + 15] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; + const int *indices = polygon->indices.ptr(); + if (!indices) // self-intersecting polygon + break; - // fourth row + _bind_shader(p_material); + RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - buffer[(3 * 4 * 4) + 0] = np->rect.position.x; - buffer[(3 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y; + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.uniforms.texpixel_size = texpixel_size; + } - buffer[(3 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(3 * 4 * 4) + 3] = (source.position.y + source.size.y) * texpixel_size.y; + _draw_polygon(indices, polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + } break; - buffer[(3 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; - buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y; + case Item::Command::TYPE_POLYLINE: { + Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command); - buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(3 * 4 * 4) + 7] = (source.position.y + source.size.y) * texpixel_size.y; + if (pline->triangles.size()) { + const int p_vertex_count = pline->triangles.size(); + const int p_triangle_count = p_vertex_count - 2; + const int p_index_count = p_triangle_count * 3; - buffer[(3 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; - buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y; + _begin(GL_TRIANGLES); + _prepare(p_vertex_count, p_index_count); - buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(3 * 4 * 4) + 11] = (source.position.y + source.size.y) * texpixel_size.y; + _bind_shader(p_material); + _bind_canvas_texture(RID(), RID()); - buffer[(3 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(3 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y; + const Vector2 *t = pline->triangles.ptr(); + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - buffer[(3 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(3 * 4 * 4) + 15] = (source.position.y + source.size.y) * texpixel_size.y; + const bool p_singlecolor = pline->triangle_colors.size() == 1; + const Color *p_colors = pline->triangle_colors.ptr(); - // print_line(String::num((source.position.y + source.size.y) * texpixel_size.y)); - } + bool single; + Color color; - glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * (16 + 16) * 2, buffer); + if (pline->triangle_colors.size() == 1) { + single = true; + color = *p_colors; + } else if (!p_colors) { + single = true; + color = Color(1, 1, 1, 1); + } else { + single = false; + } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); + const bool use_single_color = single; + const Color single_color = color; - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + for (int i = 0; i < p_vertex_count; ++i) { + if (use_single_color) + v->c = single_color; + else + v->c = p_colors[i]; - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (uint8_t *)0 + (sizeof(float) * 2)); + v->uv = Vector2(); + v->v = t[i]; - glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL); + ++v; + } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + for (int i = 0; i < p_triangle_count; ++i) { + const int indices[3] = { + i, i + 1, i + 2 + }; - } break; + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 3, indices, sizeof(indices)); + } - case Item::Command::TYPE_CIRCLE: { + _commit(p_vertex_count, p_index_count); + } else { + _begin(GL_LINES); - Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command); + _bind_shader(p_material); + _bind_canvas_texture(RID(), RID()); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); + const Color *p_colors = pline->line_colors.ptr(); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + bool single; + Color color; - static const int num_points = 32; + if (pline->line_colors.size() == 1) { + single = true; + color = *p_colors; + } else if (!p_colors) { + single = true; + color = Color(1, 1, 1, 1); + } else { + single = false; + } - Vector2 points[num_points + 1]; - points[num_points] = circle->pos; + const bool use_single_color = single; + const Color single_color = color; - int indices[num_points * 3]; + const Vector2 *p_lines = pline->lines.ptr(); - for (int i = 0; i < num_points; i++) { - points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius; - indices[i * 3 + 0] = i; - indices[i * 3 + 1] = (i + 1) % num_points; - indices[i * 3 + 2] = num_points; - } + if (pline->multiline) { + const int p_lines_count = pline->lines.size() / 2; - _bind_canvas_texture(RID(), RID()); + for (int i = 0; i < p_lines_count; ++i) { + const int p_vertex_count = 2; + const int p_index_count = 2; - _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); - } break; + _prepare(p_vertex_count, p_index_count); - case Item::Command::TYPE_POLYGON: { + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command); + for (int j = 0; j < 2; ++j) { + if (use_single_color) + v->c = single_color; + else + v->c = p_colors[i]; - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); + v->uv = Vector2(); + v->v = p_lines[i * 2 + j]; - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + ++v; + } - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); + const int indices[p_index_count] = { 0, 1 }; - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - } + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } break; + _commit(p_vertex_count, p_index_count); + } + } else { + const int p_vertex_count = pline->lines.size(); + const int p_lines_count = p_vertex_count - 1; + const int p_index_count = p_lines_count * 2; - case Item::Command::TYPE_POLYLINE: { - Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command); + _prepare(p_vertex_count, p_index_count); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); + _bind_shader(p_material); + _bind_canvas_texture(RID(), RID()); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - _bind_canvas_texture(RID(), RID()); + for (int i = 0; i < p_vertex_count; ++i) { + if (use_single_color) + v->c = single_color; + else + v->c = p_colors[i]; - if (pline->triangles.size()) { - _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); - } else { - if (pline->multiline) { - int todo = pline->lines.size() / 2; - int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); - int offset = 0; - - while (todo) { - int to_draw = MIN(max_per_call, todo); - _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); - todo -= to_draw; - offset += to_draw * 2; + v->uv = Vector2(); + v->v = p_lines[i]; + + ++v; } - } else { - _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + + for (int i = 0; i < p_lines_count; ++i) { + const int indices[2] = { i, i + 1 }; + + memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 2, indices, sizeof(indices)); + } + + _commit(p_vertex_count, p_index_count); } } } break; case Item::Command::TYPE_PRIMITIVE: { - Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(command); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } + const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; ERR_CONTINUE(primitive->points.size() < 1); + _bind_shader(p_material); RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); if (texture) { Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + state.uniforms.texpixel_size = texpixel_size; } + const int p_vertex_count = primitive->points.size(); + const int p_index_count = p_vertex_count; + + _begin(prim[p_vertex_count]); + _prepare(p_vertex_count, p_index_count); + + Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + int *index = data.mem_index_buffer + data.mem_index_buffer_offset; + + Color c; + bool p_single_color; + + const Color *p_colors = primitive->colors.ptr(); + const Vector2 *p_uvs = primitive->uvs.ptr(); + const Vector2 *p_points = primitive->points.ptr(); + 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); + p_single_color = true; + c = primitive->colors[0]; } else if (primitive->colors.empty()) { - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + p_single_color = true; + c = Color(1, 1, 1, 1); + } else { + p_single_color = false; + } + + const bool use_single_color = p_single_color; + const Color single_color = c; + + for (int i = 0; i < p_vertex_count; ++i) { + if (use_single_color) + v->c = single_color; + else + v->c = p_colors[i]; + + if (p_uvs) + v->uv = p_uvs[i]; + else + v->uv = Vector2(); + + v->v = p_points[i]; + + index[i] = i; + + ++v; } - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); + _commit(p_vertex_count, p_index_count); } break; case Item::Command::TYPE_TRANSFORM: { Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(command); state.uniforms.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix); } break; case Item::Command::TYPE_PARTICLES: { @@ -815,6 +858,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + data.texture = storage->resources.white_tex; int last_blend_mode = -1; @@ -824,8 +868,9 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons Item *ci = p_item_list; - if (current_clip != ci->final_clip_owner) { + Item *material_owner = ci->material_owner ? ci->material_owner : ci; + if (current_clip != ci->final_clip_owner) { current_clip = ci->final_clip_owner; if (current_clip) { @@ -849,8 +894,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons } } - Item *material_owner = ci->material_owner ? ci->material_owner : ci; - RID material = material_owner->material; RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material); @@ -980,9 +1023,11 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons state.uniforms.extra_matrix = Transform2D(); _set_uniforms(); - _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); + // TODO: figure out when to _flush to get better batching results + _flush(); + rebind_shader = true; // hacked in for now. if (reclip) { @@ -996,6 +1041,8 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons p_item_list = p_item_list->next; } + _flush(); + if (current_clip) { glDisable(GL_SCISSOR_TEST); } @@ -1034,17 +1081,40 @@ void RasterizerCanvasGLES2::reset_canvas() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } -void RasterizerCanvasGLES2::_bind_quad_buffer() { - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL); -} -void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { +void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &dst_rect, const Rect2 &src_rect) { + + const int p_index_count = 6; + const int p_vertex_count = 4; + + Vertex v[p_vertex_count]; + Color c(1, 1, 1, 1); + + // 0,0 + v[0].v = dst_rect.position; + v[0].c = c; + v[0].uv = src_rect.position; + + // 0,1 + v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y); + v[1].c = c; + v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + src_rect.size.y); + + // 1,1 + v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y); + v[2].c = c; + v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y); - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); + // 1,0 + v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y); + v[3].c = c; + v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + const int indices[p_index_count] = { + 0, 1, 2, + 2, 3, 0 + }; + + _draw(GL_TRIANGLES, p_vertex_count, v, p_index_count, indices); } void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) { @@ -1052,60 +1122,36 @@ void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_im void RasterizerCanvasGLES2::initialize() { - // quad buffer - { - 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); - } - // polygon buffer { uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); poly_size *= 1024; poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); - glGenBuffers(1, &data.polygon_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + glGenBuffers(1, &data.vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer); glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); - data.polygon_buffer_size = poly_size; + data.vertex_buffer_size = poly_size; glBindBuffer(GL_ARRAY_BUFFER, 0); uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128); index_size *= 1024; // kb - glGenBuffers(1, &data.polygon_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + glGenBuffers(1, &data.index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); + + data.index_buffer_size = index_size; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } // ninepatch buffers { // array buffer - glGenBuffers(1, &data.ninepatch_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // element buffer - glGenBuffers(1, &data.ninepatch_elements); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); #define _EIDX(y, x) (y * 4 + x) - uint8_t elems[3 * 2 * 9] = { + const int elems[3 * 2 * 9] = { // first row @@ -1149,14 +1195,24 @@ void RasterizerCanvasGLES2::initialize() { ; #undef _EIDX - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); + memcpy(data.ninepatch_elements, elems, sizeof(elems)); + } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + { + const uint32_t size = data.vertex_buffer_size / sizeof(Vertex); + data.mem_vertex_buffer = (Vertex *)memalloc(sizeof(Vertex) * size); + data.mem_vertex_buffer_offset = 0; + data.mem_vertex_buffer_size = size; } - state.canvas_shader.init(); + { + const uint32_t size = data.index_buffer_size / sizeof(int); + data.mem_index_buffer = (int *)memalloc(sizeof(int) * size); + data.mem_index_buffer_offset = 0; + data.mem_index_buffer_size = size; + } - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + state.canvas_shader.init(); state.canvas_shader.bind(); } @@ -1166,3 +1222,92 @@ void RasterizerCanvasGLES2::finalize() { RasterizerCanvasGLES2::RasterizerCanvasGLES2() { } + +void RasterizerCanvasGLES2::_begin(const GLuint p_primitive) { + if (data.primitive != p_primitive) { + _flush(); + data.primitive = p_primitive; + } +} + +void RasterizerCanvasGLES2::_prepare(const int p_vertex_count, const int p_index_count) { + if (data.mem_vertex_buffer_size - data.mem_vertex_buffer_offset < p_vertex_count || + data.mem_index_buffer_size - data.mem_index_buffer_offset < p_index_count) { + _flush(); + } +} + +void RasterizerCanvasGLES2::_draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices) { + glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * p_vertex_count, p_vertices); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL); + + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2)); + + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2) + sizeof(Color)); + + glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasGLES2::_flush() { + if (data.mem_vertex_buffer_offset) { + _draw(data.primitive, data.mem_vertex_buffer_offset, data.mem_vertex_buffer, data.mem_index_buffer_offset, data.mem_index_buffer); + } + + data.mem_vertex_buffer_offset = 0; + data.mem_index_buffer_offset = 0; +} + +void RasterizerCanvasGLES2::_commit(const int p_vertex_count, const int p_index_count) { + ERR_FAIL_COND(!p_vertex_count); + ERR_FAIL_COND(!p_index_count); + + if (state.uniforms.extra_matrix != state.prev_uniforms.extra_matrix || + state.uniforms.final_modulate != state.prev_uniforms.final_modulate || + state.uniforms.modelview_matrix != state.prev_uniforms.modelview_matrix || + state.uniforms.projection_matrix != state.prev_uniforms.projection_matrix || + state.uniforms.texpixel_size != state.prev_uniforms.texpixel_size || + state.uniforms.time != state.prev_uniforms.time) { + + _set_uniforms(); + state.prev_uniforms = state.uniforms; + _flush(); + } + + const int new_index_offset = data.mem_index_buffer_offset + p_index_count; + + for (int i = data.mem_index_buffer_offset; i < new_index_offset; ++i) + data.mem_index_buffer[i] += data.mem_vertex_buffer_offset; + + data.mem_vertex_buffer_offset += p_vertex_count; + data.mem_index_buffer_offset = new_index_offset; +} + +void RasterizerCanvasGLES2::_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); + + state.tiled = false; +} + +void RasterizerCanvasGLES2::_bind_shader(RasterizerStorageGLES2::Material *p_material) { + if (!state.canvas_shader.is_dirty()) { + return; + } + + _flush(); + + if (state.canvas_shader.bind()) { + state.canvas_shader.use_material((void *)p_material); + } +} diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index cda3ec79e7..d5a122e533 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -50,23 +50,44 @@ public: Color final_modulate; float time; + + Size2 texpixel_size; + }; + + struct Vertex { + Vector2 v; + Color c; + Vector2 uv; }; struct Data { - GLuint canvas_quad_vertices; - GLuint polygon_buffer; - GLuint polygon_index_buffer; + GLuint vertex_buffer; + GLuint index_buffer; + + uint32_t vertex_buffer_size; + uint32_t index_buffer_size; + + int ninepatch_elements[3 * 2 * 9]; - uint32_t polygon_buffer_size; + int *mem_index_buffer; + uint32_t mem_index_buffer_offset; + uint32_t mem_index_buffer_size; - GLuint ninepatch_vertices; - GLuint ninepatch_elements; + Vertex *mem_vertex_buffer; + uint32_t mem_vertex_buffer_offset; + uint32_t mem_vertex_buffer_size; + GLuint primitive; + GLuint texture; } data; struct State { Uniforms uniforms; + Uniforms prev_uniforms; + + bool tiled; + bool canvas_texscreen_used; CanvasShaderGLES2 canvas_shader; // CanvasShadowShaderGLES3 canvas_shadow_shader; @@ -99,9 +120,16 @@ public: _FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false); - _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(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + + _FORCE_INLINE_ void _begin(const GLuint p_primitive); + _FORCE_INLINE_ void _prepare(const int p_vertex_count, const int p_index_count); + _FORCE_INLINE_ void _commit(const int p_vertex_count, const int p_index_count); + + _FORCE_INLINE_ void _flush(); + _FORCE_INLINE_ void _draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices); + + _FORCE_INLINE_ void _untile(); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material); _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); @@ -114,8 +142,8 @@ public: virtual void reset_canvas(); RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); + _FORCE_INLINE_ void _bind_shader(RasterizerStorageGLES2::Material *p_material); - void _bind_quad_buffer(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); void initialize(); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index a1a0b9e2c6..165ffc0412 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -345,9 +345,6 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); - canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - canvas->state.canvas_shader.set_custom_shader(0); canvas->state.canvas_shader.bind(); @@ -359,7 +356,7 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re // TODO normals - canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); + canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 1, 1, -1)); glBindTexture(GL_TEXTURE_2D, 0); canvas->canvas_end(); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index c1fbf73254..38c0ccaac2 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -252,7 +252,7 @@ public: int mipmaps; bool active; - GLenum tex_id; + GLuint tex_id; uint16_t stored_cube_sides; @@ -429,6 +429,8 @@ public: bool uses_screen_texture; bool uses_screen_uv; bool uses_time; + bool uses_modelview_matrix; + bool uses_vertex; } canvas_item; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index e9b58cb272..89c1b6490d 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -122,13 +122,11 @@ GLint ShaderGLES2::get_uniform_location(int p_index) const { } bool ShaderGLES2::bind() { - - if (active != this || !version || new_conditional_version.key != conditional_version.key) { - conditional_version = new_conditional_version; - version = get_current_version(); - } else { + if (!is_dirty()) return false; - } + + conditional_version = new_conditional_version; + version = get_current_version(); ERR_FAIL_COND_V(!version, false); @@ -1109,3 +1107,7 @@ ShaderGLES2::ShaderGLES2() { ShaderGLES2::~ShaderGLES2() { finish(); } + +bool ShaderGLES2::is_dirty() const { + return active != this || !version || new_conditional_version.key != conditional_version.key; +} diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index cb515c199c..99513abfe9 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -208,6 +208,7 @@ public: GLint get_uniform_location(int p_index) const; static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; } + bool is_dirty() const; bool bind(); void unbind(); void bind_uniforms(); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 29d81bb2c4..a63c7675d8 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -20,13 +20,6 @@ varying vec4 color_interp; uniform highp vec2 color_texpixel_size; -#ifdef USE_TEXTURE_RECT - -uniform vec4 dst_rect; -uniform vec4 src_rect; - -#endif - uniform highp float time; VERTEX_SHADER_GLOBALS @@ -44,35 +37,9 @@ void main() { vec4 color = color_attrib; -#ifdef USE_TEXTURE_RECT - - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; - } - - vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); - - // This is what is done in the GLES 3 bindings and should - // take care of flipped rects. - // - // But it doesn't. - // I don't know why, will need to investigate further. - - outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); - - // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; -#else vec4 outvec = vec4(vertex.xy, 0.0, 1.0); -#ifdef USE_UV_ATTRIBUTE uv_interp = uv_attrib; -#else - uv_interp = vertex.xy; -#endif - -#endif { vec2 src_vtx=outvec.xy; |