aurora-rendering-engine/all_files.md

78 KiB
Raw Blame History

文件src/basic/math.cpp

#include "basic/math.h"

namespace are {

Mat4 MathUtils::perspective(float fov, float aspect, float near, float far) {
    return glm::perspective(fov, aspect, near, far);
}

Mat4 MathUtils::look_at(const Vec3& eye, const Vec3& center, const Vec3& up) {
    return glm::lookAt(eye, center, up);
}

Vec3 MathUtils::normalize(const Vec3& v) {
    return glm::normalize(v);
}

float MathUtils::dot(const Vec3& a, const Vec3& b) {
    return glm::dot(a, b);
}

Vec3 MathUtils::cross(const Vec3& a, const Vec3& b) {
    return glm::cross(a, b);
}

Vec3 MathUtils::reflect(const Vec3& incident, const Vec3& normal) {
    return glm::reflect(incident, normal);
}

const float* MathUtils::value_ptr(const Mat4& mat) {
    return glm::value_ptr(mat);
}

} // namespace are

文件src/core/bvh.cpp

#include "core/bvh.h"
#include "utils/logger.h"
#include "basic/constants.h"
#include <algorithm>
#include <limits>

namespace are {

// AABB implementation
void AABB::expand(const Vec3& point) {
    min_ = glm::min(min_, point);
    max_ = glm::max(max_, point);
}

void AABB::expand(const AABB& other) {
    min_ = glm::min(min_, other.min_);
    max_ = glm::max(max_, other.max_);
}

float AABB::surface_area() const {
    Vec3 extent = max_ - min_;
    return 2.0f * (extent.x * extent.y + extent.y * extent.z + extent.z * extent.x);
}

bool AABB::is_valid() const {
    return min_.x <= max_.x && min_.y <= max_.y && min_.z <= max_.z;
}

// Triangle implementation
AABB Triangle::get_bounds() const {
    AABB bounds(v0_, v0_);
    bounds.expand(v1_);
    bounds.expand(v2_);
    return bounds;
}

Vec3 Triangle::get_centroid() const {
    return (v0_ + v1_ + v2_) / 3.0f;
}

// BVH implementation
BVH::BVH() {
}

BVH::~BVH() {
    clear();
}

bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
    clear();
    
    Logger::info("Building BVH...");
    
    // Extract all triangles from meshes
    for (const auto& mesh : meshes) {
        const auto& vertices = mesh->get_vertices();
        const auto& indices = mesh->get_indices();
        uint material_id = mesh->get_material();
        Mat4 transform = mesh->get_transform();
        
        for (size_t i = 0; i < indices.size(); i += 3) {
            Triangle tri;
            
            // Transform vertices
            Vec4 v0 = transform * Vec4(vertices[indices[i]].position_, 1.0f);
            Vec4 v1 = transform * Vec4(vertices[indices[i + 1]].position_, 1.0f);
            Vec4 v2 = transform * Vec4(vertices[indices[i + 2]].position_, 1.0f);
            
            tri.v0_ = Vec3(v0) / v0.w;
            tri.v1_ = Vec3(v1) / v1.w;
            tri.v2_ = Vec3(v2) / v2.w;
            
            // Transform normals
            Mat3 normal_matrix = glm::transpose(glm::inverse(Mat3(transform)));
            tri.n0_ = glm::normalize(normal_matrix * vertices[indices[i]].normal_);
            tri.n1_ = glm::normalize(normal_matrix * vertices[indices[i + 1]].normal_);
            tri.n2_ = glm::normalize(normal_matrix * vertices[indices[i + 2]].normal_);
            
            // Copy UVs
            tri.uv0_ = vertices[indices[i]].texcoord_;
            tri.uv1_ = vertices[indices[i + 1]].texcoord_;
            tri.uv2_ = vertices[indices[i + 2]].texcoord_;
            
            tri.material_id_ = material_id;
            
            triangles_.push_back(tri);
        }
    }
    
    if (triangles_.empty()) {
        Logger::warning("No triangles to build BVH");
        return false;
    }
    
    // Initialize triangle indices
    triangle_indices_.resize(triangles_.size());
    for (size_t i = 0; i < triangles_.size(); ++i) {
        triangle_indices_[i] = static_cast<uint>(i);
    }
    
    // Reserve space for nodes (estimate)
    nodes_.reserve(triangles_.size() * 2);
    
    // Create root node
    nodes_.emplace_back();
    
    // Build BVH recursively
    build_recursive_(0, 0, static_cast<uint>(triangles_.size()));
    
    Logger::info("BVH built: " + std::to_string(nodes_.size()) + " nodes, " +
                std::to_string(triangles_.size()) + " triangles");
    
    return true;
}

void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) {
    BVHNode& node = nodes_[node_idx];
    
    // Calculate bounds
    AABB bounds = calculate_bounds_(first_prim, prim_count);
    node.aabb_min_ = bounds.min_;
    node.aabb_max_ = bounds.max_;
    
    // Leaf node threshold
    const uint LEAF_SIZE = 4;
    
    if (prim_count <= LEAF_SIZE) {
        // Create leaf node
        node.left_first_ = first_prim;
        node.count_ = prim_count;
        return;
    }
    
    // Find best split
    int axis;
    float split_pos;
    float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos);
    
    // Check if split is beneficial
    float no_split_cost = prim_count * bounds.surface_area();
    if (split_cost >= no_split_cost) {
        // Create leaf node
        node.left_first_ = first_prim;
        node.count_ = prim_count;
        return;
    }
    
    // Partition primitives
    uint mid = first_prim;
    for (uint i = first_prim; i < first_prim + prim_count; ++i) {
        Triangle& tri = triangles_[triangle_indices_[i]];
        float centroid = tri.get_centroid()[axis];
        
        if (centroid < split_pos) {
            std::swap(triangle_indices_[i], triangle_indices_[mid]);
            mid++;
        }
    }
    
    // Ensure we have primitives on both sides
    if (mid == first_prim || mid == first_prim + prim_count) {
        mid = first_prim + prim_count / 2;
    }
    
    // Create interior node
    uint left_count = mid - first_prim;
    uint right_count = prim_count - left_count;
    
    node.left_first_ = static_cast<uint>(nodes_.size());
    node.count_ = 0;
    
    // Create child nodes
    nodes_.emplace_back();
    nodes_.emplace_back();
    
    // Recursively build children
    build_recursive_(node.left_first_, first_prim, left_count);
    build_recursive_(node.left_first_ + 1, mid, right_count);
}

float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float& split_pos) {
    float best_cost = std::numeric_limits<float>::max();
    
    AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count);
    
    // Try each axis
    for (int a = 0; a < 3; ++a) {
        float extent = centroid_bounds.max_[a] - centroid_bounds.min_[a];
        if (extent < EPSILON) continue;
        
        // Try multiple split positions
        const int NUM_BINS = 16;
        for (int i = 1; i < NUM_BINS; ++i) {
            float t = static_cast<float>(i) / NUM_BINS;
            float pos = centroid_bounds.min_[a] + t * extent;
            
            // Count primitives and calculate bounds for each side
            AABB left_bounds, right_bounds;
            uint left_count = 0, right_count = 0;
            
            for (uint j = first_prim; j < first_prim + prim_count; ++j) {
                Triangle& tri = triangles_[triangle_indices_[j]];
                float centroid = tri.get_centroid()[a];
                
                if (centroid < pos) {
                    left_bounds.expand(tri.get_bounds());
                    left_count++;
                } else {
                    right_bounds.expand(tri.get_bounds());
                    right_count++;
                }
            }
            
            // Calculate SAH cost
            if (left_count == 0 || right_count == 0) continue;
            
            float cost = left_count * left_bounds.surface_area() +
                        right_count * right_bounds.surface_area();
            
            if (cost < best_cost) {
                best_cost = cost;
                axis = a;
                split_pos = pos;
            }
        }
    }
    
    return best_cost;
}

AABB BVH::calculate_bounds_(uint first_prim, uint prim_count) {
    AABB bounds{Vec3(std::numeric_limits<float>::max()),
               Vec3(std::numeric_limits<float>::lowest())};
    
    for (uint i = first_prim; i < first_prim + prim_count; ++i) {
        Triangle& tri = triangles_[triangle_indices_[i]];
        bounds.expand(tri.get_bounds());
    }
    
    return bounds;
}

AABB BVH::calculate_centroid_bounds_(uint first_prim, uint prim_count) {
    AABB bounds{Vec3(std::numeric_limits<float>::max()),
               Vec3(std::numeric_limits<float>::lowest())};
    
    for (uint i = first_prim; i < first_prim + prim_count; ++i) {
        Triangle& tri = triangles_[triangle_indices_[i]];
        bounds.expand(tri.get_centroid());
    }
    
    return bounds;
}

bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) {
    if (nodes_.empty() || triangles_.empty()) {
        Logger::error("Cannot upload empty BVH to GPU");
        return false;
    }
    
    // Reorder triangles according to BVH layout
    std::vector<Triangle> ordered_triangles;
    ordered_triangles.reserve(triangles_.size());
    
    for (uint idx : triangle_indices_) {
        ordered_triangles.push_back(triangles_[idx]);
    }
    
    // Upload nodes
    if (!node_buffer.create(BufferType::SHADER_STORAGE_BUFFER,
                           nodes_.size() * sizeof(BVHNode),
                           nodes_.data(),
                           BufferUsage::STATIC_DRAW)) {
        Logger::error("Failed to upload BVH nodes to GPU");
        return false;
    }
    
    // Upload triangles
    if (!triangle_buffer.create(BufferType::SHADER_STORAGE_BUFFER,
                               ordered_triangles.size() * sizeof(Triangle),
                               ordered_triangles.data(),
                               BufferUsage::STATIC_DRAW)) {
        Logger::error("Failed to upload BVH triangles to GPU");
        return false;
    }
    
    Logger::info("BVH uploaded to GPU successfully");
    return true;
}

void BVH::clear() {
    nodes_.clear();
    triangles_.clear();
    triangle_indices_.clear();
}

} // namespace are

文件src/core/gbuffer.cpp

#include "core/gbuffer.h"
#include "utils/logger.h"
#include <glad/glad.h>

namespace are {

GBuffer::GBuffer(uint width, uint height)
    : width_(width)
    , height_(height)
    , fbo_(INVALID_HANDLE)
    , depth_texture_(INVALID_HANDLE)
    , initialized_(false) {
    for (int i = 0; i < GBUFFER_COUNT; ++i) {
        textures_[i] = INVALID_HANDLE;
    }
}

GBuffer::~GBuffer() {
    release();
}

bool GBuffer::initialize() {
    if (initialized_) {
        Logger::warning("GBuffer already initialized");
        return true;
    }
    
    // Create framebuffer
    glGenFramebuffers(1, &fbo_);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
    
    // Create G-Buffer textures
    textures_[GBUFFER_POSITION] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT);
    textures_[GBUFFER_NORMAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT);
    textures_[GBUFFER_ALBEDO] = create_texture_(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
    
    // Attach textures to framebuffer
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION,
                          GL_TEXTURE_2D, textures_[GBUFFER_POSITION], 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL,
                          GL_TEXTURE_2D, textures_[GBUFFER_NORMAL], 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO,
                          GL_TEXTURE_2D, textures_[GBUFFER_ALBEDO], 0);
    
    // Create depth texture
    glGenTextures(1, &depth_texture_);
    glBindTexture(GL_TEXTURE_2D, depth_texture_);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width_, height_, 0,
                GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                          GL_TEXTURE_2D, depth_texture_, 0);
    
    // Set draw buffers
    GLenum draw_buffers[GBUFFER_COUNT] = {
        GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION,
        GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL,
        GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO
    };
    glDrawBuffers(GBUFFER_COUNT, draw_buffers);
    
    // Check framebuffer completeness
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        Logger::error("GBuffer framebuffer is not complete");
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        return false;
    }
    
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
    initialized_ = true;
    Logger::info("GBuffer initialized successfully");
    return true;
}

void GBuffer::release() {
    if (!initialized_) return;
    
    if (fbo_ != INVALID_HANDLE) {
        glDeleteFramebuffers(1, &fbo_);
        fbo_ = INVALID_HANDLE;
    }
    
    for (int i = 0; i < GBUFFER_COUNT; ++i) {
        if (textures_[i] != INVALID_HANDLE) {
            glDeleteTextures(1, &textures_[i]);
            textures_[i] = INVALID_HANDLE;
        }
    }
    
    if (depth_texture_ != INVALID_HANDLE) {
        glDeleteTextures(1, &depth_texture_);
        depth_texture_ = INVALID_HANDLE;
    }
    
    initialized_ = false;
    Logger::info("GBuffer released");
}

void GBuffer::render(const Scene& scene, const Shader& shader) {
    if (!initialized_) {
        Logger::error("GBuffer not initialized");
        return;
    }
    
    // Bind framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
    glViewport(0, 0, width_, height_);
    
    // Clear buffers
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // Enable depth test
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    
    // Use shader
    shader.use();
    
    // Set camera matrices
    const Camera& camera = scene.get_camera();
    Mat4 view = camera.get_view_matrix();
    Mat4 projection = camera.get_projection_matrix();
    
    shader.set_mat4("u_view", view);
    shader.set_mat4("u_projection", projection);
    
    // Render all meshes
    const auto& meshes = scene.get_meshes();
    const auto& materials = scene.get_materials();
    
    for (const auto& mesh : meshes) {
        if (!mesh->is_uploaded()) {
            Logger::warning("Mesh not uploaded to GPU, skipping");
            continue;
        }
        
        // Set model matrix
        Mat4 model = mesh->get_transform();
        shader.set_mat4("u_model", model);
        
        // Set material properties
        uint material_id = mesh->get_material();
        if (material_id < materials.size()) {
            const auto& material = materials[material_id];
            
            shader.set_vec3("u_albedo", material->get_albedo());
            shader.set_float("u_metallic", material->get_metallic());
            shader.set_float("u_roughness", material->get_roughness());
            shader.set_uint("u_material_id", material_id);
            
            // Bind textures
            auto albedo_tex = material->get_albedo_texture();
            if (albedo_tex && albedo_tex->is_valid()) {
                albedo_tex->bind(0);
                shader.set_int("u_albedo_map", 0);
                shader.set_int("u_has_albedo_map", 1);
            } else {
                shader.set_int("u_has_albedo_map", 0);
            }
            
            auto normal_tex = material->get_normal_texture();
            if (normal_tex && normal_tex->is_valid()) {
                normal_tex->bind(1);
                shader.set_int("u_normal_map", 1);
                shader.set_int("u_has_normal_map", 1);
            } else {
                shader.set_int("u_has_normal_map", 0);
            }
        }
        
        // Draw mesh
        glBindVertexArray(mesh->get_vao());
        glDrawElements(GL_TRIANGLES, mesh->get_indices().size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
    }
    
    // Unbind framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void GBuffer::resize(uint width, uint height) {
    if (width == width_ && height == height_) return;
    
    width_ = width;
    height_ = height;
    
    if (initialized_) {
        release();
        initialize();
    }
}

TextureHandle GBuffer::get_texture(int index) const {
    if (index < 0 || index >= GBUFFER_COUNT) {
        Logger::error("Invalid G-Buffer texture index");
        return INVALID_HANDLE;
    }
    return textures_[index];
}

void GBuffer::get_dimensions(uint& width, uint& height) const {
    width = width_;
    height = height_;
}

TextureHandle GBuffer::create_texture_(uint internal_format, uint format, uint type) {
    TextureHandle texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_, height_, 0, format, type, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    return texture;
}

} // namespace are

文件src/core/raytracer.cpp

#include "core/raytracer.h"
#include "utils/logger.h"
#include "basic/constants.h"
#include <glad/glad.h>

