TL;DR

  • DOOM 엔진은 게임플레이 중 malloc() 없이 자체 메모리 할당기와 캐시 축출을 사용하고, 제한된 1993년 하드웨어에서의 성능을 위해 고정소수점 연산·룩업 테이블·직접 화면 버퍼·공간 인덱스를 채택한 구조임
  • z_zone.c의 메모리 할당기는 시작 시 확보한 하나의 큰 아레나를 블록으로 나누고, 새 메모리 할당 과정에서 재생성 가능한 캐시 블록을 자동 회수함
  • tables.c는 사인·탄젠트·아크탄젠트 값을 컴파일 시점에 미리 계산해 렌더러 전체에서 부동소수점 연산 없이 고정소수점 정수 연산을 수행하게 함
  • 화면은 320×200 크기의 1바이트 픽셀 배열이며, 3D 월드·HUD·몬스터·무기 스프라이트가 동일한 픽셀 블리팅 방식으로 그려짐
  • p_maputl.c의 블록맵은 충돌 검사를 인접한 지오메트리로 제한하는 자체 공간 인덱스이며, 모든 설계가 과도한 엔지니어링이 아니라 당시 하드웨어 제약에 대한 대응임

메모리 할당과 캐시 축출

  • 게임플레이 중 malloc()을 사용하지 않으며, id가 자체 메모리 할당기를 작성함.
  • 프로그램 시작 시 하나의 큰 메모리 아레나를 한 번 확보하고, 이를 중요도 태그가 붙은 블록으로 분할함.
  • PU_STATIC
  • PU_LEVEL
  • PU_CACHE
  • 새 메모리를 할당할 때 할당기가 지나가는 기존 캐시 블록을 조용히 축출할 수 있음.
  • free()를 호출하는 대신, 할당기가 캐시된 텍스처를 재생성 비용이 낮은 데이터로 판단해 즉시 공간을 회수함.
  • 캐시 축출 정책이 메모리 할당 경로 자체에 내장된 구조이며, 오늘날의 malloc()free()로는 동일한 동작을 수행할 수 없음.

부동소수점 없는 렌더링

  • 렌더러 어디에서도 부동소수점 연산을 사용하지 않음.
  • tables.c는 2,000줄이 넘는 파일이며, 엔진이 필요로 하는 사인·탄젠트·아크탄젠트 값을 거의 전부 담은 룩업 테이블로 구성됨.
  • 해당 값은 컴파일 시점에 미리 계산되며, 이동·각도·렌더링은 이 테이블을 이용한 고정소수점 정수 연산으로 처리됨.
  • 1993년의 모든 기기에 부동소수점 연산 장치(FPU)가 탑재된 것은 아니었고, FPU가 있는 경우에도 테이블 조회가 실시간 삼각함수 계산보다 빠름.

화면 버퍼와 UI의 부재

  • 전체 화면이 바이트 배열이며, UI는 별도의 시스템이 아니라 화면을 공유한 결과임.
  • screens[0]은 픽셀당 1바이트를 사용하는 평면형 320×200 버퍼임.
  • 3D 월드는 이 버퍼에 열 단위로 그려짐.
  • 이후 HUD가 몬스터 스프라이트와 무기 스프라이트를 그릴 때 사용하는 것과 정확히 같은 픽셀 블리팅 함수로 화면 위에 찍힘.
  • UI 툴킷이나 위젯 트리가 없으며, 게임이 디스플레이 전체를 직접 소유하므로 그 위에 별도 UI 계층을 구축할 기반 자체가 없음.
  • 체력 숫자와 악마 스프라이트가 동일한 종류의 그리기 호출로 처리됨.

블록맵 기반 충돌 검사

  • 충돌 감지는 별도로 직접 구현한 공간 인덱스를 사용함.
  • p_maputl.c는 맵을 블록맵이라는 격자로 나눔.
  • 피격 검사는 레벨의 모든 벽을 순회하지 않고 인접한 지오메트리만 확인함.
  • 이 구조는 널리 논의되기 전부터 자체적으로 구현한 공간 해시임.

하드웨어 제약에 맞춘 설계

  • 이러한 시스템은 과도한 엔지니어링이 아님.
  • 각 시스템은 표준적인 대안이 대상 하드웨어에 존재하지 않았거나 너무 느렸기 때문에 도입됨.
  • malloc
  • 부동소수점 연산
  • GUI 라이브러리
  • 무차별 대입 방식의 충돌 검사
  • Benzi를 통해 메모리에 의존해 추측하는 대신 코드베이스를 직접 읽으며 DOOM 엔진의 구조를 탐색함.