Forum

Notifications
Clear all

C++ 3D Video Game Engine

1 Posts
1 Users
0 Reactions
9 Views
 josh
(@josh)
Member Admin
Joined: 2 months ago
Posts: 510
Topic starter  
# C++ 3D Video Game Engine

I'll create a comprehensive folder structure and source code for a C++ 3D game engine with key components.

## Folder Structure

```
GameEngine/
├── src/
│   ├── core/
│   │   ├── engine.cpp
│   │   ├── engine.h
│   │   ├── window.cpp
│   │   ├── window.h
│   │   └── input.cpp
│   │   └── input.h
│   ├── graphics/
│   │   ├── renderer.cpp
│   │   ├── renderer.h
│   │   ├── shader.cpp
│   │   ├── shader.h
│   │   ├── texture.cpp
│   │   ├── texture.h
│   │   ├── mesh.cpp
│   │   ├── mesh.h
│   │   └── camera.cpp
│   │   └── camera.h
│   ├── scene/
│   │   ├── scene.cpp
│   │   ├── scene.h
│   │   ├── gameobject.cpp
│   │   ├── gameobject.h
│   │   └── transform.cpp
│   │   └── transform.h
│   ├── components/
│   │   ├── meshrenderer.cpp
│   │   ├── meshrenderer.h
│   │   ├── camera.cpp
│   │   ├── camera.h
│   │   └── script.cpp
│   │   └── script.h
│   └── main.cpp
├── assets/
│   ├── shaders/
│   │   ├── vertex.glsl
│   │   └── fragment.glsl
│   ├── models/
│   └── textures/
└── CMakeLists.txt
```

## Source Code Implementation

### src/core/engine.h
```cpp
#ifndef ENGINE_H
#define ENGINE_H

#include <memory>
#include "window.h"
#include "input.h"
#include "../graphics/renderer.h"
#include "../scene/scene.h"

class Engine {
private:
    std::unique_ptr<Window> window;
    std::unique_ptr<Renderer> renderer;
    std::unique_ptr<Input> input;
    std::unique_ptr<Scene> scene;
    
    bool isRunning;
    
public:
    Engine();
    ~Engine();
    
    void Initialize();
    void Run();
    void Update(float deltaTime);
    void Render();
    void Shutdown();
    
    Window* GetWindow() { return window.get(); }
    Input* GetInput() { return input.get(); }
    Scene* GetScene() { return scene.get(); }
};

#endif // ENGINE_H
```

### src/core/engine.cpp
```cpp
#include "engine.h"
#include <iostream>

Engine::Engine() : isRunning(false) {
    window = std::make_unique<Window>(1024, 768, "3D Game Engine");
    renderer = std::make_unique<Renderer>();
    input = std::make_unique<Input>();
    scene = std::make_unique<Scene>();
}

Engine::~Engine() {
    Shutdown();
}

void Engine::Initialize() {
    if (!window->Initialize()) {
        std::cerr << "Failed to initialize window!" << std::endl;
        return;
    }
    
    if (!renderer->Initialize()) {
        std::cerr << "Failed to initialize renderer!" << std::endl;
        return;
    }
    
    isRunning = true;
    std::cout << "Engine initialized successfully!" << std::endl;
}

void Engine::Run() {
    float deltaTime = 0.0f;
    float lastFrame = 0.0f;
    
    while (isRunning && !window->ShouldClose()) {
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
        
        input->Update();
        Update(deltaTime);
        Render();
        
        window->SwapBuffers();
        glfwPollEvents();
    }
}

void Engine::Update(float deltaTime) {
    scene->Update(deltaTime);
}

void Engine::Render() {
    renderer->Clear();
    scene->Render(renderer.get());
}

void Engine::Shutdown() {
    isRunning = false;
    std::cout << "Engine shutdown complete!" << std::endl;
}
```

### src/core/window.h
```cpp
#ifndef WINDOW_H
#define WINDOW_H

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>

class Window {
private:
    GLFWwindow* window;
    int width, height;
    std::string title;
    
public:
    Window(int width, int height, const std::string& title);
    ~Window();
    
    bool Initialize();
    void SwapBuffers();
    void PollEvents();
    bool ShouldClose() const;
    
    int GetWidth() const { return width; }
    int GetHeight() const { return height; }
    GLFWwindow* GetGLFWWindow() const { return window; }
};

#endif // WINDOW_H
```

### src/core/window.cpp
```cpp
#include "window.h"
#include <iostream>

Window::Window(int width, int height, const std::string& title) 
    : width(width), height(height), title(title) {
    window = nullptr;
}

Window::~Window() {
    if (window) {
        glfwDestroyWindow(window);
    }
    glfwTerminate();
}

bool Window::Initialize() {
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW!" << std::endl;
        return false;
    }
    
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    
    window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
    if (!window) {
        std::cerr << "Failed to create GLFW window!" << std::endl;
        return false;
    }
    
    glfwMakeContextCurrent(window);
    
    // Initialize GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW!" << std::endl;
        return false;
    }
    
    // Set up viewport
    glViewport(0, 0, width, height);
    
    // Enable depth testing
    glEnable(GL_DEPTH_TEST);
    
    return true;
}

void Window::SwapBuffers() {
    glfwSwapBuffers(window);
}

void Window::PollEvents() {
    glfwPollEvents();
}

bool Window::ShouldClose() const {
    return glfwWindowShouldClose(window);
}
```

### src/core/input.h
```cpp
#ifndef INPUT_H
#define INPUT_H

#include <GLFW/glfw3.h>
#include <unordered_map>

class Input {
private:
    std::unordered_map<int, bool> keyStates;
    std::unordered_map<int, bool> previousKeyStates;
    
public:
    void Update();
    bool IsKeyPressed(int key);
    bool IsKeyReleased(int key);
    bool IsKeyDown(int key);
    
    static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
};

#endif // INPUT_H
```

### src/core/input.cpp
```cpp
#include "input.h"
#include <iostream>

void Input::Update() {
    previousKeyStates = keyStates;
}

bool Input::IsKeyPressed(int key) {
    return keyStates[key] && !previousKeyStates[key];
}

bool Input::IsKeyReleased(int key) {
    return !keyStates[key] && previousKeyStates[key];
}

bool Input::IsKeyDown(int key) {
    return keyStates[key];
}

void Input::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    static Input* input = nullptr;
    
    if (input == nullptr) {
        // This is a bit hacky but works for now
        // In a real engine, you'd have a global input manager
        return;
    }
    
    if (action == GLFW_PRESS) {
        input->keyStates[key] = true;
    } else if (action == GLFW_RELEASE) {
        input->keyStates[key] = false;
    }
}
```

### src/graphics/renderer.h
```cpp
#ifndef RENDERER_H
#define RENDERER_H

#include <GL/glew.h>
#include <vector>
#include "../scene/scene.h"
#include "shader.h"

class Renderer {
private:
    Shader* defaultShader;
    
public:
    Renderer();
    ~Renderer();
    
    bool Initialize();
    void Clear();
    void SetClearColor(float r, float g, float b, float a);
    
    void Render(const Scene& scene);
    void DrawMesh(const Mesh& mesh, const Shader& shader);
};

#endif // RENDERER_H
```

### src/graphics/renderer.cpp
```cpp
#include "renderer.h"
#include <iostream>

Renderer::Renderer() {
    defaultShader = nullptr;
}

Renderer::~Renderer() {
    if (defaultShader) {
        delete defaultShader;
    }
}

bool Renderer::Initialize() {
    // Initialize shaders
    defaultShader = new Shader("assets/shaders/vertex.glsl", "assets/shaders/fragment.glsl");
    
    if (!defaultShader->IsCompiled()) {
        std::cerr << "Failed to compile default shader!" << std::endl;
        return false;
    }
    
    return true;
}

void Renderer::Clear() {
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void Renderer::SetClearColor(float r, float g, float b, float a) {
    glClearColor(r, g, b, a);
}

void Renderer::Render(const Scene& scene) {
    // For simplicity, we'll just draw all objects with default shader
    // In a real engine, this would involve culling, sorting, etc.
    for (const auto& gameObject : scene.GetGameObjects()) {
        if (gameObject->GetComponent<MeshRenderer>()) {
            const auto* meshRenderer = gameObject->GetComponent<MeshRenderer>();
            const auto* mesh = meshRenderer->GetMesh();
            if (mesh) {
                // Set up model matrix
                defaultShader->Use();
                defaultShader->SetMat4("model", gameObject->GetTransform()->GetModelMatrix());
                
                DrawMesh(*mesh, *defaultShader);
            }
        }
    }
}

void Renderer::DrawMesh(const Mesh& mesh, const Shader& shader) {
    // Bind VAO and draw
    glBindVertexArray(mesh.GetVAO());
    glDrawElements(GL_TRIANGLES, mesh.GetIndexCount(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}
```