namespace are {

RayTracer::RayTracer(uint width, uint height, const RayTracerConfig& config)
    : width_(width)
    , height_(height)
    , config_(config)
    , accumulation_texture_(INVALID_HANDLE)
    , scene_buffer_(INVALID_HANDLE)
    , material_buffer_(INVALID_HANDLE)
    , light_buffer_(INVALID_HANDLE)
    , bvh_(nullptr)
    , bvh_built_(false)
    , frame_count_(0)
    , initialized_(false) {
}

RayTracer::~RayTracer() {
    release();
}

bool RayTracer::initialize() {
    if (initialized_) {
        Logger::warning("RayTracer already initialized");
        return true;
    }
    
    // Create accumulation texture
    glGenTextures(1, &accumulation_texture_);
    glBindTexture(GL_TEXTURE_2D, accumulation_texture_);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    // Create shader storage buffers
    glGenBuffers(1, &material_buffer_);
    glGenBuffers(1, &light_buffer_);
    
    // Load compute shader
    Logger::info("Loading ray tracing compute shader in RayTracer...");
    if (!compute_shader_.load_compute("shaders/raytracing.comp")) {
        Logger::error("Failed to load ray tracing compute shader in RayTracer");
        return false;
    }
    Logger::info("Ray tracing compute shader loaded in RayTracer");
    
    // Initialize BVH if enabled
    if (config_.use_bvh_) {
        bvh_ = std::make_unique<BVH>();
    }
    
    initialized_ = true;
    Logger::info("RayTracer initialized successfully");
    return true;
}

void RayTracer::release() {
    if (!initialized_) return;
    
    if (accumulation_texture_ != INVALID_HANDLE) {
        glDeleteTextures(1, &accumulation_texture_);
        accumulation_texture_ = INVALID_HANDLE;
    }
    
    if (material_buffer_ != INVALID_HANDLE) {
        glDeleteBuffers(1, &material_buffer_);
        material_buffer_ = INVALID_HANDLE;
    }
    
    if (light_buffer_ != INVALID_HANDLE) {
        glDeleteBuffers(1, &light_buffer_);
        light_buffer_ = INVALID_HANDLE;
    }
    
    bvh_node_buffer_.release();
    bvh_triangle_buffer_.release();
    
    compute_shader_.release();
    
    bvh_.reset();
    bvh_built_ = false;
    
    initialized_ = false;
    Logger::info("RayTracer released");
}

bool RayTracer::rebuild_bvh(const Scene& scene) {
    if (!config_.use_bvh_) {
        Logger::warning("BVH is disabled in configuration");
        return false;
    }
    
    if (!bvh_) {
        bvh_ = std::make_unique<BVH>();
    }
    
    Logger::info("Building BVH for ray tracing...");
    
    if (!bvh_->build(scene.get_meshes())) {
        Logger::error("Failed to build BVH");
        return false;
    }
    
    if (!bvh_->upload_to_gpu(bvh_node_buffer_, bvh_triangle_buffer_)) {
        Logger::error("Failed to upload BVH to GPU");
        return false;
    }
    
    bvh_built_ = true;
    Logger::info("BVH built and uploaded successfully");
    return true;
}

void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle output_texture) {
    if (!initialized_) {
        Logger::error("RayTracer not initialized");
        return;
    }
    
    if (!compute_shader_.is_valid()) {
        Logger::error("Ray tracing compute shader not loaded");
        return;
    }
    
    // Build BVH if enabled and not built yet
    if (config_.use_bvh_ && !bvh_built_) {
        rebuild_bvh(scene);
    }
    
    // Upload scene data
    upload_scene_data_(scene);
    
    // Use compute shader
    compute_shader_.use();
    
    // Bind G-Buffer textures
    bind_gbuffer_(gbuffer);
    
    // Bind output and accumulation textures
    glBindImageTexture(3, output_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
    glBindImageTexture(4, accumulation_texture_, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
    
    // Bind BVH buffers if enabled
    if (config_.use_bvh_ && bvh_built_) {
        bvh_node_buffer_.bind_base(2);
        bvh_triangle_buffer_.bind_base(3);
        compute_shader_.set_bool("u_use_bvh", true);
        compute_shader_.set_uint("u_bvh_node_count", bvh_->get_node_count());
    } else {
        compute_shader_.set_bool("u_use_bvh", false);
    }
    
    // Set uniforms
    compute_shader_.set_uint("u_frame_count", frame_count_);
    compute_shader_.set_uint("u_samples_per_pixel", config_.samples_per_pixel_);
    compute_shader_.set_uint("u_max_depth", config_.max_depth_);
    compute_shader_.set_uint("u_light_count", static_cast<uint>(scene.get_lights().size()));
    compute_shader_.set_bool("u_enable_accumulation", config_.enable_accumulation_);
    
    // Set camera data
    const Camera& camera = scene.get_camera();
    compute_shader_.set_vec3("u_camera_position", camera.get_position());
    
    Mat4 inv_vp = glm::inverse(camera.get_view_projection_matrix());
    compute_shader_.set_mat4("u_inv_view_projection", inv_vp);
    
    // Dispatch compute shader
    uint num_groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X;
    uint num_groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y;
    
    glDispatchCompute(num_groups_x, num_groups_y, 1);
    
    // Memory barrier
    glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
    
    // Increment frame count for accumulation
    if (config_.enable_accumulation_) {
        frame_count_++;
    }
}

void RayTracer::resize(uint width, uint height) {
    if (width == width_ && height == height_) return;
    
    width_ = width;
    height_ = height;
    
    if (initialized_) {
        // Recreate accumulation texture
        if (accumulation_texture_ != INVALID_HANDLE) {
            glDeleteTextures(1, &accumulation_texture_);
        }
        
        glGenTextures(1, &accumulation_texture_);
        glBindTexture(GL_TEXTURE_2D, accumulation_texture_);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        reset_accumulation();
    }
}

void RayTracer::reset_accumulation() {
    frame_count_ = 0;
}

void RayTracer::set_config(const RayTracerConfig& config) {
    bool bvh_changed = (config.use_bvh_ != config_.use_bvh_);
    
    config_ = config;
    reset_accumulation();
    
    if (bvh_changed) {
        if (config_.use_bvh_ && !bvh_) {
            bvh_ = std::make_unique<BVH>();
            bvh_built_ = false;
        } else if (!config_.use_bvh_) {
            bvh_.reset();
            bvh_built_ = false;
        }
    }
}

void RayTracer::upload_scene_data_(const Scene& scene) {
    // Upload materials
    const auto& materials = scene.get_materials();
    if (!materials.empty()) {
        struct MaterialData {
            Vec3 albedo;
            float metallic;
            Vec3 emission;
            float roughness;
            int type;
            float ior;
            Vec2 padding;
        };
        
        std::vector<MaterialData> material_data;
        material_data.reserve(materials.size());
        
        for (const auto& mat : materials) {
            MaterialData data;
            data.albedo = mat->get_albedo();
            data.metallic = mat->get_metallic();
            data.emission = mat->get_emission();
            data.roughness = mat->get_roughness();
            data.type = static_cast<int>(mat->get_type());
            data.ior = mat->get_ior();
            material_data.push_back(data);
        }
        
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, material_buffer_);
        glBufferData(GL_SHADER_STORAGE_BUFFER, 
                    material_data.size() * sizeof(MaterialData),
                    material_data.data(), GL_DYNAMIC_DRAW);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, material_buffer_);
    }
    
    // Upload lights
    const auto& lights = scene.get_lights();
    if (!lights.empty()) {
        struct LightData {
            Vec3 position;
            int type;
            Vec3 direction;
            float intensity;
            Vec3 color;
            float range;
            Vec2 spot_angles;
            Vec2 padding;
        };
        
        std::vector<LightData> light_data;
        light_data.reserve(lights.size());
        
        for (const auto& light : lights) {
            LightData data;
            data.position = light->get_position();
            data.type = static_cast<int>(light->get_type());
            data.direction = light->get_direction();
            data.intensity = light->get_intensity();
            data.color = light->get_color();
            data.range = light->get_range();
            data.spot_angles = Vec2(light->get_inner_angle(), light->get_outer_angle());
            light_data.push_back(data);
        }
        
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, light_buffer_);
        glBufferData(GL_SHADER_STORAGE_BUFFER,
                    light_data.size() * sizeof(LightData),
                    light_data.data(), GL_DYNAMIC_DRAW);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, light_buffer_);
    }
}

