Created
June 19, 2025 00:40
-
-
Save EncodeTheCode/3b5d54a032406b9956988c4a89b6494b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Image2D_OpenGL.cpp | |
#include <glad/glad.h> | |
#include <GLFW/glfw3.h> | |
#include <stb_image.h> | |
#include <glm/glm.hpp> | |
#include <glm/gtc/matrix_transform.hpp> | |
#include <glm/gtc/type_ptr.hpp> | |
#include <iostream> | |
#include <unordered_map> | |
#include <string> | |
/////////////////////////// | |
// Image2D Class | |
/////////////////////////// | |
class Image2D { | |
public: | |
Image2D(const std::string& path); | |
void draw(GLuint shader); | |
void setPosition(float x, float y); | |
void move(float dx, float dy); | |
void setScale(float scaleX, float scaleY); | |
void setSize(float newWidth, float newHeight); | |
void show(); | |
void hide(); | |
bool isVisible() const; | |
unsigned int getID() const; | |
static Image2D* getImageByID(unsigned int id); | |
static void removeImageByID(unsigned int id); | |
private: | |
static unsigned int nextID; | |
static std::unordered_map<unsigned int, Image2D*> imageRegistry; | |
unsigned int id; | |
GLuint textureID; | |
float x, y; | |
float scaleX, scaleY; | |
int width, height; | |
bool visible; | |
void loadFromFile(const std::string& path); | |
}; | |
// Static variables | |
unsigned int Image2D::nextID = 1; | |
std::unordered_map<unsigned int, Image2D*> Image2D::imageRegistry; | |
// External VAO | |
GLuint gVAO = 0, gVBO = 0; | |
void InitImageRenderer() { | |
float quadVertices[] = { | |
// pos // tex | |
0.0f, 1.0f, 0.0f, 1.0f, | |
1.0f, 0.0f, 1.0f, 0.0f, | |
0.0f, 0.0f, 0.0f, 0.0f, | |
0.0f, 1.0f, 0.0f, 1.0f, | |
1.0f, 1.0f, 1.0f, 1.0f, | |
1.0f, 0.0f, 1.0f, 0.0f | |
}; | |
glGenVertexArrays(1, &gVAO); | |
glGenBuffers(1, &gVBO); | |
glBindVertexArray(gVAO); | |
glBindBuffer(GL_ARRAY_BUFFER, gVBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); | |
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); // pos | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); // tex | |
glEnableVertexAttribArray(1); | |
} | |
Image2D::Image2D(const std::string& path) { | |
id = nextID++; | |
x = y = 0; | |
scaleX = scaleY = 1.0f; | |
visible = true; | |
loadFromFile(path); | |
imageRegistry[id] = this; | |
} | |
void Image2D::loadFromFile(const std::string& path) { | |
int channels; | |
stbi_set_flip_vertically_on_load(true); | |
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0); | |
if (!data) { | |
std::cerr << "Failed to load: " << path << "\n"; | |
textureID = 0; | |
return; | |
} | |
GLenum format = (channels == 4) ? GL_RGBA : GL_RGB; | |
glGenTextures(1, &textureID); | |
glBindTexture(GL_TEXTURE_2D, textureID); | |
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
stbi_image_free(data); | |
} | |
void Image2D::draw(GLuint shader) { | |
if (!visible || textureID == 0) return; | |
glm::mat4 model(1.0f); | |
model = glm::translate(model, glm::vec3(x, y, 0.0f)); | |
model = glm::scale(model, glm::vec3(width * scaleX, height * scaleY, 1.0f)); | |
GLint uTransform = glGetUniformLocation(shader, "uTransform"); | |
GLint uTexture = glGetUniformLocation(shader, "uTexture"); | |
glUseProgram(shader); | |
glUniformMatrix4fv(uTransform, 1, GL_FALSE, glm::value_ptr(model)); | |
glUniform1i(uTexture, 0); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, textureID); | |
glBindVertexArray(gVAO); | |
glDrawArrays(GL_TRIANGLES, 0, 6); | |
} | |
// Position/Scaling/Visibility | |
void Image2D::setPosition(float newX, float newY) { x = newX; y = newY; } | |
void Image2D::move(float dx, float dy) { x += dx; y += dy; } | |
void Image2D::setScale(float sX, float sY) { scaleX = sX; scaleY = sY; } | |
void Image2D::setSize(float newW, float newH) { | |
scaleX = newW / width; | |
scaleY = newH / height; | |
} | |
void Image2D::show() { visible = true; } | |
void Image2D::hide() { visible = false; } | |
bool Image2D::isVisible() const { return visible; } | |
unsigned int Image2D::getID() const { return id; } | |
Image2D* Image2D::getImageByID(unsigned int id) { | |
auto it = imageRegistry.find(id); | |
return (it != imageRegistry.end()) ? it->second : nullptr; | |
} | |
void Image2D::removeImageByID(unsigned int id) { | |
auto it = imageRegistry.find(id); | |
if (it != imageRegistry.end()) { | |
glDeleteTextures(1, &it->second->textureID); | |
delete it->second; | |
imageRegistry.erase(it); | |
} | |
} | |
/////////////////////////// | |
// Shader Example (basic) | |
/////////////////////////// | |
const char* vertexShaderSource = R"( | |
#version 330 core | |
layout (location = 0) in vec2 aPos; | |
layout (location = 1) in vec2 aTex; | |
uniform mat4 uTransform; | |
out vec2 TexCoord; | |
void main() { | |
gl_Position = uTransform * vec4(aPos, 0.0, 1.0); | |
TexCoord = aTex; | |
} | |
)"; | |
const char* fragmentShaderSource = R"( | |
#version 330 core | |
in vec2 TexCoord; | |
out vec4 FragColor; | |
uniform sampler2D uTexture; | |
void main() { | |
FragColor = texture(uTexture, TexCoord); | |
} | |
)"; | |
GLuint CompileShader(GLenum type, const char* src) { | |
GLuint shader = glCreateShader(type); | |
glShaderSource(shader, 1, &src, nullptr); | |
glCompileShader(shader); | |
return shader; | |
} | |
GLuint CreateShaderProgram() { | |
GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShaderSource); | |
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); | |
GLuint program = glCreateProgram(); | |
glAttachShader(program, vs); | |
glAttachShader(program, fs); | |
glLinkProgram(program); | |
glDeleteShader(vs); | |
glDeleteShader(fs); | |
return program; | |
} | |
/////////////////////////// | |
// Main Example | |
/////////////////////////// | |
int main() { | |
glfwInit(); | |
GLFWwindow* window = glfwCreateWindow(800, 600, "Image2D Demo", nullptr, nullptr); | |
glfwMakeContextCurrent(window); | |
gladLoadGL(); | |
InitImageRenderer(); | |
GLuint shader = CreateShaderProgram(); | |
Image2D* img = new Image2D("image.png"); | |
img->setPosition(100, 150); | |
img->setSize(128, 128); | |
unsigned int id = img->getID(); | |
while (!glfwWindowShouldClose(window)) { | |
glfwPollEvents(); | |
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) img->move(2.0f, 0.0f); | |
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) img->move(-2.0f, 0.0f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
img->draw(shader); | |
glfwSwapBuffers(window); | |
} | |
Image2D::removeImageByID(id); | |
glfwTerminate(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment