moltrun 1.7.2

High-performance game engine library with AI capabilities, built on wgpu for modern 3D graphics and physics simulation
Documentation
use super::batch::SpriteBatch;
use super::super::gpu::{GraphicsContext, RenderPipeline};
use super::super::resources::{Vertex, TextureCache};
use crate::runtime::AssetManager;

/// 실제 렌더링 명령을 수행하는 모듈
pub struct RenderCommands<'a> {
    graphics: &'a GraphicsContext,
    render_pipeline: &'a RenderPipeline,
}

impl<'a> RenderCommands<'a> {
    pub fn new(
        graphics: &'a GraphicsContext,
        render_pipeline: &'a RenderPipeline,
    ) -> Self {
        Self {
            graphics,
            render_pipeline,
        }
    }

    /// 스프라이트 배치를 사용하여 렌더 패스 실행 (텍스처 지원)
    pub fn execute_render_pass_with_textures(
        &self,
        encoder: &mut wgpu::CommandEncoder,
        view: &wgpu::TextureView,
        sprite_batch: &SpriteBatch,
        texture_cache: &mut TextureCache,
        asset_manager: &mut AssetManager,
    ) {
        if sprite_batch.is_empty() {
            return;
        }

        let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
            label: Some("Render Pass"),
            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                view,
                resolve_target: None,
                ops: wgpu::Operations {
                    load: wgpu::LoadOp::Clear(wgpu::Color {
                        r: 0.1,
                        g: 0.2,
                        b: 0.3,
                        a: 1.0,
                    }),
                    store: wgpu::StoreOp::Store,
                },
                depth_slice: None,
            })],
            depth_stencil_attachment: None,
            occlusion_query_set: None,
            timestamp_writes: None,
        });

        render_pass.set_pipeline(self.render_pipeline.pipeline());

        // BindGroup들을 먼저 생성하여 수명 보장
        let mut bind_groups = Vec::new();
        let mut vertex_buffers = Vec::new();
        let mut index_buffers = Vec::new();
        
        for sprite_data in sprite_batch.sprites().iter() {
            let cached_texture = texture_cache.get_or_load(
                &sprite_data.texture_path,
                asset_manager,
            );
            
            // BindGroup 생성 및 저장
            let bind_group = self.graphics.device().create_bind_group(&wgpu::BindGroupDescriptor {
                label: Some("Texture Bind Group"),
                layout: self.render_pipeline.texture_bind_group_layout(),
                entries: &[
                    wgpu::BindGroupEntry {
                        binding: 0,
                        resource: wgpu::BindingResource::TextureView(&cached_texture.view),
                    },
                    wgpu::BindGroupEntry {
                        binding: 1,
                        resource: wgpu::BindingResource::Sampler(&cached_texture.sampler),
                    },
                ],
            });
            bind_groups.push(bind_group);
            
            // 버퍼 생성 및 저장
            let vertex_buffer = self.create_vertex_buffer(&sprite_data.vertices);
            let index_buffer = self.create_index_buffer(&sprite_data.indices);
            vertex_buffers.push(vertex_buffer);
            index_buffers.push(index_buffer);
        }
        
        // 실제 렌더링
        for idx in 0..sprite_batch.sprites().len() {
            render_pass.set_bind_group(0, &bind_groups[idx], &[]);
            render_pass.set_vertex_buffer(0, vertex_buffers[idx].slice(..));
            render_pass.set_index_buffer(index_buffers[idx].slice(..), wgpu::IndexFormat::Uint16);
            render_pass.draw_indexed(0..6, 0, 0..1);
        }
    }

    fn create_vertex_buffer(&self, sprites: &[Vertex]) -> wgpu::Buffer {
        let buffer = self.graphics.device().create_buffer(&wgpu::BufferDescriptor {
            label: Some("Vertex Buffer"),
            size: (std::mem::size_of::<Vertex>() * sprites.len()) as u64,
            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        });
        
        self.graphics.queue().write_buffer(&buffer, 0, bytemuck::cast_slice(sprites));
        buffer
    }

    fn create_index_buffer(&self, indices: &[u16]) -> wgpu::Buffer {
        let buffer = self.graphics.device().create_buffer(&wgpu::BufferDescriptor {
            label: Some("Index Buffer"),
            size: (std::mem::size_of::<u16>() * indices.len()) as u64,
            usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        });
        
        self.graphics.queue().write_buffer(&buffer, 0, bytemuck::cast_slice(indices));
        buffer
    }
}