void RayTracer::bind_gbuffer_(const GBuffer& gbuffer) {
    glBindImageTexture(0, gbuffer.get_texture(GBUFFER_POSITION), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
    glBindImageTexture(1, gbuffer.get_texture(GBUFFER_NORMAL), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
    glBindImageTexture(2, gbuffer.get_texture(GBUFFER_ALBEDO), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}

void RayTracer::set_compute_shader(const Shader& shader) {
    compute_shader_ = shader;
    Logger::info("Compute shader set for RayTracer");
}

} // namespace are

文件src/core/renderer.cpp

#include "core/renderer.h"
#include "utils/logger.h"
#include <chrono>
#include <glad/glad.h>

namespace are {

Renderer::Renderer(const RendererConfig &config)
	: config_(config)
	, initialized_(false)
	, frame_count_(0) {
}

Renderer::~Renderer() {
	shutdown();
}

bool Renderer::initialize() {
    if (initialized_) {
        Logger::warning("Renderer already initialized");
        return true;
    }
    
    Logger::info("Initializing Aurora Rendering Engine...");
    
    // Initialize shader manager
    shader_manager_ = std::make_unique<ShaderManager>();
    if (!shader_manager_->initialize()) {
        Logger::error("Failed to initialize shader manager");
        return false;
    }
    
    // Initialize G-Buffer
    gbuffer_ = std::make_unique<GBuffer>(config_.width_, config_.height_);
    if (!gbuffer_->initialize()) {
        Logger::error("Failed to initialize G-Buffer");
        return false;
    }
    
    // Initialize ray tracer
    RayTracerConfig rt_config;
    rt_config.samples_per_pixel_ = config_.samples_per_pixel_;
    rt_config.max_depth_ = config_.max_ray_depth_;
    rt_config.enable_shadows_ = true;
    rt_config.enable_reflections_ = true;
    rt_config.enable_accumulation_ = config_.enable_accumulation_;
    rt_config.use_bvh_ = true;
    
    raytracer_ = std::make_unique<RayTracer>(config_.width_, config_.height_, rt_config);
    if (!raytracer_->initialize()) {
        Logger::error("Failed to initialize ray tracer");
        return false;
    }
    
    // Pass compute shader to ray tracer
    const Shader& rt_shader = shader_manager_->get_raytracing_shader();
    if (!rt_shader.is_valid()) {
        Logger::error("Ray tracing shader is invalid");
        return false;
    }
    raytracer_->set_compute_shader(rt_shader);
    
    // Initialize screen blit
    screen_blit_ = std::make_unique<ScreenBlit>();
    if (!screen_blit_->initialize()) {
        Logger::error("Failed to initialize screen blit");
        return false;
    }
    
    initialized_ = true;
    Logger::info("Aurora Rendering Engine initialized successfully");
    return true;
}

void Renderer::shutdown() {
	if (!initialized_)
		return;

	Logger::info("Shutting down Aurora Rendering Engine...");

	if (screen_blit_) {
        screen_blit_->release();
        screen_blit_.reset();
    }

	if (raytracer_) {
		raytracer_->release();
		raytracer_.reset();
	}

	if (gbuffer_) {
		gbuffer_->release();
		gbuffer_.reset();
	}

	if (shader_manager_) {
		shader_manager_->release();
		shader_manager_.reset();
	}

	initialized_ = false;
	Logger::info("Aurora Rendering Engine shut down");
}

RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
    RenderStats stats = {};
    
    if (!initialized_) {
        Logger::error("Renderer not initialized");
        return stats;
    }
    
    // Start timing
    auto start_time = std::chrono::high_resolution_clock::now();
    
    // Phase 1: G-Buffer pass
    auto gbuffer_start = std::chrono::high_resolution_clock::now();
    
    const Shader& gbuffer_shader = shader_manager_->get_gbuffer_shader();
    gbuffer_->render(scene, gbuffer_shader);
    
    auto gbuffer_end = std::chrono::high_resolution_clock::now();
    stats.gbuffer_time_ms_ = std::chrono::duration<float, std::milli>(gbuffer_end - gbuffer_start).count();
    
    // Phase 2: Ray tracing pass
    auto raytrace_start = std::chrono::high_resolution_clock::now();
    
    // Create output texture if not provided
    TextureHandle rt_output = output_texture;
    bool created_temp_texture = false;
    
    if (rt_output == 0) {
        glGenTextures(1, &rt_output);
        glBindTexture(GL_TEXTURE_2D, rt_output);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, config_.width_, config_.height_, 
                    0, GL_RGBA, GL_FLOAT, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        created_temp_texture = true;
    }
    
    raytracer_->trace(scene, *gbuffer_, rt_output);
    
    auto raytrace_end = std::chrono::high_resolution_clock::now();
    stats.raytrace_time_ms_ = std::chrono::duration<float, std::milli>(raytrace_end - raytrace_start).count();
    
    // Phase 3: Blit to screen if output is default framebuffer
    if (created_temp_texture && output_texture == 0) {
        screen_blit_->blit_fullscreen(rt_output);
        glDeleteTextures(1, &rt_output);
    }
    
    // Calculate total frame time
    auto end_time = std::chrono::high_resolution_clock::now();
    stats.frame_time_ms_ = std::chrono::duration<float, std::milli>(end_time - start_time).count();
    
    // Count triangles
    const auto& meshes = scene.get_meshes();
    for (const auto& mesh : meshes) {
        stats.triangle_count_ += mesh->get_indices().size() / 3;
    }
    
    // Estimate ray count (very rough)
    stats.ray_count_ = config_.width_ * config_.height_ * config_.samples_per_pixel_ * config_.max_ray_depth_;
    
    frame_count_++;
    
    return stats;
}

void Renderer::resize(uint width, uint height) {
	if (width == config_.width_ && height == config_.height_)
		return;

	config_.width_ = width;
	config_.height_ = height;

	if (initialized_) {
		gbuffer_->resize(width, height);
		raytracer_->resize(width, height);

		Logger::info("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height));
	}
}

void Renderer::set_config(const RendererConfig &config) {
	bool size_changed = (config.width_ != config_.width_ || config.height_ != config_.height_);

	config_ = config;

	if (initialized_) {
		if (size_changed) {
			resize(config_.width_, config_.height_);
		}

		// Update ray tracer config
		RayTracerConfig rt_config = raytracer_->get_config();
		rt_config.samples_per_pixel_ = config_.samples_per_pixel_;
		rt_config.max_depth_ = config_.max_ray_depth_;
		rt_config.enable_accumulation_ = config_.enable_accumulation_;
		raytracer_->set_config(rt_config);
	}
}

} // namespace are

文件src/core/screen_blit.cpp

#include "core/screen_blit.h"
#include "utils/logger.h"
#include <glad/glad.h>

namespace are {

namespace {
    const char* VERTEX_SHADER_SOURCE = R"(
        #version 430 core
        layout(location = 0) in vec2 a_position;
        layout(location = 1) in vec2 a_texcoord;
        
        out vec2 v_texcoord;
        
        void main() {
            v_texcoord = a_texcoord;
            gl_Position = vec4(a_position, 0.0, 1.0);
        }
    )";
    
    const char* FRAGMENT_SHADER_SOURCE = R"(
        #version 430 core
        in vec2 v_texcoord;
        out vec4 frag_color;
        
        uniform sampler2D u_texture;
        
        void main() {
            frag_color = texture(u_texture, v_texcoord);
        }
    )";
}

ScreenBlit::ScreenBlit()
    : vao_(0)
    , vbo_(0)
    , initialized_(false) {
}

ScreenBlit::~ScreenBlit() {
    release();
}

bool ScreenBlit::initialize() {
    if (initialized_) {
        Logger::warning("ScreenBlit already initialized");
        return true;
    }
    
    // Compile shader
    if (!shader_.compile(VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)) {
        Logger::error("Failed to compile screen blit shader");
        return false;
    }
    
    // Create fullscreen quad
    create_quad_();
    
    initialized_ = true;
    Logger::info("ScreenBlit initialized successfully");
    return true;
}

void ScreenBlit::release() {
    if (!initialized_) return;
    
    shader_.release();
    
    if (vao_ != 0) {
        glDeleteVertexArrays(1, &vao_);
        vao_ = 0;
    }
    
    if (vbo_ != 0) {
        glDeleteBuffers(1, &vbo_);
        vbo_ = 0;
    }
    
    initialized_ = false;
}

void ScreenBlit::blit(TextureHandle texture, int x, int y, uint width, uint height) {
    if (!initialized_) {
        Logger::error("ScreenBlit not initialized");
        return;
    }
    
    // Set viewport
    glViewport(x, y, width, height);
    
    // Disable depth test
    glDisable(GL_DEPTH_TEST);
    
    // Use shader
    shader_.use();
    shader_.set_int("u_texture", 0);
    
    // Bind texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    // Draw quad
    glBindVertexArray(vao_);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
    
    // Re-enable depth test
    glEnable(GL_DEPTH_TEST);
}

void ScreenBlit::blit_fullscreen(TextureHandle texture) {
    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);
    blit(texture, viewport[0], viewport[1], viewport[2], viewport[3]);
}

void ScreenBlit::create_quad_() {
    // Fullscreen quad vertices (position + texcoord)
    float vertices[] = {
        // Position    // TexCoord
        -1.0f, -1.0f,  0.0f, 0.0f,
         1.0f, -1.0f,  1.0f, 0.0f,
         1.0f,  1.0f,  1.0f, 1.0f,
        
        -1.0f, -1.0f,  0.0f, 0.0f,
         1.0f,  1.0f,  1.0f, 1.0f,
        -1.0f,  1.0f,  0.0f, 1.0f
    };
    
    glGenVertexArrays(1, &vao_);
    glGenBuffers(1, &vbo_);
    
    glBindVertexArray(vao_);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    // Position attribute
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    
    // TexCoord attribute
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    
    glBindVertexArray(0);
}

} // namespace are

文件src/core/shader_manager.cpp

#include "core/shader_manager.h"
#include "utils/logger.h"

namespace are {

ShaderManager::ShaderManager()
    : initialized_(false) {
}

ShaderManager::~ShaderManager() {
    release();
}

bool ShaderManager::initialize() {
    if (initialized_) {
        Logger::warning("ShaderManager already initialized");
        return true;
    }
    
    Logger::info("Loading built-in shaders...");
    
    if (!load_builtin_shaders_()) {
        Logger::error("Failed to load built-in shaders");
        return false;
    }
    
    initialized_ = true;
    Logger::info("ShaderManager initialized successfully");
    return true;
}

void ShaderManager::release() {
    if (!initialized_) return;
    
    gbuffer_shader_.release();
    raytracing_shader_.release();
    
    for (auto& pair : shader_cache_) {
        pair.second.release();
    }
    shader_cache_.clear();
    
    initialized_ = false;
    Logger::info("ShaderManager released");
}

Shader ShaderManager::load_shader(const std::string& name,
                                  const std::string& vertex_path,
                                  const std::string& fragment_path) {
    // Check cache
    auto it = shader_cache_.find(name);
    if (it != shader_cache_.end()) {
        Logger::info("Shader '" + name + "' loaded from cache");
        return it->second;
    }
    
    // Load shader
    Shader shader;
    if (!shader.load(vertex_path, fragment_path)) {
        Logger::error("Failed to load shader '" + name + "'");
        return Shader();
    }
    
    shader_cache_[name] = shader;
    Logger::info("Shader '" + name + "' loaded successfully");
    return shader;
}

Shader ShaderManager::load_compute_shader(const std::string& name,
                                         const std::string& compute_path) {
    // Check cache
    auto it = shader_cache_.find(name);
    if (it != shader_cache_.end()) {
        Logger::info("Compute shader '" + name + "' loaded from cache");
        return it->second;
    }
    
    // Load shader
    Shader shader;
    if (!shader.load_compute(compute_path)) {
        Logger::error("Failed to load compute shader '" + name + "'");
        return Shader();
    }
    
    shader_cache_[name] = shader;
    Logger::info("Compute shader '" + name + "' loaded successfully");
    return shader;
}

Shader ShaderManager::get_shader(const std::string& name) const {
    auto it = shader_cache_.find(name);
    if (it != shader_cache_.end()) {
        return it->second;
    }
    
    Logger::warning("Shader '" + name + "' not found in cache");
    return Shader();
}

bool ShaderManager::load_builtin_shaders_() {
    // Load G-Buffer shader
    if (!gbuffer_shader_.load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) {
        Logger::error("Failed to load G-Buffer shader");
        return false;
    }
    shader_cache_["gbuffer"] = gbuffer_shader_;
    
    // Load ray tracing compute shader
    if (!raytracing_shader_.load_compute("shaders/raytracing.comp")) {
        Logger::error("Failed to load ray tracing shader");
        return false;
    }
    shader_cache_["raytracing"] = raytracing_shader_;

	// Load ray tracing compute shader
    Logger::info("Loading ray tracing compute shader...");
    if (!raytracing_shader_.load_compute("shaders/raytracing.comp")) {
        Logger::error("Failed to load ray tracing shader");
        return false;
    }
    shader_cache_["raytracing"] = raytracing_shader_;
    Logger::info("Ray tracing shader loaded successfully");
    
    return true;
}

} // namespace are

文件src/scene/camera.cpp

#include "scene/camera.h"
#include "basic/math.h"
#include <glm/gtc/matrix_transform.hpp>

