I'm trying to make a GUI:
#include <iostream>
#include "header/spgui.h"
// Declare global variables without immediate initialization.
GLuint VAO, VBO, EBO;
GLuint shaderProgram;
struct Vertex {
glm::vec2 position; // (x, y)
glm::vec2 texCoords; // (u, v)
glm::vec4 color; // (r, g, b, a)
};
// struct PageVertex {
// Vertex Page;
// };
// Vector to hold all UI elements
std::vector<Widget> uiElements;
std::vector<float> vertices; // Stores position and color
std::vector<unsigned int> indices;
unsigned int indexOffset = 0; // Keeps track of the current index offset
void SWidget(const Widget& data) {
uiElements.push_back(data);
}
void addvertices(float x, float y, float width, float height, float r, float g, float b) {
int screenWidth, screenHeight;
glfwGetFramebufferSize(getWindow(), &screenWidth, &screenHeight); // Get current window size
// Convert pixel values to normalized device coordinates (NDC)
float xNDC = (x / screenWidth) * 2.0f - 1.0f;
float yNDC = (y / screenHeight) * 2.0f - 1.0f;
float widthNDC = (width / screenWidth) * 2.0f;
float heightNDC = (height / screenHeight) * 2.0f;
// Append vertex positions and colors
vertices.insert(vertices.end(), {
xNDC, yNDC, r, g, b, // Bottom-left
xNDC + widthNDC, yNDC, r, g, b, // Bottom-right
xNDC + widthNDC, yNDC + heightNDC, r, g, b, // Top-right
xNDC, yNDC + heightNDC, r, g, b // Top-left
});
// Append indices, adjusting for the current index offset
indices.insert(indices.end(), {
indexOffset, indexOffset + 1, indexOffset + 2, // First triangle
indexOffset + 2, indexOffset + 3, indexOffset // Second triangle
});
// Increase index offset by 4 since each box adds 4 new vertices
indexOffset += 4;
}
std::array<float, 2> setAnchor(const Widget& data) {
int screenWidth, screenHeight;
glfwGetFramebufferSize(getWindow(), &screenWidth, &screenHeight);
float xAnchor = 0, yAnchor = 0;
if (data.anchor == "center") {
xAnchor = (screenWidth / 2.0f) - (data.width / 2.0f);
yAnchor = (screenHeight / 2.0f) - (data.height / 2.0f);
}
return {xAnchor, yAnchor};
}
//Object Setup
void addBox(const Widget& data) {
if(data.anchor != ""){
auto [anchorX, anchorY] = setAnchor(data); // Destructure directly
addvertices(data.posX + anchorX, data.posY + anchorY, data.width, data.height, data.colorR, data.colorG, data.colorB);
}else {
addvertices(data.posX, data.posY, data.width, data.height, data.colorR, data.colorG, data.colorB);
}
}
void setupSWidget(){
vertices.clear();
indices.clear();
for (const auto& w : uiElements) {
std::cout << "Widget: " << w.name << std::endl;
std::string Sobject = w.object;
if (Sobject == "box") {
addBox(w );
} else if (Sobject == "button") {
// Handle case "2" if needed
}
}
//refreshBuffers();
//std::cout << "Vertices count after setup: " << vertices.size() << ", Indices count: " << indices.size() << std::endl;
}
// void moveWidget(const std::string& widgetName, float deltaX, float deltaY) {
// bool widgetFound = false;
// for (auto& widget : uiElements) {
// if (widget.name == widgetName) {
// widget.posX += deltaX;
// widget.posY += deltaY;
// widgetFound = true;
// break; // Stop searching once found
// }
// }
// if (!widgetFound) {
// std::cerr << "Warning: Widget with name '" << widgetName << "' not found!" << std::endl;
// return;
// }
// // Recompute the vertices
// setupSWidget();
// // Update GPU buffers
// refreshBuffers();
// }
// struct Object {
// float x, y; // Position
// };
// // List of objects
// std::vector<Object> objects;
// Move a specific object
void moveWidget(int index, float dx, float dy) {
if (index >= 0 && index < vertices.size() / 5 - 3) { // Ensure it's within bounds
int baseIndex = index * 5; // Each vertex has 5 floats (x, y, r, g, b)
// Move all four vertices
vertices[baseIndex] += dx; // Bottom-left x
vertices[baseIndex + 5] += dx; // Bottom-right x
vertices[baseIndex + 10] += dx; // Top-right x
vertices[baseIndex + 15] += dx; // Top-left x
vertices[baseIndex + 1] += dy; // Bottom-left y
vertices[baseIndex + 6] += dy; // Bottom-right y
vertices[baseIndex + 11] += dy; // Top-right y
vertices[baseIndex + 16] += dy; // Top-left y
}
}
//======================================================================================================
// Function: Check for OpenGL errors and output their location
void checkOpenGLError(const std::string& location) {
GLenum error = glGetError();
while (error != GL_NO_ERROR) {
std::string errorMessage;
switch (error) {
case GL_INVALID_ENUM: errorMessage = "GL_INVALID_ENUM"; break;
case GL_INVALID_VALUE: errorMessage = "GL_INVALID_VALUE"; break;
case GL_INVALID_OPERATION: errorMessage = "GL_INVALID_OPERATION"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: errorMessage = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
case GL_OUT_OF_MEMORY: errorMessage = "GL_OUT_OF_MEMORY"; break;
default: errorMessage = "Unknown Error"; break;
}
std::cerr << "OpenGL Error at " << location << ": " << errorMessage << std::endl;
error = glGetError();
}
}
// Function: Set up shaders, buffers, and vertex attributes
void createshader() {
// Create the shader program
shaderProgram = glCreateProgram();
// Vertex Shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Check for vertex shader compile errors
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cerr << "ERROR: Vertex Shader Compilation Failed\n" << infoLog << std::endl;
}
// Fragment Shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for fragment shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cerr << "ERROR: Fragment Shader Compilation Failed\n" << infoLog << std::endl;
}
// Link Shaders to the Shader Program
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cerr << "ERROR: Shader Program Linking Failed\n" << infoLog << std::endl;
}
// Delete shaders as they are now linked into the program
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// Set uniform color if needed here (or in your render loop)
// Generate VAO, VBO, and EBO
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO); // Persistent EBO
glBindVertexArray(VAO);
// Upload initial vertex data
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
// Upload initial index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_DYNAMIC_DRAW);
// Define position attribute (x, y)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Define color attribute (r, g, b)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// Unbind VAO (optional)
glBindVertexArray(0);
}
// Function: Refresh buffers with the latest vertices and indices data
void refreshBuffers() {
std::cout << "Refreshing Buffers: " << vertices.size() << " vertices, " << indices.size() << " indices." << std::endl;
glBindVertexArray(VAO); // Bind the VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); // Bind the VBO
if (!vertices.empty()) {
// Use offset 0 to update the entire buffer
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(float), vertices.data());
checkOpenGLError("glBufferSubData (GL_ARRAY_BUFFER)");
} else {
std::cerr << "Error: Vertices buffer is empty!" << std::endl;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Bind the EBO
if (!indices.empty()) {
// Use offset 0 to update the entire buffer
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indices.size() * sizeof(unsigned int), indices.data());
checkOpenGLError("glBufferSubData (GL_ELEMENT_ARRAY_BUFFER)");
} else {
std::cerr << "Error: Indices buffer is empty!" << std::endl;
}
glBindVertexArray(0); // Unbind the VAO
}
// Function: Render UI elements
void renderUI() {
// Bind default framebuffer (already complete, no need to check)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Update vertex buffer data ONLY if needed
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(float), vertices.data());
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Bind shader program
glUseProgram(shaderProgram);
// Bind VAO and EBO
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Ensure the EBO is bound
// Render UI
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, 0);
// Unbind VAO (good practice)
glBindVertexArray(0);
}
// Function: Clean up OpenGL objects
void deleteObjects() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
}
...but I can't move any object without it disappearing.
When you call moveWidget(); it's supposed to move one of the objects, but its not.