moltrun 1.7.2

High-performance game engine library with AI capabilities, built on wgpu for modern 3D graphics and physics simulation
Documentation
use std::collections::HashMap;
use std::sync::Arc;
use wgpu::{Device, Queue, Texture, TextureView, Sampler};
use image::DynamicImage;
use crate::runtime::{AssetManager, AssetResult};
use super::texture::{create_texture_from_image, create_placeholder_texture};

/// GPU에 바인딩할 수 있는 캐시된 텍스처
/// TextureView와 Sampler를 포함하여 BindGroup 생성 시 바로 사용 가능
pub struct CachedTexture {
    pub texture: Texture,
    pub view: TextureView,
    pub sampler: Sampler,
}

impl CachedTexture {
    /// DynamicImage로부터 CachedTexture 생성
    pub fn from_image(image: &DynamicImage, device: &Device, queue: &Queue) -> AssetResult<Self> {
        let texture = create_texture_from_image(device, queue, image)?;
        
        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
            label: Some("Texture Sampler"),
            address_mode_u: wgpu::AddressMode::ClampToEdge,
            address_mode_v: wgpu::AddressMode::ClampToEdge,
            address_mode_w: wgpu::AddressMode::ClampToEdge,
            mag_filter: wgpu::FilterMode::Linear,
            min_filter: wgpu::FilterMode::Linear,
            mipmap_filter: wgpu::FilterMode::Nearest,
            ..Default::default()
        });
        
        Ok(Self {
            texture,
            view,
            sampler,
        })
    }
    
    /// Placeholder용 간단한 생성자
    fn from_texture(texture: Texture, device: &Device) -> Self {
        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
            label: Some("Placeholder Sampler"),
            ..Default::default()
        });
        
        Self {
            texture,
            view,
            sampler,
        }
    }
}

/// 텍스처 캐시 - GPU 리소스 관리
/// AssetManager에서 이미지를 받아 GPU 텍스처로 변환 및 캐싱
pub struct TextureCache {
    cache: HashMap<String, CachedTexture>,
    device: Arc<Device>,
    queue: Arc<Queue>,
    placeholder: CachedTexture,
}

impl TextureCache {
    pub fn new(device: Arc<Device>, queue: Arc<Queue>) -> Self {
        let placeholder_texture = create_placeholder_texture(&device, &queue, [255, 0, 255, 255]);
        let placeholder = CachedTexture::from_texture(placeholder_texture, &device);
        
        Self {
            cache: HashMap::new(),
            device,
            queue,
            placeholder,
        }
    }
    
    /// 텍스처를 가져오거나 로드합니다
    /// 1. 캐시에 있으면 반환
    /// 2. 없으면 AssetManager에서 이미지 로드 → GPU 업로드 → 캐싱
    /// 3. 실패 시 placeholder 반환
    pub fn get_or_load(
        &mut self,
        texture_path: &str,
        asset_manager: &mut AssetManager,
    ) -> &CachedTexture {
        if texture_path.is_empty() {
            return &self.placeholder;
        }
        
        if self.cache.contains_key(texture_path) {
            return &self.cache[texture_path];
        }
        
        let image = match asset_manager.load_image(texture_path) {
            Ok(img) => img,
            Err(e) => {
                log::warn!("Failed to load image '{}': {}", texture_path, e);
                return &self.placeholder;
            }
        };

        let cached_texture = match CachedTexture::from_image(&image, &self.device, &self.queue) {
            Ok(tex) => tex,
            Err(e) => {
                log::warn!("Failed to create texture '{}': {}", texture_path, e);
                return &self.placeholder;
            }
        };

        self.cache.insert(texture_path.to_string(), cached_texture);
        log::info!("✅ 텍스처 GPU 업로드: {}", texture_path);
        
        &self.cache[texture_path]
    }
    
    pub fn placeholder(&self) -> &CachedTexture {
        &self.placeholder
    }

    pub fn clear(&mut self) {
        self.cache.clear();
        log::info!("TextureCache 초기화");
    }
}