namespace are {

Camera::Camera()
    : position_(0.0f, 0.0f, 5.0f)
    , target_(0.0f, 0.0f, 0.0f)
    , up_(0.0f, 1.0f, 0.0f)
    , projection_type_(ProjectionType::PERSPECTIVE)
    , fov_(glm::radians(45.0f))
    , aspect_(16.0f / 9.0f)
    , left_(-1.0f)
    , right_(1.0f)
    , bottom_(-1.0f)
    , top_(1.0f)
    , near_(0.1f)
    , far_(100.0f)
    , view_dirty_(true)
    , projection_dirty_(true) {
}

Camera::~Camera() {
}

void Camera::set_perspective(float fov, float aspect, float near, float far) {
    projection_type_ = ProjectionType::PERSPECTIVE;
    fov_ = glm::radians(fov);
    aspect_ = aspect;
    near_ = near;
    far_ = far;
    projection_dirty_ = true;
}

void Camera::set_orthographic(float left, float right, float bottom, float top, float near, float far) {
    projection_type_ = ProjectionType::ORTHOGRAPHIC;
    left_ = left;
    right_ = right;
    bottom_ = bottom;
    top_ = top;
    near_ = near;
    far_ = far;
    projection_dirty_ = true;
}

void Camera::set_position(const Vec3& position) {
    position_ = position;
    view_dirty_ = true;
}

void Camera::set_target(const Vec3& target) {
    target_ = target;
    view_dirty_ = true;
}

void Camera::set_up(const Vec3& up) {
    up_ = up;
    view_dirty_ = true;
}

Mat4 Camera::get_view_matrix() const {
    if (view_dirty_) {
        view_matrix_ = MathUtils::look_at(position_, target_, up_);
        view_dirty_ = false;
    }
    return view_matrix_;
}

Mat4 Camera::get_projection_matrix() const {
    if (projection_dirty_) {
        if (projection_type_ == ProjectionType::PERSPECTIVE) {
            projection_matrix_ = MathUtils::perspective(fov_, aspect_, near_, far_);
        } else {
            projection_matrix_ = glm::ortho(left_, right_, bottom_, top_, near_, far_);
        }
        projection_dirty_ = false;
    }
    return projection_matrix_;
}

Mat4 Camera::get_view_projection_matrix() const {
    return get_projection_matrix() * get_view_matrix();
}

Vec3 Camera::get_forward() const {
    return MathUtils::normalize(target_ - position_);
}

Vec3 Camera::get_right() const {
    Vec3 forward = get_forward();
    return MathUtils::normalize(MathUtils::cross(forward, up_));
}

Vec3 Camera::get_up() const {
    Vec3 forward = get_forward();
    Vec3 right = get_right();
    return MathUtils::cross(right, forward);
}

} // namespace are

文件src/scene/material.cpp

#include "scene/material.h"

namespace are {

Material::Material()
    : albedo_(1.0f, 1.0f, 1.0f)
    , emission_(0.0f, 0.0f, 0.0f)
    , metallic_(0.0f)
    , roughness_(0.5f)
    , ior_(1.5f)
    , type_(MaterialType::DIFFUSE)
    , albedo_texture_(nullptr)
    , normal_texture_(nullptr) {
}

Material::~Material() {
}

void Material::set_albedo(const Vec3& albedo) {
    albedo_ = albedo;
}

void Material::set_emission(const Vec3& emission) {
    emission_ = emission;
}

void Material::set_metallic(float metallic) {
    metallic_ = glm::clamp(metallic, 0.0f, 1.0f);
}

void Material::set_roughness(float roughness) {
    roughness_ = glm::clamp(roughness, 0.0f, 1.0f);
}

void Material::set_ior(float ior) {
    ior_ = ior;
}

void Material::set_type(MaterialType type) {
    type_ = type;
}

void Material::set_albedo_texture(std::shared_ptr<Texture> texture) {
    albedo_texture_ = texture;
}

void Material::set_normal_texture(std::shared_ptr<Texture> texture) {
    normal_texture_ = texture;
}

} // namespace are

文件src/scene/light.cpp

#include "scene/light.h"
#include <glm/gtc/constants.hpp>

namespace are {

Light::Light()
    : type_(LightType::POINT)
    , position_(0.0f, 5.0f, 0.0f)
    , direction_(0.0f, -1.0f, 0.0f)
    , color_(1.0f, 1.0f, 1.0f)
    , intensity_(1.0f)
    , range_(10.0f)
    , inner_angle_(glm::radians(30.0f))
    , outer_angle_(glm::radians(45.0f)) {
}

Light::~Light() {
}

void Light::set_type(LightType type) {
    type_ = type;
}

void Light::set_position(const Vec3& position) {
    position_ = position;
}

void Light::set_direction(const Vec3& direction) {
    direction_ = glm::normalize(direction);
}

void Light::set_color(const Vec3& color) {
    color_ = color;
}

void Light::set_intensity(float intensity) {
    intensity_ = intensity;
}

void Light::set_range(float range) {
    range_ = range;
}

void Light::set_spot_angles(float inner_angle, float outer_angle) {
    inner_angle_ = glm::radians(inner_angle);
    outer_angle_ = glm::radians(outer_angle);
}

} // namespace are

文件src/scene/scene.cpp

#include "scene/scene.h"

namespace are {

Scene::Scene() {
    // Create default camera
    camera_ = std::make_shared<Camera>();
}

Scene::~Scene() {
    clear();
}

uint Scene::add_mesh(std::shared_ptr<Mesh> mesh) {
    meshes_.push_back(mesh);
    return static_cast<uint>(meshes_.size() - 1);
}

uint Scene::add_material(std::shared_ptr<Material> material) {
    materials_.push_back(material);
    return static_cast<uint>(materials_.size() - 1);
}

uint Scene::add_light(std::shared_ptr<Light> light) {
    lights_.push_back(light);
    return static_cast<uint>(lights_.size() - 1);
}

void Scene::set_camera(std::shared_ptr<Camera> camera) {
    camera_ = camera;
}

void Scene::clear() {
    meshes_.clear();
    materials_.clear();
    lights_.clear();
}

void Scene::update(float delta_time) {
    // Reserved for future animation/physics updates
    (void)delta_time; // Suppress unused parameter warning
}

} // namespace are

文件src/scene/mesh.cpp

#include "scene/mesh.h"
#include "utils/logger.h"
#include <glad/glad.h>

namespace are {

Mesh::Mesh()
    : material_id_(0)
    , transform_(1.0f)
    , vao_(0)
    , vbo_(0)
    , ebo_(0)
    , uploaded_(false) {
}

Mesh::~Mesh() {
    release_gpu_resources();
}

void Mesh::set_vertices(const std::vector<Vertex>& vertices) {
    vertices_ = vertices;
    uploaded_ = false;
}

void Mesh::set_indices(const std::vector<uint>& indices) {
    indices_ = indices;
    uploaded_ = false;
}

void Mesh::set_material(uint material_id) {
    material_id_ = material_id;
}

void Mesh::set_transform(const Mat4& transform) {
    transform_ = transform;
}

bool Mesh::upload_to_gpu() {
    if (uploaded_) {
        Logger::warning("Mesh already uploaded to GPU");
        return true;
    }
    
    if (vertices_.empty()) {
        Logger::error("Cannot upload mesh: no vertices");
        return false;
    }
    
    if (indices_.empty()) {
        Logger::error("Cannot upload mesh: no indices");
        return false;
    }
    
    // Generate VAO
    glGenVertexArrays(1, &vao_);
    glBindVertexArray(vao_);
    
    // Generate and upload VBO
    glGenBuffers(1, &vbo_);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_);
    glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), 
                vertices_.data(), GL_STATIC_DRAW);
    
    // Generate and upload EBO
    glGenBuffers(1, &ebo_);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(uint),
                indices_.data(), GL_STATIC_DRAW);
    
    // Set vertex attributes
    // Location 0: Position
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                         (void*)offsetof(Vertex, position_));
    
    // Location 1: Normal
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                         (void*)offsetof(Vertex, normal_));
    
    // Location 2: TexCoord
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                         (void*)offsetof(Vertex, texcoord_));
    
    // Location 3: Tangent
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                         (void*)offsetof(Vertex, tangent_));
    
    glBindVertexArray(0);
    
    uploaded_ = true;
    Logger::info("Mesh uploaded to GPU successfully");
    return true;
}

void Mesh::release_gpu_resources() {
    if (!uploaded_) return;
    
    if (vao_ != 0) {
        glDeleteVertexArrays(1, &vao_);
        vao_ = 0;
    }
    
    if (vbo_ != 0) {
        glDeleteBuffers(1, &vbo_);
        vbo_ = 0;
    }
    
    if (ebo_ != 0) {
        glDeleteBuffers(1, &ebo_);
        ebo_ = 0;
    }
    
    uploaded_ = false;
}

} // namespace are

文件src/resource/buffer.cpp

#include "resource/buffer.h"
#include "utils/logger.h"
#include <glad/glad.h>

namespace are {

namespace {
    GLenum get_gl_buffer_type(BufferType type) {
        switch (type) {
            case BufferType::VERTEX_BUFFER: return GL_ARRAY_BUFFER;
            case BufferType::INDEX_BUFFER: return GL_ELEMENT_ARRAY_BUFFER;
            case BufferType::UNIFORM_BUFFER: return GL_UNIFORM_BUFFER;
            case BufferType::SHADER_STORAGE_BUFFER: return GL_SHADER_STORAGE_BUFFER;
            default: return GL_ARRAY_BUFFER;
        }
    }
    
