moltrun 1.7.2

High-performance game engine library with AI capabilities, built on wgpu for modern 3D graphics and physics simulation
Documentation
use crate::components::{Transform, Sprite};
use super::super::resources::Vertex;

/// 2D 좌표 변환 유틸리티
pub struct CoordinateTransform {
    screen_width: f32,
    screen_height: f32,
}

impl CoordinateTransform {
    pub fn new(screen_width: f32, screen_height: f32) -> Self {
        Self { screen_width, screen_height }
    }
    
    /// 화면 픽셀 좌표를 NDC(Normalized Device Coordinates)로 변환
    /// 화면: (0,0) = 왼쪽 위 → NDC: (-1,1) = 왼쪽 위
    pub fn screen_to_ndc(&self, screen_x: f32, screen_y: f32) -> [f32; 2] {
        let ndc_x = (screen_x / self.screen_width) * 2.0 - 1.0;
        let ndc_y = 1.0 - (screen_y / self.screen_height) * 2.0; // Y축 뒤집기
        [ndc_x, ndc_y]
    }
    
    /// 화면 크기를 NDC 크기로 변환
    pub fn screen_size_to_ndc(&self, width: f32, height: f32) -> [f32; 2] {
        [width / self.screen_width, height / self.screen_height]
    }
}

/// 2D 변환 (위치, 크기, 회전) 계산기
pub struct Transform2D;

impl Transform2D {
    /// 로컬 좌표에 2D 변환 적용 (회전 + 이동)
    pub fn apply_transform(
        local_pos: [f32; 2],
        center: [f32; 2], 
        rotation: f32
    ) -> [f32; 2] {
        let rotation_rad = rotation.to_radians();  // degree를 radian으로 변환
        let cos_r = rotation_rad.cos();
        let sin_r = rotation_rad.sin();
        
        // 회전 적용
        let rotated_x = local_pos[0] * cos_r - local_pos[1] * sin_r;
        let rotated_y = local_pos[0] * sin_r + local_pos[1] * cos_r;
        
        // 이동 적용
        [center[0] + rotated_x, center[1] + rotated_y]
    }
    
    /// Transform과 Sprite로부터 사각형 4개 모서리 좌표 계산
    pub fn calculate_sprite_corners(
        transform: &Transform,
        sprite: &Sprite,
        coord_transform: &CoordinateTransform,
    ) -> [Vertex; 4] {
        // 실제 크기 (scale 적용)
        let width = sprite.size.x * transform.scale.x;
        let height = sprite.size.y * transform.scale.y;
        
        // 스프라이트 색상
        let color = [sprite.color.r, sprite.color.g, sprite.color.b, sprite.color.a];
        
        // UV 좌표 계산 (flip_x, flip_y 고려)
        let u_start = if sprite.flip_x { 1.0 } else { 0.0 };
        let u_end = if sprite.flip_x { 0.0 } else { 1.0 };
        let v_start = if sprite.flip_y { 1.0 } else { 0.0 };
        let v_end = if sprite.flip_y { 0.0 } else { 1.0 };
        
        let uv_coords = [
            [u_start, v_start], // 왼쪽 아래
            [u_end, v_start],   // 오른쪽 아래
            [u_end, v_end],     // 오른쪽 위
            [u_start, v_end],   // 왼쪽 위
        ];
        
        // 화면 좌표계의 로컬 모서리 좌표 (픽셀 단위)
        let local_corners_screen = [
            [-width / 2.0, -height / 2.0], // 왼쪽 아래
            [width / 2.0, -height / 2.0],  // 오른쪽 아래
            [width / 2.0, height / 2.0],   // 오른쪽 위
            [-width / 2.0, height / 2.0],  // 왼쪽 위
        ];
        
        // 화면 좌표계의 중심점
        let center_screen = [transform.position.x, transform.position.y];
        
        // 회전 적용 후 NDC 변환, UV 좌표 포함
        let mut vertices = [Vertex::with_uv([0.0, 0.0], color, [0.0, 0.0]); 4];
        for (i, &local_pos) in local_corners_screen.iter().enumerate() {
            // 1. 화면 좌표에서 회전 적용
            let rotated_screen = Self::apply_transform(local_pos, center_screen, transform.rotation);
            
            // 2. 회전된 화면 좌표를 NDC로 변환
            let final_ndc = coord_transform.screen_to_ndc(rotated_screen[0], rotated_screen[1]);
            vertices[i] = Vertex::with_uv(final_ndc, color, uv_coords[i]);
        }
        
        vertices
    }
}