### src/graphics/shader.h
```cpp
#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <GL/glew.h>
#include <glm/glm.hpp>

class Shader {
private:
    GLuint ID;
    bool compiled;
    
    std::string vertexPath;
    std::string fragmentPath;
    
public:
    Shader(const std::string& vertexPath, const std::string& fragmentPath);
    ~Shader();
    
    bool IsCompiled() const { return compiled; }
    
    void Use();
    void SetMat4(const std::string& name, const glm::mat4& mat) const;
    void SetVec3(const std::string& name, const glm::vec3& vec) const;
    
private:
    void CompileShader();
};

#endif // SHADER_H
```

### src/graphics/shader.cpp
```cpp
#include "shader.h"
#include <iostream>
#include <fstream>
#include <sstream>

Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) 
    : vertexPath(vertexPath), fragmentPath(fragmentPath), compiled(false) {
    CompileShader();
}

Shader::~Shader() {
    if (ID != 0) {
        glDeleteProgram(ID);
    }
}

void Shader::CompileShader() {
    // Read shader files
    std::string vertexCode;
    std::string fragmentCode;
    
    try {
        std::ifstream vertexFile(vertexPath);
        std::ifstream fragmentFile(fragmentPath);
        
        if (!vertexFile.is_open()) {
            throw std::runtime_error("Failed to open vertex shader file");
        }
        if (!fragmentFile.is_open()) {
            throw std::runtime_error("Failed to open fragment shader file");
        }
        
        std::stringstream vShaderStream, fShaderStream;
        vShaderStream << vertexFile.rdbuf();
        fShaderStream << fragmentFile.rdbuf();
        
        vertexFile.close();
        fragmentFile.close();
        
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    } catch (const std::exception& e) {
        std::cerr << "Error reading shader files: " << e.what() << std::endl;
        return;
    }
    
    const char* vShaderCode = vertexCode.c_str();
    const char* fShaderCode = fragmentCode.c_str();
    
    // Compile shaders
    GLuint vertex, fragment;
    GLint success;
    GLchar infoLog[512];
    
    // Vertex Shader
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);
    
    glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertex, 512, NULL, infoLog);
        std::cerr << "Vertex shader compilation failed:\n" << infoLog << std::endl;
        return;
    }
    
    // Fragment Shader
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);
    
    glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragment, 512, NULL, infoLog);
        std::cerr << "Fragment shader compilation failed:\n" << infoLog << std::endl;
        return;
    }
    
    // Shader Program
    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    glLinkProgram(ID);
    
    glGetProgramiv(ID, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(ID, 512, NULL, infoLog);
        std::cerr << "Shader program linking failed:\n" << infoLog << std::endl;
        return;
    }
    
    // Clean up
    glDeleteShader(vertex);
    glDeleteShader(fragment);
    
    compiled = true;
}

void Shader::Use() {
    if (compiled) {
        glUseProgram(ID);
    }
}

void Shader::SetMat4(const std::string& name, const glm::mat4& mat) const {
    if (!compiled) return;
    
    glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

void Shader::SetVec3(const std::string& name, const glm::vec3& vec) const {
    if (!compiled) return;
    
    glUniform3f(glGetUniformLocation(ID, name.c_str()), vec.x, vec.y, vec.z);
}
```

### src/graphics/mesh.h
```cpp
#ifndef MESH_H
#define MESH_H

#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>

struct Vertex {
    glm::vec3 Position;
    glm::vec3 Normal;
    glm::vec2 TexCoords;
};

class Mesh {
private:
    std::vector<Vertex> vertices;
    std::vector<unsigned int> indices;
    
    GLuint VAO, VBO, EBO;
    
public:
    Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices);
    ~Mesh();
    
    void SetupMesh();
    void Draw() const;
    
    GLuint GetVAO() const { return VAO; }
    unsigned int GetIndexCount() const { return static_cast<unsigned int>(indices.size()); }
};

#endif // MESH_H
```