    GLenum get_gl_usage(BufferUsage usage) {
        switch (usage) {
            case BufferUsage::STATIC_DRAW: return GL_STATIC_DRAW;
            case BufferUsage::DYNAMIC_DRAW: return GL_DYNAMIC_DRAW;
            case BufferUsage::STREAM_DRAW: return GL_STREAM_DRAW;
            default: return GL_STATIC_DRAW;
        }
    }
}

Buffer::Buffer()
    : handle_(INVALID_HANDLE)
    , type_(BufferType::VERTEX_BUFFER)
    , size_(0)
    , usage_(BufferUsage::STATIC_DRAW) {
}

Buffer::~Buffer() {
    // Don't auto-release, let user control lifetime
}

bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) {
    if (handle_ != INVALID_HANDLE) {
        Logger::warning("Buffer already created, releasing old buffer");
        release();
    }
    
    type_ = type;
    size_ = size;
    usage_ = usage;
    
    glGenBuffers(1, &handle_);
    
    GLenum gl_type = get_gl_buffer_type(type);
    GLenum gl_usage = get_gl_usage(usage);
    
    glBindBuffer(gl_type, handle_);
    glBufferData(gl_type, size, data, gl_usage);
    glBindBuffer(gl_type, 0);
    
    Logger::info("Buffer created successfully");
    return true;
}

void Buffer::update(size_t offset, size_t size, const void* data) {
    if (handle_ == INVALID_HANDLE) {
        Logger::error("Cannot update invalid buffer");
        return;
    }
    
    if (offset + size > size_) {
        Logger::error("Buffer update out of bounds");
        return;
    }
    
    GLenum gl_type = get_gl_buffer_type(type_);
    
    glBindBuffer(gl_type, handle_);
    glBufferSubData(gl_type, offset, size, data);
    glBindBuffer(gl_type, 0);
}

void Buffer::bind() const {
    if (handle_ == INVALID_HANDLE) {
        Logger::warning("Attempting to bind invalid buffer");
        return;
    }
    
    GLenum gl_type = get_gl_buffer_type(type_);
    glBindBuffer(gl_type, handle_);
}

void Buffer::bind_base(uint binding_point) const {
    if (handle_ == INVALID_HANDLE) {
        Logger::warning("Attempting to bind invalid buffer");
        return;
    }
    
    GLenum gl_type = get_gl_buffer_type(type_);
    glBindBufferBase(gl_type, binding_point, handle_);
}

void Buffer::unbind() const {
    GLenum gl_type = get_gl_buffer_type(type_);
    glBindBuffer(gl_type, 0);
}

void Buffer::release() {
    if (handle_ != INVALID_HANDLE) {
        glDeleteBuffers(1, &handle_);
        handle_ = INVALID_HANDLE;
    }
    
    size_ = 0;
}

} // namespace are

文件src/resource/model_loader.cpp

#include "resource/model_loader.h"
#include "utils/logger.h"
#include "resource/texture.h"

// Note: This is a simplified implementation without Assimp
// For full implementation, include Assimp and implement properly

namespace are {

bool ModelLoader::load(const std::string& path,
                      std::vector<std::shared_ptr<Mesh>>& meshes,
                      std::vector<std::shared_ptr<Material>>& materials,
                      bool flip_uvs) {
    Logger::error("ModelLoader requires Assimp library (not implemented in this version)");
    Logger::info("To implement: include <assimp/Importer.hpp>, <assimp/scene.h>, <assimp/postprocess.h>");
    
    // Placeholder implementation
    // TODO: Implement with Assimp
    /*
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(path, 
        aiProcess_Triangulate | 
        aiProcess_GenNormals |
        aiProcess_CalcTangentSpace |
        (flip_uvs ? aiProcess_FlipUVs : 0));
    
    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
        Logger::error("Failed to load model: " + std::string(importer.GetErrorString()));
        return false;
    }
    
    std::string directory = path.substr(0, path.find_last_of('/'));
    process_node_(scene->mRootNode, scene, meshes, materials, directory);
    
    Logger::info("Model loaded: " + path);
    return true;
    */
    
    return false;
}

bool ModelLoader::load_and_upload(const std::string& path,
                                 std::vector<std::shared_ptr<Mesh>>& meshes,
                                 std::vector<std::shared_ptr<Material>>& materials,
                                 bool flip_uvs) {
    if (!load(path, meshes, materials, flip_uvs)) {
        return false;
    }
    
    // Upload all meshes to GPU
    for (auto& mesh : meshes) {
        if (!mesh->upload_to_gpu()) {
            Logger::error("Failed to upload mesh to GPU");
            return false;
        }
    }
    
    return true;
}

void ModelLoader::process_node_(void* node, void* scene,
                               std::vector<std::shared_ptr<Mesh>>& meshes,
                               std::vector<std::shared_ptr<Material>>& materials,
                               const std::string& directory) {
    // TODO: Implement with Assimp
    /*
    aiNode* ai_node = static_cast<aiNode*>(node);
    const aiScene* ai_scene = static_cast<const aiScene*>(scene);
    
    // Process all meshes in this node
    for (uint i = 0; i < ai_node->mNumMeshes; ++i) {
        aiMesh* ai_mesh = ai_scene->mMeshes[ai_node->mMeshes[i]];
        meshes.push_back(process_mesh_(ai_mesh, ai_scene, materials, directory));
    }
    
    // Process children recursively
    for (uint i = 0; i < ai_node->mNumChildren; ++i) {
        process_node_(ai_node->mChildren[i], ai_scene, meshes, materials, directory);
    }
    */
}

std::shared_ptr<Mesh> ModelLoader::process_mesh_(void* mesh, void* scene,
                                                std::vector<std::shared_ptr<Material>>& materials,
                                                const std::string& directory) {
    // TODO: Implement with Assimp
    /*
    aiMesh* ai_mesh = static_cast<aiMesh*>(mesh);
    const aiScene* ai_scene = static_cast<const aiScene*>(scene);
    
    std::vector<Vertex> vertices;
    std::vector<uint> indices;
    
    // Process vertices
    for (uint i = 0; i < ai_mesh->mNumVertices; ++i) {
        Vertex vertex;
        
        vertex.position_ = Vec3(ai_mesh->mVertices[i].x,
                               ai_mesh->mVertices[i].y,
                               ai_mesh->mVertices[i].z);
        
        if (ai_mesh->HasNormals()) {
            vertex.normal_ = Vec3(ai_mesh->mNormals[i].x,
                                 ai_mesh->mNormals[i].y,
                                 ai_mesh->mNormals[i].z);
        }
        
        if (ai_mesh->mTextureCoords[0]) {
            vertex.texcoord_ = Vec2(ai_mesh->mTextureCoords[0][i].x,
                                   ai_mesh->mTextureCoords[0][i].y);
        }
        
        if (ai_mesh->HasTangentsAndBitangents()) {
            vertex.tangent_ = Vec3(ai_mesh->mTangents[i].x,
                                  ai_mesh->mTangents[i].y,
                                  ai_mesh->mTangents[i].z);
        }
        
        vertices.push_back(vertex);
    }
    
    // Process indices
    for (uint i = 0; i < ai_mesh->mNumFaces; ++i) {
        aiFace face = ai_mesh->mFaces[i];
        for (uint j = 0; j < face.mNumIndices; ++j) {
            indices.push_back(face.mIndices[j]);
        }
    }
    
    // Process material
    uint material_id = materials.size();
    if (ai_mesh->mMaterialIndex >= 0) {
        aiMaterial* ai_material = ai_scene->mMaterials[ai_mesh->mMaterialIndex];
        
        auto material = std::make_shared<Material>();
        
        // Load diffuse color
        aiColor3D color;
        if (ai_material->Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
            material->set_albedo(Vec3(color.r, color.g, color.b));
        }
        
        // Load textures
        load_material_textures_(ai_material, aiTextureType_DIFFUSE, material, directory);
        load_material_textures_(ai_material, aiTextureType_NORMALS, material, directory);
        
        materials.push_back(material);
    }
    
    auto mesh_obj = std::make_shared<Mesh>();
    mesh_obj->set_vertices(vertices);
    mesh_obj->set_indices(indices);
    mesh_obj->set_material(material_id);
    
    return mesh_obj;
    */
    
    return nullptr;
}

void ModelLoader::load_material_textures_(void* material, int type,
                                         std::shared_ptr<Material>& mat,
                                         const std::string& directory) {
    // TODO: Implement with Assimp
    /*
    aiMaterial* ai_material = static_cast<aiMaterial*>(material);
    aiTextureType ai_type = static_cast<aiTextureType>(type);
    
    for (uint i = 0; i < ai_material->GetTextureCount(ai_type); ++i) {
        aiString str;
        ai_material->GetTexture(ai_type, i, &str);
        
        std::string filename = directory + "/" + std::string(str.C_Str());
        
        auto texture = std::make_shared<Texture>();
        if (texture->load_from_file(filename)) {
            if (ai_type == aiTextureType_DIFFUSE) {
                mat->set_albedo_texture(texture);
            } else if (ai_type == aiTextureType_NORMALS) {
                mat->set_normal_texture(texture);
            }
        }
    }
    */
}

} // namespace are

文件src/resource/shader.cpp

#include "resource/shader.h"
#include "utils/logger.h"
#include "basic/math.h"  // 修改为math.h
#include <glad/glad.h>
#include <fstream>
#include <sstream>

