#include "Renderer.h" #include "Log.h" #include "AssetManager.h" #include "Texture.h" #include Renderer* Renderer::ptr = nullptr; static const char* g_vert_src = "#version 300 es \n" "precision mediump float; \n" "uniform vec2 res; // resolution \n" "layout (location = 0) in vec2 v_p0; // top left corner on screen \n" "layout (location = 1) in vec2 v_p1; // top right corner on screen \n" "layout (location = 2) in vec2 v_src_p0; \n" "layout (location = 3) in vec2 v_src_p1; \n" "layout (location = 4) in vec4 v_color; // color \n" "layout (location = 5) in int v_expand_r; // \n" "out vec4 f_color; \n" "out vec2 f_uv; \n" "flat out int f_expand_r; \n" "const vec2 vertices[6] = vec2[6]( \n" " vec2(-1,-1), \n" " vec2(+1, -1), \n" " vec2(-1, +1), \n" " vec2(+1, -1), \n" " vec2(+1, +1), \n" " vec2(-1, +1) \n" "); \n" "void main() \n" "{ \n" " vec2 v = vertices[gl_VertexID]; \n" " // destination on screen \n" " //vec2 dst_half_size = (v_p1 - v_p0) / 2.0; \n" " //vec2 dst_center = (v_p1 + v_p0) / 2.0; \n" " vec2 dst_pos = v * ((v_p1 - v_p0) / 2.0) + ((v_p1 + v_p0) / 2.0); \n" " dst_pos.y = res.y - dst_pos.y; \n" " vec2 src = v * ((v_src_p1 - v_src_p0) / 2.0) + ((v_src_p1 + v_src_p0) / 2.0); \n" " gl_Position = vec4(2.0 * dst_pos.x / res.x - 1.0, \n" " 2.0 * dst_pos.y / res.y - 1.0, \n" " 0.0, \n" " 1.0); \n" " f_color = v_color; \n" " f_uv = src; \n" " f_expand_r = v_expand_r; \n" "} \n"; static const char* g_frag_src = "#version 300 es \n" "precision mediump float; \n" "in vec2 f_uv; \n" "in vec4 f_color; \n" "flat in int f_expand_r; \n" "layout (location = 0) out vec4 frag_color; \n" "uniform sampler2D s_texture; \n" "void main() \n" "{ \n" " vec4 tex_color = texture(s_texture, f_uv); \n" " if (f_expand_r == 1) \n" " tex_color = tex_color.rrrr; \n" " frag_color = tex_color * f_color; \n" "} \n"; void Renderer::create() { Renderer::ptr = new Renderer; } void Renderer::destroy() { delete Renderer::ptr; Renderer::ptr = nullptr; } Renderer::Renderer() { GLuint vertex = 0, fragment = 0; vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &g_vert_src, nullptr); glCompileShader(vertex); int status = 0; glGetShaderiv(vertex, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { char info[512]; glGetShaderInfoLog(vertex, 512, nullptr, info); ALOGE("Failed to compile ui vertex shader: %s", info); } fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &g_frag_src, nullptr); glCompileShader(fragment); glGetShaderiv(fragment, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { char info[512]; glGetShaderInfoLog(fragment, 512, nullptr, info); ALOGE("Failed to compile ui fragment shader: %s", info); } m_shader = glCreateProgram(); glAttachShader(m_shader, vertex); glAttachShader(m_shader, fragment); glLinkProgram(m_shader); glGetProgramiv(m_shader, GL_LINK_STATUS, &status); if (status != GL_TRUE) { char info[512]; glGetProgramInfoLog(m_shader, 512, nullptr, info); ALOGE("Failed to link ui shader: %s", info); } glDeleteShader(vertex); glDeleteShader(fragment); glGenBuffers(1, &m_vbo); glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); glBindBuffer(GL_ARRAY_BUFFER, m_vbo); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(2 * sizeof(float))); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(4 * sizeof(float))); glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(6 * sizeof(float))); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(8 * sizeof(float))); glVertexAttribPointer(5, 1, GL_INT, GL_FALSE, sizeof(Rect), (GLvoid*)(12 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glVertexAttribDivisor(0, 1); glVertexAttribDivisor(1, 1); glVertexAttribDivisor(2, 1); glVertexAttribDivisor(3, 1); glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glBindVertexArray(0); // Dummy texture (1x1px white) unsigned char tex[] = {255, 255, 255, 255}; Texture dummy_texture(1, 1, tex); m_textures.insert(std::make_pair(0, dummy_texture)); m_dummy_texture = 0; } Renderer::~Renderer() { for (auto texture : m_textures) texture.second.destroy(); glDeleteProgram(m_shader); glDeleteVertexArrays(1, &m_vao); glDeleteBuffers(1, &m_vbo); } void Renderer::addRect(float x, float y, float w, float h) { addRect(x, y, w, h, 1.f, 1.f, 1.f, 1.f, m_dummy_texture, 0.f, 0.f, 1.f, 1.f); } void Renderer::addRect(float x, float y, float w, float h, StringHandle texture) { addRect(x, y, w, h, 1.f, 1.f, 1.f, 1.f, texture, 0.f, 0.f, 1.f, 1.f); } void Renderer::addRect(float x, float y, float w, float h, float r, float g, float b, float a) { addRect(x, y, w, h, r, g, b, a, m_dummy_texture, 0.f, 0.f, 1.f, 1.f); } void Renderer::addRect(float x, float y, float w, float h, float r, float g, float b, float a, StringHandle texture) { addRect(x, y, w, h, r, g, b, a, texture, 0.f, 0.f, 1.f, 1.f); } void Renderer::addRect(float x, float y, float w, float h, StringHandle texture, float src_x, float src_y, float src_w, float src_h) { addRect(x, y, w, h, 1.f, 1.f, 1.f, 1.f, texture, src_x, src_y, src_w, src_h); } void Renderer::addRect(float x, float y, float w, float h, float r, float g, float b, float a, StringHandle texture, float src_x, float src_y, float src_w, float src_h) { if (m_textures.find(texture) == m_textures.end()) { Texture tex; if (!AssetManager::ptr->loadTexture(StringRepository::global->getString(texture), &tex)) { ALOGE("Failed to load texture"); return; } m_textures.insert(std::make_pair(texture, tex)); } Rect rect = {}; rect.dst_p0_x = x; rect.dst_p0_y = y; rect.dst_p1_x = x + w; rect.dst_p1_y = y + h; rect.src_p0_x = src_x; rect.src_p0_y = src_y; rect.src_p1_x = src_x + src_w; rect.src_p1_y = src_y + src_h; rect.r = r; rect.g = g; rect.b = b; rect.a = a; rect.expand_r = 0; m_rects.push_back(rect); m_draw_textures.push_back(texture); } void Renderer::addFontRect(float x, float y, float w, float h, float char_height, StringHandle font, StringHandle id, float src_x0, float src_y0, float src_x1, float src_y1) { addFontRect(x, y, w, h, 0.f, 0.f, 0.f, 1.f, char_height, font, id, src_x0, src_y0, src_x1, src_y1); } void Renderer::addFontRect(float x, float y, float w, float h, float r, float g, float b, float a, float char_height, StringHandle font, StringHandle id, float src_x0, float src_y0, float src_x1, float src_y1) { if (m_textures.find(id) == m_textures.end()) { Texture tex; if (!AssetManager::ptr->loadFontBitmap(StringRepository::global->getString(font), char_height, &tex)) { ALOGE("Failed to load texture"); return; } m_textures.insert(std::make_pair(id, tex)); } Rect rect = {}; rect.dst_p0_x = x; rect.dst_p0_y = y; rect.dst_p1_x = x + w; rect.dst_p1_y = y + h; rect.src_p0_x = src_x0; rect.src_p0_y = src_y0; rect.src_p1_x = src_x1; rect.src_p1_y = src_y1; rect.r = r; rect.g = g; rect.b = b; rect.a = a; rect.expand_r = 1; m_rects.push_back(rect); m_draw_textures.push_back(id); } void Renderer::renderFrame(float width, float height) { assert(m_rects.size() == m_draw_textures.size()); glViewport(0, 0, static_cast(width), static_cast(height)); //glClearColor(0.8f, 0.3f, 0.3f, 1.f); glClearColor(0.0f, 0.0f, 0.0f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); const auto rect_count = static_cast(m_rects.size()); if (rect_count == 0) return; glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindVertexArray(m_vao); glUseProgram(m_shader); glUniform2f(glGetUniformLocation(m_shader, "res"), width, height); glUniform1i(glGetUniformLocation(m_shader, "s_texture"), 0); glBindBuffer(GL_ARRAY_BUFFER, m_vbo); size_t start = 0; StringHandle current_texture = m_draw_textures[0]; while (start < rect_count) { glActiveTexture(GL_TEXTURE0); m_textures[current_texture].bind(); for (size_t i = start; i < rect_count; ++i) { StringHandle texture = m_draw_textures[i]; if ((texture != current_texture)) { // Draw everything in [start, i - 1] const size_t count = i - start; glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(Rect) * count), &m_rects[start], GL_STREAM_DRAW); glDrawArraysInstanced(GL_TRIANGLES, 0, 6, static_cast(count)); start = i; current_texture = texture; break; } if (i == rect_count - 1) { // just draw it const size_t count = rect_count - start; glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(Rect) * count), &m_rects[start], GL_STREAM_DRAW); glDrawArraysInstanced(GL_TRIANGLES, 0, 6, static_cast(count)); start = rect_count; current_texture = texture; } } } m_rects.clear(); m_draw_textures.clear(); } void Renderer::getTextureSize( StringHandle texture, unsigned int* w, unsigned int* h) { if (m_textures.find(texture) == m_textures.end()) { Texture tex; if (!AssetManager::ptr->loadTexture(StringRepository::global->getString(texture), &tex)) { ALOGE("Failed to load texture"); return; } m_textures.insert(std::make_pair(texture, tex)); } Texture tex = m_textures[texture]; tex.getTextureSize(w, h); }