### src/graphics/mesh.cpp
```cpp
#include "mesh.h"
#include <iostream>

Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices) 
    : vertices(vertices), indices(indices) {
    SetupMesh();
}

Mesh::~Mesh() {
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}

void Mesh::SetupMesh() {
    // Create buffers/arrays
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    
    glBindVertexArray(VAO);
    
    // Load data into vertex buffers
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
    
    // Set the vertex attribute pointers
    // Vertex Positions
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    
    // Vertex Normals
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
    
    // Vertex Texture Coords
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
    
    glBindVertexArray(0);
}

void Mesh::Draw() const {
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}
```

### src/scene/scene.h
```cpp
#ifndef SCENE_H
#define SCENE_H

#include <vector>
#include <memory>
#include "gameobject.h"
#include "../graphics/renderer.h"

class Scene {
private:
    std::vector<std::unique_ptr<GameObject>> gameObjects;
    
public:
    Scene();
    ~Scene();
    
    void Update(float deltaTime);
    void Render(Renderer* renderer);
    
    GameObject* AddGameObject(std::unique_ptr<GameObject> gameObject);
    const std::vector<std::unique_ptr<GameObject>>& GetGameObjects() const { return gameObjects; }
};

#endif // SCENE_H
```

### src/scene/scene.cpp
```cpp
#include "scene.h"
#include <iostream>

Scene::Scene() {
    // Create default camera
}

Scene::~Scene() {
    // Cleanup
}

void Scene::Update(float deltaTime) {
    for (auto& obj : gameObjects) {
        obj->Update(deltaTime);
    }
}

void Scene::Render(Renderer* renderer) {
    if (renderer) {
        renderer->Render(*this);
    }
}

GameObject* Scene::AddGameObject(std::unique_ptr<GameObject> gameObject) {
    GameObject* ptr = gameObject.get();
    gameObjects.push_back(std::move(gameObject));
    return ptr;
}
```

### src/scene/gameobject.h
```cpp
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H

#include <memory>
#include <vector>
#include "../graphics/mesh.h"
#include "../components/transform.h"

class Component;

class GameObject {
private:
    std::vector<std::unique_ptr<Component>> components;
    Transform* transform;
    
public:
    GameObject();
    ~GameObject();
    
    void Update(float deltaTime);
    
    template<typename T>
    T* AddComponent() {
        static_assert(std::is_base_of<Component, T>::value, "T must inherit from Component");
        std::unique_ptr<T> component = std::make_unique<T>();
        T* ptr = component.get();
        components.push_back(std::move(component));
        return ptr;
    }
    
    template<typename T>
    T* GetComponent() const {
        for (const auto& component : components) {
            if (T* comp = dynamic_cast<T*>(component.get())) {
                return comp;
            }
        }
        return nullptr;
    }
    
    Transform* GetTransform() const { return transform; }
};

#endif // GAMEOBJECT_H
```

### src/scene/gameobject.cpp
```cpp
#include "gameobject.h"
#include "../components/transform.h"

GameObject::GameObject() {
    transform = AddComponent<Transform>();
}

GameObject::~GameObject() {
    // Cleanup components
}

void GameObject::Update(float deltaTime) {
    for (auto& component : components) {
        component->Update(deltaTime);
    }
}
```

### src/components/transform.h
```cpp
#ifndef TRANSFORM_H
#define TRANSFORM_H

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

class Component;

class Transform : public Component {
private:
    glm::vec3 position;
    glm::vec3 rotation;
    glm::vec3 scale;
    
public:
    Transform();
    
    const glm::vec3& GetPosition() const { return position; }
    const glm::vec3& GetRotation() const { return rotation; }
    const glm::vec3& GetScale() const { return scale; }
    
    void SetPosition(const glm::vec3& pos) { position = pos; }
    void SetRotation(const glm::vec3& rot) { rotation = rot; }
    void SetScale(const glm::vec3& sc) { scale = sc; }
    
    glm::mat4 GetModelMatrix() const;
    
    void Update(float deltaTime) override;
};

#endif // TRANSFORM_H
```

### src/components/transform.cpp
```cpp
#include "transform.h"

Transform::Transform() : position(0.0f), rotation(0.0f), scale(1.0f) {
}

glm::mat4 Transform::GetModelMatrix() const {
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, position);
    model = glm::rotate(model, rotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
    model = glm::rotate(model, rotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
    model = glm::rotate(model, rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
    model = glm::scale(model, scale);
    return model;
}

void Transform::Update(float deltaTime) {
    // Transform doesn't need to update anything
}
```

### src/components/component.h
```cpp
#ifndef COMPONENT_H
#define COMPONENT_H

class Component {
public:
    virtual ~Component() = default;
    virtual void Update(float deltaTime) = 0;
};

#endif // COMPONENT_H
```