namespace are {

Shader::Shader()
    : handle_(INVALID_HANDLE) {
}

Shader::~Shader() {
    // Don't auto-release, let user control lifetime
}

bool Shader::load(const std::string& vertex_path, const std::string& fragment_path) {
    std::string vertex_source = read_file_(vertex_path);
    std::string fragment_source = read_file_(fragment_path);
    
    if (vertex_source.empty() || fragment_source.empty()) {
        Logger::error("Failed to read shader files");
        return false;
    }
    
    return compile(vertex_source, fragment_source);
}

bool Shader::load_compute(const std::string& compute_path) {
    std::string compute_source = read_file_(compute_path);
    
    if (compute_source.empty()) {
        Logger::error("Failed to read compute shader file");
        return false;
    }
    
    return compile_compute(compute_source);
}

bool Shader::compile(const std::string& vertex_source, const std::string& fragment_source) {
    uint vertex_shader = compile_shader_(vertex_source, GL_VERTEX_SHADER);
    if (vertex_shader == 0) return false;
    
    uint fragment_shader = compile_shader_(fragment_source, GL_FRAGMENT_SHADER);
    if (fragment_shader == 0) {
        glDeleteShader(vertex_shader);
        return false;
    }
    
    uint shaders[] = { vertex_shader, fragment_shader };
    bool success = link_program_(shaders, 2);
    
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    
    return success;
}

bool Shader::compile_compute(const std::string& compute_source) {
    uint compute_shader = compile_shader_(compute_source, GL_COMPUTE_SHADER);
    if (compute_shader == 0) return false;
    
    uint shaders[] = { compute_shader };
    bool success = link_program_(shaders, 1);
    
    glDeleteShader(compute_shader);
    
    return success;
}

void Shader::use() const {  // 改为const
    if (handle_ != INVALID_HANDLE) {
        glUseProgram(handle_);
    }
}

void Shader::release() {
    if (handle_ != INVALID_HANDLE) {
        glDeleteProgram(handle_);
        handle_ = INVALID_HANDLE;
    }
    uniform_cache_.clear();
}

void Shader::set_bool(const std::string& name, bool value) const {  // 新增
    glUniform1i(get_uniform_location_(name), static_cast<int>(value));
}

void Shader::set_int(const std::string& name, int value) const {  // 改为const
    glUniform1i(get_uniform_location_(name), value);
}

void Shader::set_uint(const std::string& name, uint value) const {  // 改为const
    glUniform1ui(get_uniform_location_(name), value);
}

void Shader::set_float(const std::string& name, float value) const {  // 改为const
    glUniform1f(get_uniform_location_(name), value);
}

void Shader::set_vec2(const std::string& name, const Vec2& value) const {  // 改为const
    glUniform2fv(get_uniform_location_(name), 1, &value[0]);
}

void Shader::set_vec3(const std::string& name, const Vec3& value) const {  // 改为const
    glUniform3fv(get_uniform_location_(name), 1, &value[0]);
}

void Shader::set_vec4(const std::string& name, const Vec4& value) const {  // 改为const
    glUniform4fv(get_uniform_location_(name), 1, &value[0]);
}

void Shader::set_mat3(const std::string& name, const Mat3& value) const {  // 改为const
    glUniformMatrix3fv(get_uniform_location_(name), 1, GL_FALSE, &value[0][0]);
}

void Shader::set_mat4(const std::string& name, const Mat4& value) const {  // 改为const
    glUniformMatrix4fv(get_uniform_location_(name), 1, GL_FALSE, MathUtils::value_ptr(value));
}

int Shader::get_uniform_location_(const std::string& name) const {  // 改为const
    auto it = uniform_cache_.find(name);
    if (it != uniform_cache_.end()) {
        return it->second;
    }
    
    int location = glGetUniformLocation(handle_, name.c_str());
    uniform_cache_[name] = location;  // mutable允许修改
    
    if (location == -1) {
        Logger::warning("Uniform '" + name + "' not found in shader");
    }
    
    return location;
}

uint Shader::compile_shader_(const std::string& source, uint type) {
    uint shader = glCreateShader(type);
    const char* source_cstr = source.c_str();
    glShaderSource(shader, 1, &source_cstr, nullptr);
    glCompileShader(shader);
    
    int success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char info_log[512];
        glGetShaderInfoLog(shader, 512, nullptr, info_log);
        
        std::string type_str = (type == GL_VERTEX_SHADER) ? "VERTEX" :
                              (type == GL_FRAGMENT_SHADER) ? "FRAGMENT" : "COMPUTE";
        Logger::error("Shader compilation failed (" + type_str + "): " + std::string(info_log));
        
        glDeleteShader(shader);
        return 0;
    }
    
    return shader;
}

bool Shader::link_program_(const uint* shaders, uint count) {
    handle_ = glCreateProgram();
    
    for (uint i = 0; i < count; ++i) {
        glAttachShader(handle_, shaders[i]);
    }
    
    glLinkProgram(handle_);
    
    int success;
    glGetProgramiv(handle_, GL_LINK_STATUS, &success);
    if (!success) {
        char info_log[512];
        glGetProgramInfoLog(handle_, 512, nullptr, info_log);
        Logger::error("Shader linking failed: " + std::string(info_log));
        
        glDeleteProgram(handle_);
        handle_ = INVALID_HANDLE;
        return false;
    }
    
    return true;
}

std::string Shader::read_file_(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        Logger::error("Failed to open file: " + path);
        return "";
    }
    
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

} // namespace are

文件src/resource/texture.cpp

#include "resource/texture.h"
#include "utils/logger.h"
#include <glad/glad.h>
#include <stb_image.h>

namespace are {

namespace {
    GLenum get_gl_internal_format(TextureFormat format) {
        switch (format) {
            case TextureFormat::R8: return GL_R8;
            case TextureFormat::RG8: return GL_RG8;
            case TextureFormat::RGB8: return GL_RGB8;
            case TextureFormat::RGBA8: return GL_RGBA8;
            case TextureFormat::R16F: return GL_R16F;
            case TextureFormat::RG16F: return GL_RG16F;
            case TextureFormat::RGB16F: return GL_RGB16F;
            case TextureFormat::RGBA16F: return GL_RGBA16F;
            case TextureFormat::R32F: return GL_R32F;
            case TextureFormat::RG32F: return GL_RG32F;
            case TextureFormat::RGB32F: return GL_RGB32F;
            case TextureFormat::RGBA32F: return GL_RGBA32F;
            case TextureFormat::DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8;
            default: return GL_RGBA8;
        }
    }
    
    GLenum get_gl_format(TextureFormat format) {
        switch (format) {
            case TextureFormat::R8:
            case TextureFormat::R16F:
            case TextureFormat::R32F:
                return GL_RED;
            case TextureFormat::RG8:
            case TextureFormat::RG16F:
            case TextureFormat::RG32F:
                return GL_RG;
            case TextureFormat::RGB8:
            case TextureFormat::RGB16F:
            case TextureFormat::RGB32F:
                return GL_RGB;
            case TextureFormat::RGBA8:
            case TextureFormat::RGBA16F:
            case TextureFormat::RGBA32F:
                return GL_RGBA;
            case TextureFormat::DEPTH24_STENCIL8:
                return GL_DEPTH_STENCIL;
            default:
                return GL_RGBA;
        }
    }
    
    GLenum get_gl_type(TextureFormat format) {
        switch (format) {
            case TextureFormat::R8:
            case TextureFormat::RG8:
            case TextureFormat::RGB8:
            case TextureFormat::RGBA8:
                return GL_UNSIGNED_BYTE;
            case TextureFormat::R16F:
            case TextureFormat::RG16F:
            case TextureFormat::RGB16F:
            case TextureFormat::RGBA16F:
            case TextureFormat::R32F:
            case TextureFormat::RG32F:
            case TextureFormat::RGB32F:
            case TextureFormat::RGBA32F:
                return GL_FLOAT;
            case TextureFormat::DEPTH24_STENCIL8:
                return GL_UNSIGNED_INT_24_8;
            default:
                return GL_UNSIGNED_BYTE;
        }
    }
    
    GLenum get_gl_filter(TextureFilter filter) {
        switch (filter) {
            case TextureFilter::NEAREST: return GL_NEAREST;
            case TextureFilter::LINEAR: return GL_LINEAR;
            case TextureFilter::NEAREST_MIPMAP_NEAREST: return GL_NEAREST_MIPMAP_NEAREST;
            case TextureFilter::LINEAR_MIPMAP_NEAREST: return GL_LINEAR_MIPMAP_NEAREST;
            case TextureFilter::NEAREST_MIPMAP_LINEAR: return GL_NEAREST_MIPMAP_LINEAR;
            case TextureFilter::LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
            default: return GL_LINEAR;
        }
    }
    
    GLenum get_gl_wrap(TextureWrap wrap) {
        switch (wrap) {
            case TextureWrap::REPEAT: return GL_REPEAT;
            case TextureWrap::MIRRORED_REPEAT: return GL_MIRRORED_REPEAT;
            case TextureWrap::CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
            case TextureWrap::CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER;
            default: return GL_REPEAT;
        }
    }
}

Texture::Texture()
    : handle_(INVALID_HANDLE)
    , width_(0)
    , height_(0)
    , format_(TextureFormat::RGBA8)
    , has_mipmaps_(false) {
}

Texture::~Texture() {
    // Don't auto-release, let user control lifetime
}

bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
    // Load image using stb_image
    int width, height, channels;
    stbi_set_flip_vertically_on_load(true);
    unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
    
    if (!data) {
        Logger::error("Failed to load texture: " + path);
        return false;
    }
    
    // Determine format based on channels
    TextureFormat format;
    switch (channels) {
        case 1: format = TextureFormat::R8; break;
        case 2: format = TextureFormat::RG8; break;
        case 3: format = TextureFormat::RGB8; break;
        case 4: format = TextureFormat::RGBA8; break;
        default:
            Logger::error("Unsupported channel count: " + std::to_string(channels));
            stbi_image_free(data);
            return false;
    }
    
    // Create texture
    bool success = create(width, height, format);
    if (!success) {
        stbi_image_free(data);
        return false;
    }
    
    // Upload data
    success = upload(data, width, height, format);
    stbi_image_free(data);
    
    if (!success) {
        return false;
    }
    
    // Generate mipmaps if requested
    if (generate_mipmaps) {
        this->generate_mipmaps();
    }
    
    Logger::info("Texture loaded successfully: " + path);
    return true;
}

bool Texture::create(uint width, uint height, TextureFormat format) {
    if (handle_ != INVALID_HANDLE) {
        Logger::warning("Texture already created, releasing old texture");
        release();
    }
    
    width_ = width;
    height_ = height;
    format_ = format;
    
    glGenTextures(1, &handle_);
    glBindTexture(GL_TEXTURE_2D, handle_);
    
    GLenum internal_format = get_gl_internal_format(format);
    GLenum gl_format = get_gl_format(format);
    GLenum type = get_gl_type(format);
    
    glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, gl_format, type, nullptr);
    
    // Set default parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    
    glBindTexture(GL_TEXTURE_2D, 0);
    
    return true;
}

bool Texture::upload(const void* data, uint width, uint height, TextureFormat format) {
    if (handle_ == INVALID_HANDLE) {
        Logger::error("Cannot upload to invalid texture");
        return false;
    }
    
    if (width != width_ || height != height_ || format != format_) {
        Logger::warning("Upload parameters differ from texture creation, recreating texture");
        create(width, height, format);
    }
    
    glBindTexture(GL_TEXTURE_2D, handle_);
    
    GLenum gl_format = get_gl_format(format);
    GLenum type = get_gl_type(format);
    
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, gl_format, type, data);
    
    glBindTexture(GL_TEXTURE_2D, 0);
    
    return true;
}

void Texture::set_filter(TextureFilter min_filter, TextureFilter mag_filter) {
    if (handle_ == INVALID_HANDLE) {
        Logger::error("Cannot set filter on invalid texture");
        return;
    }
    
    glBindTexture(GL_TEXTURE_2D, handle_);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, get_gl_filter(min_filter));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, get_gl_filter(mag_filter));
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::set_wrap(TextureWrap wrap_s, TextureWrap wrap_t) {
    if (handle_ == INVALID_HANDLE) {
        Logger::error("Cannot set wrap mode on invalid texture");
        return;
    }
    
    glBindTexture(GL_TEXTURE_2D, handle_);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, get_gl_wrap(wrap_s));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, get_gl_wrap(wrap_t));
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::generate_mipmaps() {
    if (handle_ == INVALID_HANDLE) {
        Logger::error("Cannot generate mipmaps for invalid texture");
        return;
    }
    
    glBindTexture(GL_TEXTURE_2D, handle_);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
    
    has_mipmaps_ = true;
}

void Texture::bind(uint unit) const {
    if (handle_ == INVALID_HANDLE) {
        Logger::warning("Attempting to bind invalid texture");
        return;
    }
    
    glActiveTexture(GL_TEXTURE0 + unit);
    glBindTexture(GL_TEXTURE_2D, handle_);
}

void Texture::unbind() const {
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::release() {
    if (handle_ != INVALID_HANDLE) {
        glDeleteTextures(1, &handle_);
        handle_ = INVALID_HANDLE;
    }
    
    width_ = 0;
    height_ = 0;
    has_mipmaps_ = false;
}

} // namespace are

文件src/utils/config.cpp

#include "utils/config.h"
#include "utils/logger.h"
#include <fstream>
#include <sstream>
#include <algorithm>

namespace are {

// Static storage
static std::unordered_map<std::string, std::string> g_config_map;

// Helper function to trim whitespace
static std::string trim(const std::string& str) {
    size_t first = str.find_first_not_of(" \t\r\n");
    if (first == std::string::npos) return "";
    size_t last = str.find_last_not_of(" \t\r\n");
    return str.substr(first, last - first + 1);
}

bool Config::load(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        Logger::error("Failed to open config file: " + path);
        return false;
    }
    
    g_config_map.clear();
    
    std::string line;
    std::string current_section;
    
    while (std::getline(file, line)) {
        line = trim(line);
        
        // Skip empty lines and comments
        if (line.empty() || line[0] == '#' || line[0] == ';') {
            continue;
        }
        
        // Section header
        if (line[0] == '[' && line.back() == ']') {
            current_section = line.substr(1, line.length() - 2);
            continue;
        }
        
        // Key-value pair
        size_t pos = line.find('=');
        if (pos != std::string::npos) {
            std::string key = trim(line.substr(0, pos));
            std::string value = trim(line.substr(pos + 1));
            
            // Add section prefix if in a section
            if (!current_section.empty()) {
                key = current_section + "." + key;
            }
            
            g_config_map[key] = value;
        }
    }
    
    Logger::info("Config loaded: " + path + " (" + std::to_string(g_config_map.size()) + " entries)");
    return true;
}

bool Config::save(const std::string& path) {
    std::ofstream file(path);
    if (!file.is_open()) {
        Logger::error("Failed to open config file for writing: " + path);
        return false;
    }
    
    for (const auto& pair : g_config_map) {
        file << pair.first << "=" << pair.second << std::endl;
    }
    
    Logger::info("Config saved: " + path);
    return true;
}

std::string Config::get_string(const std::string& key, const std::string& default_value) {
    auto it = g_config_map.find(key);
    if (it != g_config_map.end()) {
        return it->second;
    }
    return default_value;
}

int Config::get_int(const std::string& key, int default_value) {
    auto it = g_config_map.find(key);
    if (it != g_config_map.end()) {
        try {
            return std::stoi(it->second);
        } catch (...) {
            Logger::warning("Failed to parse int for key: " + key);
        }
    }
    return default_value;
}

float Config::get_float(const std::string& key, float default_value) {
    auto it = g_config_map.find(key);
    if (it != g_config_map.end()) {
        try {
            return std::stof(it->second);
        } catch (...) {
            Logger::warning("Failed to parse float for key: " + key);
        }
    }
    return default_value;
}

bool Config::get_bool(const std::string& key, bool default_value) {
    auto it = g_config_map.find(key);
    if (it != g_config_map.end()) {
        std::string value = it->second;
        std::transform(value.begin(), value.end(), value.begin(), ::tolower);
        
        if (value == "true" || value == "1" || value == "yes" || value == "on") {
            return true;
        }
        if (value == "false" || value == "0" || value == "no" || value == "off") {
            return false;
        }
    }
    return default_value;
}

void Config::set_string(const std::string& key, const std::string& value) {
    g_config_map[key] = value;
}

void Config::set_int(const std::string& key, int value) {
    g_config_map[key] = std::to_string(value);
}

void Config::set_float(const std::string& key, float value) {
    g_config_map[key] = std::to_string(value);
}

void Config::set_bool(const std::string& key, bool value) {
    g_config_map[key] = value ? "true" : "false";
}

} // namespace are

文件src/utils/logger.cpp

#include "utils/logger.h"
#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <sstream>

namespace are {

// Static members
static LogLevel g_min_level = LogLevel::DEBUG;
static std::ofstream g_log_file;
static bool g_initialized = false;

bool Logger::initialize(const std::string& log_file) {
    if (g_initialized) {
        return true;
    }
    
    if (!log_file.empty()) {
        g_log_file.open(log_file, std::ios::out | std::ios::app);
        if (!g_log_file.is_open()) {
            std::cerr << "Failed to open log file: " << log_file << std::endl;
            return false;
        }
    }
    
    g_initialized = true;
    return true;
}

void Logger::shutdown() {
    if (g_log_file.is_open()) {
        g_log_file.close();
    }
    g_initialized = false;
}

static std::string get_current_time() {
    auto now = std::time(nullptr);
    auto tm = *std::localtime(&now);
    std::ostringstream oss;
    oss << std::put_time(&tm, "%H:%M:%S");
    return oss.str();
}

static std::string level_to_string(LogLevel level) {
    switch (level) {
        case LogLevel::DEBUG: return "DEBUG";
        case LogLevel::INFO: return "INFO";
        case LogLevel::WARNING: return "WARN";
        case LogLevel::ERROR: return "ERROR";
        case LogLevel::FATAL: return "FATAL";
        default: return "UNKNOWN";
    }
}

void Logger::log(LogLevel level, const std::string& message) {
    if (level < g_min_level) return;
    
    std::string time_str = get_current_time();
    std::string level_str = level_to_string(level);
    std::string formatted = "[" + time_str + "] [" + level_str + "] " + message;
    
    // Console output
    if (level >= LogLevel::ERROR) {
        std::cerr << formatted << std::endl;
    } else {
        std::cout << formatted << std::endl;
    }
    
    // File output
    if (g_log_file.is_open()) {
        g_log_file << formatted << std::endl;
        g_log_file.flush();
    }
}

void Logger::debug(const std::string& message) {
    log(LogLevel::DEBUG, message);
}

void Logger::info(const std::string& message) {
    log(LogLevel::INFO, message);
}

void Logger::warning(const std::string& message) {
    log(LogLevel::WARNING, message);
}

void Logger::error(const std::string& message) {
    log(LogLevel::ERROR, message);
}

void Logger::fatal(const std::string& message) {
    log(LogLevel::FATAL, message);
}

void Logger::set_level(LogLevel level) {
    g_min_level = level;
}

} // namespace are