Witam, ostatnio zaciekawiłem się klasą renderowania 2d, którą oferuje imgui. Postanowiłem na bardzo podobnej zasadzie zrobić to w swojej aplikacji.
class TestRenderer
{
public:
TestRenderer();
~TestRenderer();
void Create();
void DrawRect(const Rect& rect, GLuint color, float thickness);
void Present();
private:
void MapBuffer(int numVertices, int numElements);
void AddVertexData(GLuint index, const Vector2& position, GLuint color);
void AddElementData(GLuint index, GLuint value);
void AddRectElements();
void CreatePolygon(const Vector2* vertices, const GLuint verticesCount, GLuint color, float thickness);
private:
GLuint vao = 0, // vertex array
vbo = 0, // vertex buffer
ebo = 0, // index buffer
currentVertexIndex = 0,
* mappedElement = nullptr;
Vertex* mappedVertex = nullptr;
std::vector<Vertex> vertexBuffer; // vertex data
std::vector<GLuint> elementBuffer; // index data
std::vector<Vector2> vertices; // vertices positions
};
void TestRenderer::Create()
{
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}
void TestRenderer::Present()
{
Mat4 projection = Mat4(1.0f);
projection = glm::ortho(0.0f, 1280.0f, 720.0f, 0.0f);
shader->UseProgram();
shader->UniformMatrix4fv("projection", projection);
GLuint elemCount = elementBuffer.size();
vao = vao->Create();
vao->BindVertexArray();
glBindBuffers(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(Vertex), (const void*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), (const void*)offsetof(Vertex, color));
glBufferData(GL_ARRAY_BUFFER, vertexBuffer.size() * sizeof(Vertex), vertexBuffer.data(), GL_DYNAMIC_DRAW);
glBindBuffers(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, elementBuffer.size() * sizeof(GLuint), elementBuffer.data(), GL_DYNAMIC_DRAW);
vertexBuffer.clear();
elementBuffer.clear();
const unsigned short* elementBufferOffset = 0;
glDrawElements(GL_TRIANGLES, elemCount, GL_UNSIGNED_INT, elementBufferOffset);
elementBufferOffset += elemCount;
glDeleteVertexArrays(1, &vao);
}
void TestRenderer::CreatePolygon(const Vector2* vertices, const GLuint verticesCount, GLuint color, float thickness)
{
if (verticesCount < 2) {
return;
}
// Do stworzenia na przykład niewypełnionego kwadrata potrzebujemy 4 wypełnionych prostokątów
// Więc, niewypełniony kwadrat jest zbudowany z 4 prostokątów, a każdy z nich zawiera 4 wierzchołki ( *4) i 6 indeksów ( * 6)
MapBuffer(verticesCount * 4, verticesCount * 6);
for (GLuint i = 0; i < verticesCount; ++i)
{
const int j = (i + 1) == verticesCount ? 0 : i + 1;
const Vector2& position1 = vertices[i];
const Vector2& position2 = vertices[j];
Vector2 difference = position2 - position1;
difference *= difference.Magnitude() > 0 ? 1.0f / difference.Magnitude() : 1.0f;
const float dx = difference.x * (thickness * 0.5f);
const float dy = difference.y * (thickness * 0.5f);
AddVertexData(0, Vector2(position1.x + dy, position1.y - dx), color);
AddVertexData(1, Vector2(position2.x + dy, position2.y - dx), color);
AddVertexData(2, Vector2(position2.x - dy, position2.y + dx), color);
AddVertexData(3, Vector2(position1.x - dy, position1.y + dx), color);
AddRectElements();
mappedVertex += 4;
currentVertexIndex += 4;
}
this->vertices.clear();
}
void TestRenderer::AddVertexData(GLuint index, const Vector2& position, GLuint color)
{
mappedVertex[index].position = position;
mappedVertex[index].color = color;
}
void TestRenderer::AddRectElements()
{
AddElementData(0, currentVertexIndex);
AddElementData(1, currentVertexIndex + 1);
AddElementData(2, currentVertexIndex + 2);
AddElementData(3, currentVertexIndex + 2);
AddElementData(4, currentVertexIndex + 3);
AddElementData(5, currentVertexIndex);
mappedElement += 6;
}
void TestRenderer::AddElementData(GLuint index, GLuint value)
{
mappedElement[index] = value;
}
void TestRenderer::MapBuffer(int numVertices, int numElements)
{
currentVertexIndex = vertexBuffer.size();
// Map vertex buffer
int oldVertexSize = vertexBuffer.size();
vertexBuffer.resize(oldVertexSize + numVertices);
mappedVertex = vertexBuffer.data() + oldVertexSize;
// Map element buffer
int oldIndexSize = elementBuffer.size();
elementBuffer.resize(oldIndexSize + numElements);
mappedElement = elementBuffer.data() + oldIndexSize;
}
void TestRenderer::DrawRect(const Rect& rect, GLuint color, float thickness)
{
// Add vertices
Vector2 position = {rect.x, rect.y};
Vector2 size = {rect.w, rect.h};
vertices.push_back(position);
vertices.push_back(Vector2(size.x, position.y));
vertices.push_back(size);
vertices.push_back(Vector2(position.x, size.y));
// Create rect
CreatePolygon(vertices.data(), vertices.size(), color, thickness);
}
#version 330 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
out vec4 v_color;
uniform mat4 projection;
void main()
{
gl_Position = projection* vec4(a_position, 1.0);
v_color = a_color;
}
#version 330 core
layout (location = 0) out vec4 color;
in vec4 v_color;
void main()
{
color = v_color;
}
void main()
{
//Stwórz okno (1280x720), zainicjuj glew, dodaj shadery
TestRenderer tr;
tr.Create();
while(running)
{
ProcesEvent();
//wyczyść kolor buffer bit
tr.DrawRect(Rect(100.0f, 100.0f, 50.0f, 50.0f, 0xff0080ff, 1.0f);
tr.Present();
}
}
I o ile przy HD wszystko ładnie pięknie, to jak zmieniam szerokość i wysokość to kwadrat zmienia się razem z tym na na przykład prostokąt.
Myślałem, że imgui stosuje jakiegoś typu skalowanie, ale nie mogłem tego znaleźć.
Przy małym thickness niektóre boki kwadratu znikają i pokazują się dopiero jak zwiększę rozdzielczość.
Przy za małej rozdzielczości niektóre boki znikają.
W imgui cały czas wszystko jest na swoim miejscu.
Dlaczego tak się dzieje?
W jaki sposób mogę to zmienić, naprawić?