364 lines
15 KiB
C++
364 lines
15 KiB
C++
#include "Renderer.h"
|
|
#include "Log.h"
|
|
#include "AssetManager.h"
|
|
#include "Texture.h"
|
|
|
|
#include <assert.h>
|
|
|
|
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<int>(width), static_cast<int>(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<GLsizei>(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<GLsizeiptr>(sizeof(Rect) * count),
|
|
&m_rects[start],
|
|
GL_STREAM_DRAW);
|
|
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, static_cast<GLsizei>(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<GLsizeiptr>(sizeof(Rect) * count),
|
|
&m_rects[start],
|
|
GL_STREAM_DRAW);
|
|
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, static_cast<GLsizei>(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);
|
|
} |