0314

2026년 3월 14일

레터박스의 구현

0314.gif

일단 고도엔진에 keep설정에 대응되는

레터박싱을 구현해 보았다.

FinalDrawPass의 result_texture와

resolving_tex 를 강제로 삭제하고

1600x900 이란 상수 크기로 다시 만들어 주입했다.


이걸 나중에 앱 딴에다가 놔야 한다.

걍 none인지, keep인지, keep_width인지, keep_height인지.

또 IFinalDrawPass에

owner.m_어쩌고 이런식으로 되있는거 함수로 정상화시킴

레터박싱에 따른 screen mouse pos를 적절히 클리핑하고

해당 상수 범위 내로 만든 다음, view mouse pos도 (1600, 900) / 2를 빼서 구한다.


아무튼 이 기능의 핵심은

윈도우 크기가 바뀌어도 메인 스크린 자체의 종횡비가 유지되어

메인 스크린이 아닌 영역에는 검은색 띠가 생기는 것이다.

또한, 검은 띠가 생겨도?

엔진 사용자 딴에서는 검은 띠 영역에 대해서는 마우스 위치를 고려하지 않겠지만,

GLFW는 그런 거 없고 그냥 생으로 주기 때문에,

특수화해서 만든 IFinalLetterboxDrawPassregister_screen_mouse_position_info() 에서

검은 띠 영역은 잘라놓고 비율을 직접 계산,

이후 올바른 screen 저장하고 → view / world 마우스 위치를 저장해둔다.

이거 구현이 아주 약간 머리아픈 건 있다.

일단 난 다음처럼 만들었다.

void IFinalLettexboxDrawPass::register_screen_mouse_position_info(const Vector2f& value) {
    // 이러면 안됨. 레터박스로 잘라서.
    //m_screen_mouse_position = value;

    const auto& window_size = get_owner().get_owner().get_last_window_size();
    //const auto& window_size = get_owner().get_owner().m_WindowSize4User;
    dp::Vector2f topleft = dp::Vector2f(window_size / 2u) - (dp::Vector2f(get_size()) / 2.0f);
    dp::Vector2f bottomright = dp::Vector2f(window_size / 2u) + (dp::Vector2f(get_size()) / 2.0f);

    // topleft가 시작점이 됨.
    // 끝점이 bottomright.
    dp::Vector2f cursor = value;
    cursor.x = dp::clamp(cursor.x, topleft.x, bottomright.x);
    cursor.y = dp::clamp(cursor.y, topleft.y, bottomright.y);
    cursor -= topleft;

    // 이제 [0, ActualSize.x] 범위를 [0, 1] 로 만든 후에
    //      [0, 1600]으로
    const auto& WIN_INITIAL_SIZE = get_owner().get_owner().get_window()->get_initial_size();

    cursor /= dp::Vector2f(get_size());
    cursor *= dp::Vector2f(WIN_INITIAL_SIZE); // dp::Vector2f(1600, 900);

    m_screen_mouse_position = cursor;

    this->update_mosue_position_info();
}

내가 강조하고 싶은 건 IFinalLetterboxDrawPass 의 중요성이다.

얘가 해야 하는 건 다음과 같다.

  • 방금 위에서 언급한 마우스 위치 적절히 저장
  • update() 부분에서 '클리핑 영역'의 초깃값을 윈도우의 현재 크기가 아닌, 고정된 초기 윈도우 상수 크기로 재구현. -> for 콜리젼 디텍션
  • 마찬가지로 draw() 부분에서도 초기 윈도우 크기로 재구현. -> for UI 렌더링 클리핑

  • 가장 중요한거. 종횡비를 유지시켜서 actual size 를 계산하고, IDrawPass::m_sizeresize()통해서 "실질적 크기" 로 저장해두기.


참고로 이 레터박싱 기능을 쓰기 위해

내가 고안한 조건들은 다음과 같다.

  1. app에서 WindowDesc를 줄 때, desc.LetterboxEnabled 를 true로 해준다.

  2. IFinalDrawPass 대신에, IFinalLetterboxDrawPass 를 그대로 쓰거나? 아니면 직접 만든다.

  3. 2D 카메라 업데이트와, fdp같이, 윈도우 크기에 관련된 건 전부!!! desc에 적었던 초깃값 상수로 계산한다 (window->get_initial_size()로 얻을 수 있다)

  4. 모든 UI (및 스크린 시스템) 만들 때 윈도우 크기가 상수라고 가정하고 배치한다.

  5. App 단에서, 리사이징되거나?? 마우스 움직였다면? Scene에 연결해서

밑에처럼 반드시!!!! 업데이트 해준다.

(레터박스 켜놓으면 뒷걸음질치다 쥐잡기는커녕 뇌진탕이 일어난다.)

public: // projection / mousepos 갱신은 무조건 필수임. 특히 register_screen_mouse_info 필수임!!!!!!!
    void UPDATE_PROJECTION(const dp::Vector2u& size) {
        final_draw_pass->resize(size);
    }
    void UPDATE_MOUSEPOS(const dp::Vector2f& pos) {
        final_draw_pass->register_screen_mouse_position_info(pos);
        //std::cout << final_draw_pass->get_world_space_mouse_position() << "\n";
    }