0314
2026년 3월 14일
레터박스의 구현

일단 고도엔진에 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는 그런 거 없고 그냥 생으로 주기 때문에,
특수화해서 만든 IFinalLetterboxDrawPass 의 register_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_size를resize()통해서 "실질적 크기" 로 저장해두기.
참고로 이 레터박싱 기능을 쓰기 위해
내가 고안한 조건들은 다음과 같다.
-
app에서 WindowDesc를 줄 때, desc.LetterboxEnabled 를 true로 해준다.
-
IFinalDrawPass 대신에, IFinalLetterboxDrawPass 를 그대로 쓰거나? 아니면 직접 만든다.
-
2D 카메라 업데이트와, fdp같이, 윈도우 크기에 관련된 건 전부!!! desc에 적었던 초깃값 상수로 계산한다 (window->get_initial_size()로 얻을 수 있다)
-
모든 UI (및 스크린 시스템) 만들 때 윈도우 크기가 상수라고 가정하고 배치한다.
-
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";
}