0326 게임엔진프로젝트
(중요) 게임엔진프로젝트
* 현실 메모장에 있던 거 옮긴 거임
파이프라인 > 상태설정 + 렌더패스 > 버퍼 바인딩 + 상태설정 + 드로우 콜
다음은 유일한 엔진과 그 밑에 달리는 앱들에 대한 구조이다.
앱들을 여러개 달 수 있게 하려는 이유는,
전에 게임엔진디자인.txt라는 글에서도 썼다시피
게임 엔진이라고 부를 수...는 없는 "코어" 가 있고, (이는 라이브러리 형태이다)
에디터와 런타임이 코어를 공유하는데,
코어 하나에서 앱이 2개 돌아가는데
첫번째 앱이 에디터이고
두번째 앱이 런타임디버그인거다.
근데 엔진을 실행했을 때 보이는 건 에디터이다.
당연히도 런타임디버그는 윈도우를 보여주기 전이기에.
여기에 대해서 생각하놓은 것은
1. 에디터가 런타임디버그에게 특정 행동을 요청하는 경우
- 런타임 윈도우 켜주세요 / 꺼주세요
- 핫리로드 해주세요
- 스크립트에 중단점이 걸렸어요 잠시만 중단해주세요
2. 런타임디버그가 에디터에게 특정 행동을 요청하는 경우
- "나 이제 곧 꺼집니다, 에디터 모드로 진입하세요"
- 메세지 로그를 띄워 주세요
에디터에서 런타임디버그를 실행하고 있는 중에서
이러한 일련의 과정들이 "스레드-세이프 통신 큐"에서 일어나게 되는 거다.
(참고로 멀티스레딩을 쓸지 안쓸지는 런타임에 Cfg로 받는다.)
에디터가 "에디터_전용_큐" 에다가 요청(Produce)하면
런타임디버그는 그걸 보고 지운(Consume) 다음 해당 액션을 실행
런타임디버그가 "런타임디버그_전용_큐" 에다가 요청(Produce)하면
에디터는 그걸 보고 지운(Consume) 다음 액션을 실행.
물론, 전용 큐는 Engine 안에 기본적으로 존재한다.
Engine을 인터페이스로 만들지 말지는 아직도 잘 모르겠다.
그냥 싱글톤 하나에다가 각 앱 전용 통신 큐를 만들어놓을까.....
Engine (오직 1개)
// 추상화된 서브시스템들.
- IRenderer* renderer{Type::GL3}
// VertexBuffer, FrameBuffer를 추상화해서 제공한다.
// 단, 현재 GL컨텍스트가 무엇인지는 신경쓰지 않는다.
// 렌더러에게 요청 날리기 전에 현재 GL컨텍스트 확인하는 건
// 렌더서버가 할 일이다.
- IAudioEngine* audioEngine{Type::FMOD}
- IPhysicsEngine* physicsEngine{Type::Box2D}
- vec<App*> apps
App (여러개일 수 있음)
- IWindow* window;
// 모든 서버에 App을 소유한 Engine의 서브시스템을 주입한다.
// 참고로 렌더서버는 DI로써 window가 추가적으로 필요하다.
- RenderServer* renderServer { window, renderer };
// App 소유의 객체들에게 VAO등을 "아이디로" 발급해준다.
// 또는 자주 쓰일 법한 VAO & Program은 미리 만들어 캐싱한다.
// (물론, GL의 경우 내부 GLuint 핸들은 모든 App이 공유한다.)
// 렌더러가 컨텍스트에 맞는 추상화된 핸들을 생성해준다면,
// 렌더서버의 주요 목적은, 렌더러가 생성해준 객체를 사용자에게
// 가볍게 제공하고, "그걸 가지고 쉽게 파이프라인구성/렌더패스구성/렌더링 할 수 있게 하는 것이다."
// 렌더서버는 RenderPass와 Attachment라는 추상 클래스를 제공하며,
// C++의 체이닝과 단일-링크드-리스트 형태를 통해서
// 패스들의 조합을 구성할 수 있다.
// 물론, 다음 렌더페스가 없다면 종료하고, 원한다면 기본 프레임버퍼에 그릴 수 있도록.
struct RenderPass {
std::unordered_map<AttachmentType, AttachmentDesc> ???
위에거는 그냥 대충 이 패스의 출력물이 다음 패스에 어떻게 연결될 건지를 설명함
RenderPass* nextPass = nullptr;
}
// 패스에는 "출력되는첨부물"과 "그 첨부의 데이터타입, 이미지크기 등"을 설정할 수 있게 해야 한다.
// 렌더 패스의 구성은 조금 더 생각을 해 봐야 할 것 같다.
// 특이하게 6방향으로 찍으면서 타겟을 바꿔가는 경우(환경매핑 / 포인트셰도우매핑) 도 있으니까.
// (이럴 경우에는 SetAttachmentTarget(Type::Color0, 자신의_해당_타겟) 이런 식으로 바꿔가면서 렌더링하면 될 듯 하다.)
// 렌더패스의 구성
// FBO (필수)
// RBO (선택)
// 뎁스인가? 스텐실인가? 뎁스스텐실인가?
// Tex0 ...
// 첨부타입은? 크기는? 내부/외부포맷은? 필터는? 래핑은?
//
// 렌더링의 경우에는,
// DrawTexture(tex_id id, vec2 size, Matrix4 world, Matrix4 view, Matrix4 proj)
// DrawGlyph(wchar_t wc, Matrix4 world, Matrix4 view, Matrix4 proj)
// DrawCircle(float radius, Matrix4 world, Matrix4 view, Matrix4 proj)
// DrawCube(float extent, Matrix4 world, Matrix4 view, Matrix4 proj);
// DrawTexCube(tex_id id, float extent, Matrix4 world, Matrix4 view, Matrix4 proj);
//
// 이런 식으로, "렌더 서버가 제공한 아이디"를 사용해서 렌더링할 수 있게 해준다.
// (물론 저기에 Cube같은 경우 렌더서버 내부에서 이미 생성해 놓은 메시이다)
// 또한 각각의 드로우 콜에 종속되는 (GL의 경우 글로벌 스테이트인) 설정들에 대해서는,
// 여러 렌더패스 사이에서 바뀔 수도 있고,
// 각 드로우 콜 사이에서 바뀌어야 할 수도 있기 때문에,
//
// 전자의 경우 -> 렌더페스와 렌더페스(링크드 리스트) 사이에 들어갈 수 있는 클래스를 만들어서
// 렌더페스와 그 클래스를 하나로 볼 수 있는 추상 클래스를 또 하나 만든다?
// 예를 들면, StatePass라던가. ConfigPass라던가..
// **** 근데 중요한 건 이 클래스 내부에서도 후자와 다를 게 없음 *****
// 후자의 경우 -> 그냥 렌더 서버에 함수로 요청하자.
- AudioServer* audioServer { audioEngine };
- PhysicsServer* physicsServer{ physicsEngine };
// ************ 중요 **********************
// OpenGL기준으로, 렌더 서버가 무언가를
// 생성, 바인드, 그리기 전에 참조하고 있는
// 윈도우 컨텍스트를 Current로 만든다.
// ****************************************