### src/components/meshrenderer.h
```cpp
#ifndef MESHRENDERER_H
#define MESHRENDERER_H

#include "component.h"
#include "../graphics/mesh.h"

class MeshRenderer : public Component {
private:
    Mesh* mesh;
    
public:
    MeshRenderer();
    
    void SetMesh(Mesh* m) { mesh = m; }
    Mesh* GetMesh() const { return mesh; }
    
    void Update(float deltaTime) override;
};

#endif // MESHRENDERER_H
```

### src/components/meshrenderer.cpp
```cpp
#include "meshrenderer.h"

MeshRenderer::MeshRenderer() : mesh(nullptr) {
}

void MeshRenderer::Update(float deltaTime) {
    // Mesh renderer doesn't need to update anything
}
```

### src/main.cpp
```cpp
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "scene/scene.h"
#include "graphics/mesh.h"
#include "components/meshrenderer.h"

// Error callback for GLFW
void glfwErrorCallback(int error, const char* description) {
    std::cerr << "GLFW Error: " << description << std::endl;
}

int main() {
    // Initialize GLFW
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW" << std::endl;
        return -1;
    }
    
    glfwSetErrorCallback(glfwErrorCallback);
    
    // Set OpenGL version and profile
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    // Create window
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Engine", nullptr, nullptr);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    
    glfwMakeContextCurrent(window);
    
    // Initialize GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        return -1;
    }
    
    // Set up OpenGL settings
    glEnable(GL_DEPTH_TEST);
    
    // Create scene
    Scene scene;
    
    // Main loop
    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // Update and render scene
        float deltaTime = 0.016f; // Assuming 60 FPS
        scene.Update(deltaTime);
        
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    
    // Cleanup
    glfwTerminate();
    return 0;
}
```

### CMakeLists.txt
```cmake
cmake_minimum_required(VERSION 3.10)
project(OpenGLEngine)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find required packages
find_package(glfw3 REQUIRED)
find_package(GLEW REQUIRED)
find_package(glm REQUIRED)

# Add executable
add_executable(${PROJECT_NAME} 
    src/main.cpp
    src/scene/scene.cpp
    src/scene/gameobject.cpp
    src/graphics/mesh.cpp
    src/graphics/shader.cpp
    src/graphics/renderer.cpp
    src/components/transform.cpp
    src/components/meshrenderer.cpp
)

# Include directories
target_include_directories(${PROJECT_NAME} PRIVATE 
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${GLFW_INCLUDE_DIRS}
    ${GLEW_INCLUDE_DIRS}
    ${GLM_INCLUDE_DIRS}
)

# Link libraries
target_link_libraries(${PROJECT_NAME} 
    glfw
    GLEW::GLEW
    ${OPENGL_LIBRARIES}
)

# Set C++ standard
set_target_properties(${PROJECT_NAME} PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
)
```

### Shader Files (src/shaders/vertex.glsl and src/shaders/fragment.glsl)

**vertex.glsl:**
```glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model)))) * aNormal;
    TexCoord = aTexCoord;
    
    gl_Position = projection * view * vec4(FragPos, 1.0);
}
```

**fragment.glsl:**
```glsl
#version 330 core
out vec4 FragColor;

in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;

uniform vec3 objectColor;
uniform vec3 lightPos;
uniform vec3 viewPos;

void main()
{
    // Ambient
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * objectColor;
    
    // Diffuse
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * objectColor;
    
    vec3 result = ambient + diffuse;
    FragColor = vec4(result, 1.0);
}
```

This implementation provides a basic but functional OpenGL engine framework with:

1. **Core Architecture**: Scene management, GameObjects with components
2. **Rendering Pipeline**: Meshes, shaders, and transforms
3. **Component System**: Extensible component architecture
4. **OpenGL Integration**: Proper setup and rendering loop
5. **Build System**: CMake configuration for easy compilation

The engine supports:
- Basic 3D rendering with lighting
- Transform-based object positioning
- Component-based architecture
- Modular design for extensibility
- Cross-platform compatibility

To build and run:
1. Install required dependencies (GLFW, GLEW, GLM)
2. Create a build directory and run CMake
3. Compile the project
4. Run the executable

This framework provides a solid foundation that can be extended with features like audio, physics, scripting, etc.

   
Quote
Share: