Как перевести vmf в bsp
Сохранение и компиляция


Карта должна быть компилирована в формат, который может прочесть игровой движок перед тем, как можно будет начать игру. Этот процесс включает в себя расчет видимости, так что на компьютере можно быстрее рассчитывать те части карты, которые нам необходимы в первую очередь, и рассчитать статический свет, исходящий от нашего светового энтити.
Сохранение
Компилирование
Вы сохранили карту в формат VMF, который представляет из себя текст. Чтобы загружать карту в игре, вам необходимо откомпилировать ее. Компиляция преобразовывает сырой VMF файл в бинарный BSP формат. В этом процессе обрабатывается геометрия карты, рассчитывается освещение и тени, за каждое действие отвечают программы компиляции: BSP, VIS и RAD.
Окно Compile Process будет показывать прогресс компиляции (вы можете остановить процесс, если он занимает слишком долгое время). Когда компилирование завершено, игра автоматически запуститься и загрузит вашу карту.
Поздравляем, вы сделали вашу первую карту!
Результат
Это скриншот сделанной карты, запущенной в Half-Life 2: Deathmatch. Здесь не на что смотреть, но теперь вы знаете необходимые основы, чтобы начать создавать вашу собственную карту.
Как перевести vmf в bsp
У вас есть готовый исходник карты, и вы хотите её скомпилировать минуя Hammer Editor.
Такое бывает, если Вам нужно просто срочно скомпилировать карту без запуска Hammer Editor. Кроме того, компиляция через исполняемый *.bat файл проходит немного быстрее, а окно, отображающее прогресс, никогда не зависнет.
В отличие от Hammer Editor — Кто компилировал большие не оптимизированные карты, тот знает, что одну из своих первых не оптимизированных карт я компилировал около 26 часов! Я даже запустил Windows в безопасном режиме, чтобы минимизировать трату ресурсов процессора.
Выбираем подходящую директорию, куда мы положим исходник карты и исполняемый *.bat файл. Например, ваш рабочий стол. Кладём в этом место исходник вашей карты (формат *.vmf) и создаём текстовый документ с любым именем. Открываем и пишем туда следующее:
Синтаксис исполняемого *.bat файла таков:
Самое главное, запомните: Путь до папки игры, это директория игры, в которой хранится файл gameinfo.txt — этот файл отвечает за информацию об игре.
Несколько примеров с директориями игр, где хранится файл gameinfo.txt
Для Half-Life 2 это Steam → SteamApps → common → Half-Life 2 → hl2
Для Garry’s Mod это Steam → SteamApps → common → Garry’s Mod → garrysmod
Для Synergy это Steam → SteamApps → common → Synergy → synergy
Для CS:GO это Steam → SteamApps → common → Counter-Strike Global Offensive → csgo
Для Team Fortress 2 это Steam → SteamApps → common → Team Fortress 2 → tf
Для Portal это Steam → SteamApps → common → Portal → portal
Для Source FilmMaker это Steam → SteamApps → common → SourceFilmmaker → game → usermod
Именно в этих ↑ папках находятся файлы gameinfo.txt для всех игр, как видите по разным папкам.
-fast — Быстрая компиляция для теста карты.
-low — Выполнять с низшим приоритетом.
-novconfig — При компиляции запретить показывать окна с сообщениями об ошибках.
-threads # — Число, оказывающее влияние на быстродействие компилятора.
-onlyents — VBPS будет компилировать только entity.
-onlyprops — Добавляет или обновляет только static и/или props.
-glview — Записывает информацию GLView в директории с VMF-файлом вашей карты.
-nodetail — Игнорирует все func_detail.
-nowater — Не компилирует воду.
-noweld — Не объединять вертексы вместе.
-nocsg — Не разбивавать пересекающиеся браши.
-noshare — Отбрасывавать уникальные рёбра, вместо замены их.
-notjunc — Не исправлять t-функцию.
-noprune — Не резать рядомстоящую мировую геометрию.
-nomerge — Не объединять разрезанные грани в узлы (ноды)..
-nomergewater — Не объединять разрезанные грани на воде
-nosubdiv Не разделять грани для лайтмапов.
-micro — VBPS предупреждает, когда браши компилятся с размером, меньше заданного ( по умолчанию 1.0).
-fulldetail Делает всю детальную геометрию мировой геометрией.
-bumpall — Делает на всех поверхностях эффект бампа.
-snapaxial — Выравнивает координаты до целых чисел.
-block # # — Контролирует минимальную величину размера сетки, которую может использовать VBSP.
-blocks # # # # — Вводит минимальную и максимальную величину размера сетки, которую может использовать VBSP.
-dumpstaticprops — Записывает prop_static в *.txt
-dumpcollide — Записывает файл с информации о столкновениях (коллизии).
-luxelscale # — Масштабирует все лайтмапы на это значение (по умолчанию 1.0).
-lightifmissing — Лайтмапы будут созданы для всех граней, даже если они им не нужны.
-keepstalezip — Оставляет нетронутым файлы BSP в zip, но обновляет всё остальное.
-replacematerials — Замещает материалы, использую данные из materialsub.txt в папке content\maps
-FullMinidumps — Записывает большой дамп при фатальной компиляции
-linuxdata Включает запись информации для многопользовательских серверво в Linux (но эта информация записывается автоматически, если находятся такие энтити, как info_player_terrorist, info_player_deathmatch, info_player_teamspawn, info_player_axis, или info_player_coop).
-nolinuxdata Выключает запись информации для многопользовательских серверво в Linux.
-virtualdispphysics Использует виртуальную модель коллизии (она не будет просчитана заранее) для дисплэсментов.
-xbox Включить оптимизацию для Xbox.
-radius_override — Устанавливает видимый радиус, прописанный в env_fog_controller.
-nosort — Не сортировать порталы (сортировака произовдится для оптимизации).
-tmpin — Читает порталы из карты \tmp\
-tmpout — Записывает порталы в \tmp\
-mpi — Использует VMPI для равномерного просчёта.
-mpi_pw — Использовать пароль для выбора настроек работы VMPI.
-ldr Компиляция только лайтмапов LDR.
-hdr — Компиляция только лайтмапов HDR.
-both — Компилирует лайтмапы сразу для Low Dynamic Range и High Dynamic Range (LDR и HDR) моделей освещения. Компилятор запуститься дважды.
-final — Увеличивает качество light_environment и других источников света.
-bounce — Установка уровня световых отражений. Увеличение этого параметра улучшает тени и темные участки. Почти не влияет на скорость компиляции. По умолчанию равно 10.
-smooth — Установить предел для сглаживания света (в градусах). По умолчанию VRAD использует отдельное для каждой поверхности освещение (Phong shading). С этим параметром применяется сглаживание освещения (Phong smoothing) на поверхностях, если угол между поверхностями меньше чем указанный. По умолчанию равен 45 градусам.
-luxeldensity — Уменьшает масшатб всех люкселей. По умолчания (и максимум) равен 1.
-softsun — Считать солнце, как источник мощного света \. Делает магкие тени. Рекоммендуемое значение между 0 и 5. По умолчанию 5.
-StaticPropLighting — Создаёт освещение на каждый вертекс для prop_static. light_spot делает это по умолчанию. При большом количестве prop_static размер карты очень сильно увеличивается.
-StaticPropPolys (Новое с выпуском Orange Box) — Выполнение испытание теней для каждого полигона prop_statics. Очень сильно нагружает процессор.
-mpi — Использует VMPI для равномерного просчёта.
-mpi_pw — Использовать пароль для выбора настроек работы VMPI.
-noextra — Запрещает суперсэмплинг.
-chop — Установить размер блока освещения (патча) для нормальных текстур. Увеличение размера патчей ведет к ускорению вычислений VRAD, но ухудшению качества освещения.
-maxchop — Устанавливает максимальный размер патчей. Смотреть предыдущий параметр.
-LargeDispSampleRadius — Этот параметр может использоваться, если освещене падает на землю. Компиляция занимает много времени, но зато будет выглядеть красиво.
-compressconstant — Сжимает лайтмапы, варииация цвета которой меньше, чем n ( ) юнитов.
-dumpnormals — Записывать нормали в файл дампа
-debugextra — Помещать отладочную информацию в лайтмапы для визуализирования суперсэмлинга.
-dlightmap — Превращает направленное освещение в разнонаправленные лайтпамы.
-stoponexit — Ждать нажатия кнопки для выхода.
-nodetaillight — Не освещать детали(detail)
-centersamples — Переместить сэмлы в центр.
-loghash — Записать хэш таблицы в samplehash.txt
-onlydetail — Освещать только датали (detail props) и полистовое освещение.
-maxdispsamplesize # — Установить максмальный размер сэмплов для дисплейсментов (умолчание 512).
-StaticPropNormals — При освещении статики, просто показывать его вектор нормали.
BSPSource
(September 16, 2017)
BSPSource is a Java-based graphical map decompiler for all Source games, up to Dota 2. It converts a compiled BSP into an editable VMF file for you to use in Hammer. It’s based off of the earlier, now obsolete, VMEX. To run it, run bspsrc.bat and drop BSPs into the box, then click «Decompile».

Decompiled map names have _d appended to differentiate them from the original. Decompiling maps with BSPSource may not always give you a perfect VMF. Some differences like keyvalues, materials, and other variables may occur. Some solids, instances, and areaportals may also be broken.

Actively maintained project
BSPSource is an actively maintained project. The latest version featured on this page is v1.4.0. If this is out-of-date, you can grab the newest version at ata4’s GitHub and contact us to update the link.
VDU’s guides are licensed under CC BY-SA 4.0. Content and design by mariteaux except where specified. Tools belong to their respective coders.
©2017-2020, some rights reserved. Long live the Union.
Как перевести vmf в bsp
Сначала внесу небольшую ясность, для чего я написал это руководство и почему всё-таки меня посетила эта идея? Начнём с того, что все вы знаете, что я использую Propper для создания своих моделей для Мастерской Garry’s Mod. И как то на днях меня посетила очень интересная мысль, конечно же я задался вопросом: А можно ли преобразовать файл модели *.mdl в исходный формат файла карты *.vmf, чтобы открыть его через редактор Hammer Editor и отредактировать под свои нужды?
Примерно неделю я искал методику преобразования, искал инфу, но нифига не находилось. И я решил ещё раз скачать и опробовать все программы, которые в наши дни создали для работы с Source движком, начал я, конечно же, с таких программ как BSP Source, Crowbar, EntSpy, Crafty, MDL Viewer и даже в программе Blender перекопал все функции, но нифига не нашёл.
Потом я вспомнил, что есть такая замечательная программа, как MilkShape 3D — Эта программа для работы с моделированием, для тех кто не знает. Скачав эту программу я понимал, что у программы очень большой функционал и решил опробовать её. До этого я ни разу не работал с MilkShape 3D и по этому, как и вы, в этой программе я до сих пор новичок.
Приложения, которые вам понадобятся для работы, это:
Crafty [game-rus.ucoz.ru] — Утилита для просмотров игровых файлов Source движка.
GCFScape [game-rus.ucoz.ru] — Утилита для распаковки *.vpk файлов в Source играх.
Ну и, конечно же, MilkShape 3D. Её вы сможете скачать с официального сайта: www.milkshape3d.com
Кликните по наименованиям программ и ссылке на официальный сайт, чтобы перейти и загрузить эти программы на ваш компьютер. Скачайте и установите эти программы, а мы едем дальше.
Для активации программы Milkshape 3D запустите программу и нажмите сверху: Help → About. Перед вами появится окошко о программе, в этом окошке нажмите кнопочку — Register и в появившемся окошке введите один из ключей ниже:
Name: Milkshape
Code: J2Bd1-TCdcZ3-T27d11d
Name: User
Code: dS40d-1Ed33d-36d27d2
Итак, для начала вам нужно взять какой-нибудь файл модели *.mdl — с помощью программ мы разберём файл модели, а затем преобразуем его в исходный формат файла карты, то есть *.vmf
В качестве тестовой модели мы будем использовать модель скорой помощи из Team Fortress 2. Эту модель вы сможете найти, если откроете файл tf2_misc_dir.vpk с помощью программы GFSCape, если что, файл лежит в директории Team Fortress 2 → tf → tf2_misc_dir.vpk
Извлеките файлы модели в любую удобную вам папку, вот как сделал я:
С помощью программы Crafty сейчас мы разберём эту модель и экспортируем в исходный формат модели файла *.obj
Запустите Crafty и откройте файл модели *.mdl через программу. При открытии вы увидите что-то вроде вот этого:
Не у всех пользователей одинаково открывается обозреватель моделей. У некоторых будет белое, как у меня на скриншоте, а у некоторых будет показана текстура модели. Вам нужно нажать File → Export или клавиши: Ctrl + E — Чтобы открыть экспортер файла модели в другой формат.
Введите название файла, и укажите формат *.obj для экспорта, как показано на картинке:
Теперь запускаем MilkShape 3D и нажимаем: File → Import → Wavefront OBJ…
И открываем наш *.obj файл.
Вот так в редакторе выглядит исходный файл модели:
Но наша задача не осматривать модель, а преобразовать её в исходник для Hammer Editor, по этом не расслабляемся и продолжаем преобразование.
Теперь нажимаем File → Import → Q3Radiant MAP…
После нажатия перед вами откроется вот такое окошко:
Это специальный экспортер, который позволяет преобразовывать всё что угодно в формат *.map — Этот формат используется в редакторе GoldSource Engine для старых GoldSource игр, проще говоря. Например CS 1.6 или Half-Life.
После сохранения в папке, через которую мы открывали модель в редакторе — появится *.map файл:
Теперь вновь запускаем Crafty и с помощью этой программы открываем наш сохранённый *.map файл. В моём случае я открою файл ambulance.map итак, что получилось у меня:
Теперь вновь нажимаем File → Export или Ctrl + E
Вводим название файла модели и указываем тип файла: *.vmf — Исходный формат файла карты Hammer Editor и сохраняем его.
И что мы видим? О чудо! У нас появился исходный файл карты *.vmf файл. Открываем его через Hammer Editor и смотрим, вот что получилось у меня:
Модель преобразована в браш, теперь вы можете делать с ней, что захотите. Обрезать, удалить, увеличить, удалить часть, скопировать часть. Экспериментируйте друзья!
Как вы видите, всё очень просто. Достаточно приложить небольшое усилие и желание — и только тогда у вас всё получится.
Структура файлового формата BSP (Source)
Эта статья основана на статье пользователя Rof «The Source Engine BSP File Format» от Октября 2005, взятой с сервиса Geocities перед тем как он был закрыт. Зеркало на оригинальную статью можно найти тут.
Contents
Введение
Этот документ описывает структуру файлового формата BSP используемого движком Source. Формат схож, но не идентичен фаловым форматам BSP используемых движком GoldSrc (Half-Life 1), которые в свою очередь основыны на файловых форматах используемых в Quake, Quake II и QuakeWorld, плюс к этому и в поздних версиях Quake III Arena. Поэтому статья пользователя Max McGuire, Quake 2 BSP File Format также является бесценной помощью в понимании общей структуры данного формата и его отдельных частей, которые остались в прежнем виде или схожи с их предшественниками.
Данный документ является расширением записок сделаных пользователем Rof во время написания своего декомпилятора файлов BSP для Half-Life 2, под названием VMEX. Поэтому основное внимание в этих записках уделяется тем частям формата, которые необходимы для декомпиляции карт (процесс преобразования BSP файла обратно в VMF файл, который может быть загружен в редактор карт Hammer).
Большая часть информации, которая содержится в данном документе, происходит из статьи пользователя Max McGuire (о которой упоминалось выше), из исходного кода включенного в Source SDK (в частности заголовочный файл C public/bspfile.h), и из собственных эксперементов пользователя Rof в то время как он писал свой декомпилятор карт, VMEX.
Беглый обзор
В файле формата BSP содержится подавляющее большинство информации, которая необходима движку Source для рендеринга и проигрывания карты. Эта информация включает в себя геометрию всех полигонов на уровне; ссылки на имена и ориентации текстур, которые нужно нанести на полигоны; данные используемые для симуляции физического поведения игрока и других объектов во время игры; расположение и свойства всех сущностей (объектов) на карте, таких как brush-based, model (prop) based и невидимые (логические) сущности; BSP дерево и таблицу видимости используемые для определения расположения игрока в контексте геометрии карты и для рендеринга видимой части карты настолько эффективно, насколько это возможно. Файлы карты также могут содержать в себе любые другие кастомные текстуры и модели использованные на уровне, встроенные внутри Pakfile lump карты (смотреть ниже).
Информация хранящаяся не в BSP файле, включает в себя описание карты отображаемое в многопользовательских играх (таких как Counter-Strike: Source или Half-Life 2: Deathmatch) после загрузки карты (хранится в файле под названием mapname.txt) и файл навигации ИИ используемый неигровыми персонажами (NPC), которым необходимо перемещаться по карте (хранится в файле mapname.nav). Благодаря тому как работает файловая система движка Source, эти внешние файлы также могут быть встроены в Pakfile lump BSP файла, однако зачастую это не используется.
Файлы оффициальных карт хранятся в Steam Game Cache File (GCF) формате, и доступны игровому движку через файловую систему Steam. Они могут быть извлечены из GCF файла для рассмотрения вне Steam с помощью утилиты, написаной пользователем Nemesis, GCFScape. В более новых играх, в которых используется формат файлов VPK, файлы карт зачастую хранятся прямо в файловой системе операционной системы.
Данные внутри BSP файлов могут хранится как в little-endian («остроконечный») формате для PC/Mac, так и в big-endian («тупоконечный») для PS3/X360. Смена порядка байтов (Byte-swapping) требуется когда загрузка little-endian файла выполняется на big-endian платформе, таких как Java и наоборот.
Заголовок BSP файла
Файл BSP начинатся с заголовка. Это структура содержащая несколько полей, сначала идет поле, которое идентифицирует файл как Valve Source Engine BSP файл, далее поле определяющее версию формата, затем следует поле содержащее информацию о списке директорий местоположения файла, длину и версию всех подсекций файла (в количестве 64-x штук), известных как lumps, в которых хранятся разные части данных карты. Наконец, в последнем поле структуры содержится информация о ревизии карты.
Структура заголовка приведена в заголовочном файле public/bspfile.h, который входит в состав SDK, ссылки на этот файл будут широко использоваться на протяжении всего документа. В общем длина заголовка составляет 1036 байт:

Где ident это 4-байтовое магическое число определенное как:
Таким образом первые 4 байта файла BSP это всегда VBSP (в ASCII коде). Эти байты идентифицируют файл как BSP файл; другие форматы файлов BSP используют другие магические числа (так, например, в играх на движке Quake от id Software, файлы BSP начинаются с числа IBSP ). BSP формат используемый движком GoldSrc и вовсе не использовал какие либо магические числа. Порядок в котором записано это магическое число также может быть использован для опрделения порядка следования байтов (endianness) в файле: VBSP используется для little-endian и PSBV для big-endian.
Второй integer (4-х байтовое число) это версия файлового формата BSP (BSPVERSION); для игр на движке Source, число находится в диапозоне от 19 до 21, за исключением VTMB (Vampire: The Masquerade – Bloodlines), которая использует более раннюю версию формата, 17 (смотреть таблицу ниже). Стоит отметить, что в файловых форматах BSP для других движков (HL1, Quake series, и т.д.) используются совершенно разные диапозоны номеров версий.
Версии
В этой таблице содержится информация о различных версиях BSP формата используемых в некоторых играх основаных на движке Source.
За большим количеством деталей относящимся к специфичным, для конкретных игр, форматам BSP, обращаться к Source BSP File Format/Game-Specific.
Структура Lump
Cтруктура lump_t определена в заголовочном файле файле bspfile.h:
Первые два integer’а содержат отступ в байтах (от начала BSP файла) и длину в байтах, которую имеет блок данных lump’а; далее integer определяющий номер версии формата данного lump’а (обычно нуль), и затем четырех байтовый идентификатор (массив из 4-х char, каждый из которых занимает 1 байт), который обычно равен < 0, 0, 0, 0 >. Для сжатых lump’ов, fourCC (последнее поле) содержит несжатый размер данных lump’а в форме integer’а form (детали смотреть в секции Сжатие Lump’ов ). У неиспользуемых членов массива lump_t (у которых нет даннх на которые бы они ссылались) все элементы (поля) установлены в нуль.
Сдвиги lump’ов (и им соответствующие данные) всегда округляются до ближайшей 4-байтовой границы, хотя lump и вовсе может не иметь длины.
Типы Lump
Тип данных, на которые указывает массив lump_t определяется его положением в массиве; например, первый lump в массиве (Lump 0) это всегда данные сущностей (entity) BSP файла (смотреть ниже). Фактическое местонахождение данных в BSP файле определяется сдвигом и длиной записи этого lump’а, и они не находятся в какои-либо кокретном порядке; например, данные сущности (entity data) обычно хранятся по направлению к концу BSP файла несмотря на то, что являются первыми в lump массиве. Таким образом, массив заголовков lump_t это директория где фактически находятся lump данные, которые могут быть расположены где-нибудь в другом месте внутри файла.
Порядок в lump массиве определен следующим образом:
Имейте в виду, что lump-ы 53-56 используются только в BSP файлах версии 20 и выше. Но lump-ы 22-25 не используются в BSP файлах версии 20.
И наконец, заголовки заканчиваются цельным числом (не десятичным) содержащее число ревизии карты. Это число основано на ревизии числа *.vmf файла карты ( mapversion ), который увеличивает каждый раз, когда карта сохраняется в Hammer editor.
Сжатый lump
BSP файлы для консольных платформ (таких как PlayStation 3 и Xbox 360) обычно имеют свои lump с LZMA. В таком случае, структура lump начинается со следующего заголовка (‘public/tier1/lzmaDecoder.h’):
Где id обозначается как:
Есть два специальных события для сжатия lump-ов: LUMP_PAKFILE никогда не сжимается и каждый игровой lump в LUMP_GAME_LUMP сжимается индивидуально. Размер сжатия игрового lump-а может быть определён вычитанием текущих игрового lump-го смещения с этим следующим записем. Именно по этой причине последний игровой lump является пустым, который хранит в себе только запись.
Lumps
Plane
The basis of the BSP geometry is defined by planes, which are used as splitting surfaces across the BSP tree structure.
The plane lump (Lump 1) is an array of dplane_t structures:
where the Vector type is a 3-vector defined as:
Floats are 4 bytes long; there are thus 20 bytes per plane, and the plane lump should be a multiple of 20 bytes long.
Mathematically, the plane is described by the set of points (x, y, z) which satisfy the equation:
There can be up to 65536 planes in a map (MAX_MAP_PLANES).
Vertex
The vertex lump (Lump 3) is an array of coordinates of all the vertices (corners) of brushes in the map geometry. Each vertex is a Vector of 3 floats (x, y, and z), giving 12 bytes per vertex.
Note that vertices can be shared between faces, if the vertices coincide exactly.
There are a maximum of 65536 vertices in a map (MAX_MAP_VERTS).
The edge lump (Lump 12) is an array of dedge_t structures:
Each edge is simply a pair of vertex indices (which index into the vertex lump array). The edge is defined as the straight line between the two vertices. Usually, the edge array is referenced through the Surfedge array (see below).
As for vertices, edges can be shared between adjacent faces. There is a limit of 256000 edges in a map (MAX_MAP_EDGES).
Surfedge
The Surfedge lump (Lump 13), presumable short for surface edge, is an array of (signed) integers. Surfedges are used to reference the edge array, in a somewhat complex way. The value in the surfedge array can be positive or negative. The absolute value of this number is an index into the edge array: if positive, it means the edge is defined from the first to the second vertex; if negative, from the second to the first vertex.
By this method, the Surfedge array allows edges to be referenced for a particular direction. (See the face lump entry below for more on why this is done).
There is a limit of 512000 (MAX_MAP_SURFEDGES) surfedges per map. Note that the number of surfedges is not necessarily the same as the number of edges in the map.
Face and original face
The face lump (Lump 7) contains the major geometry of the map, used by the game engine to render the viewpoint of the player. The face lump contains faces after they have undergone the BSP splitting process; they therefore do not directly correspond to the faces of brushes created in Hammer. Faces are always flat, convex polygons, though they can contain edges that are co-linear.
The face lump is one of the more complex structures of the map file. It is an array of dface_t entries, each 56 bytes long:
The first member planenum is the plane number, i.e., the index into the plane array that corresponds to the plane that is aligned with this face in the world. Side is zero if this plane faces in the same direction as the face (i.e. «out» of the face) or non-zero otherwise.
Firstedge is an index into the Surfedge array; this and the following numedges entries in the surfedge array define the edges of the face. As mentioned above, whether the value in the surfedge array is positive or negative indicates whether the corresponding pair of vertices listed in the Edge array should be traced from the first vertex to the second, or vice versa. The vertices which make up the face are thus referenced in clockwise order; when looking towards the face, each edge is traced in a clockwise direction. This makes rendering the faces easier, and allows quick culling of faces that face away from the viewpoint.
OrigFace is the index of the original face which was split to produce this face. NumPrims and firstPrimID are related to the drawing of «Non-polygonal primitives» (see below). The other members of the structure are used to reference face-lighting info (see the Lighting lump, below).
The face array is limited to 65536 (MAX_MAP_FACES) entries.
The original face lump (Lump 27) has the same structure as the face lump, but contains the array of faces before the BSP splitting process is done. These faces are therefore closer to the original brush faces present in the precompile map than the face array, and there are less of them. The origFace entry for all original faces is zero. The maximum size of the original face array is also 65536 entries.
Both the face and original face arrays are culled; that is, many faces present before compilation of the map (primarily those that face towards the «void» outside the map) are removed from the array.
Brush and brushside
The brush lump (Lump 18) contains all brushes that were present in the original VMF file before compiling. Unlike faces, brushes are constructive solid geometry (CSG) defined by planes instead of edges and vertices. It is the presence of the brush and brushside lumps in Source BSP files that makes decompiling them a much easier job than for GoldSrc files, which lacked this info. The lump is an array of 12-byte dbrush_t structures:
The first integer firstside is an index into the brushside array lump, this and the following numsides brushsides make up all the sides in this brush. The contents entry contains bitflags which determine the contents of this brush. The values are binary-ORed together, and are defined in the public/bspflags.h file:
| Name | Value | Notes |
|---|---|---|
| CONTENTS_EMPTY | 0 | No contents |
| CONTENTS_SOLID | 0x1 | an eye is never valid in a solid |
| CONTENTS_WINDOW | 0x2 | translucent, but not watery (glass) |
| CONTENTS_AUX | 0x4 | |
| CONTENTS_GRATE | 0x8 | alpha-tested «grate» textures. Bullets/sight pass through, but solids don’t |
| CONTENTS_SLIME | 0x10 | |
| CONTENTS_WATER | 0x20 | |
| CONTENTS_MIST | 0x40 | |
| CONTENTS_OPAQUE | 0x80 | block AI line of sight |
| CONTENTS_TESTFOGVOLUME | 0x100 | things that cannot be seen through (may be non-solid though) |
| CONTENTS_UNUSED | 0x200 | unused |
| CONTENTS_UNUSED6 | 0x400 | unused |
| CONTENTS_TEAM1 | 0x800 | per team contents used to differentiate collisions between players and objects on different teams |
| CONTENTS_TEAM2 | 0x1000 | |
| CONTENTS_IGNORE_NODRAW_OPAQUE | 0x2000 | ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW |
| CONTENTS_MOVEABLE | 0x4000 | hits entities which are MOVETYPE_PUSH (doors, plats, etc.) |
| CONTENTS_AREAPORTAL | 0x8000 | remaining contents are non-visible, and don’t eat brushes |
| CONTENTS_PLAYERCLIP | 0x10000 | |
| CONTENTS_MONSTERCLIP | 0x20000 | |
| CONTENTS_CURRENT_0 | 0x40000 | currents can be added to any other contents, and may be mixed |
| CONTENTS_CURRENT_90 | 0x80000 | |
| CONTENTS_CURRENT_180 | 0x100000 | |
| CONTENTS_CURRENT_270 | 0x200000 | |
| CONTENTS_CURRENT_UP | 0x400000 | |
| CONTENTS_CURRENT_DOWN | 0x800000 | |
| CONTENTS_ORIGIN | 0x1000000 | removed before bsping an entity |
| CONTENTS_MONSTER | 0x2000000 | should never be on a brush, only in game |
| CONTENTS_DEBRIS | 0x4000000 | |
| CONTENTS_DETAIL | 0x8000000 | brushes to be added after vis leafs |
| CONTENTS_TRANSLUCENT | 0x10000000 | auto set if any surface has trans |
| CONTENTS_LADDER | 0x20000000 | |
| CONTENTS_HITBOX | 0x40000000 | use accurate hitboxes on trace |
Some of these flags seem to be inherited from previous game engines and are not used in Source maps. They are also used to describe to contents of the map’s leaves (see below). The CONTENTS_DETAIL flag is used to mark brushes that were in func_detail entities before compiling.
The brush array is limited to 8192 entries (MAX_MAP_BRUSHES).
The brushside lump (Lump 19) is an array of 8-byte structures:
Planenum is an index info the plane array, giving the plane corresponding to this brushside. Texinfo and dispinfo are references into the texture and displacement info lumps. Bevel is zero for normal brush sides, but 1 if the side is a bevel plane (which seem to be used for collision detection).
Unlike the face array, brushsides are not culled (removed) where they touch the void. Void-facing sides do however have their texinfo entry changed to the tools/toolsnodraw texture during the compile process. Note there is no direct way of linking brushes and brushsides and the corresponding face array entries which are used to render that brush. Brushsides are used by the engine to calculate all player physics collision with world brushes. (Vphysics objects use lump 29 instead.)
The maximum number of brushsides is 65536 (MAX_MAP_BRUSHSIDES). The maximum number of brushsides on a single brush is 128 (MAX_BRUSH_SIDES).
Node and leaf
The node array (Lump 5) and leaf array (Lump 10) define the Binary Space Partition (BSP) tree structure of the map. The BSP tree is used by the engine to quickly determine the location of the player’s viewpoint with respect to the map geometry, and along with the visibility information (see below), to decide which parts of the map are to be drawn.
The nodes and leaves form a tree structure. Each leaf represents a defined volume of the map, and each node represents the volume which is the sum of all its child nodes and leaves further down the tree.
Each node has exactly two children, which can be either another node or a leaf. A child node has two further children, and so on until all branches of the tree are terminated with leaves, which have no children. Each node also references a plane in the plane array. When determining the player’s viewpoint, the engine is trying to find which leaf the viewpoint falls inside. It first compares the coordinates of the point with the plane referenced in the headnode (Node 0). If the point is in front of the plane, it then moves to the first child of the node; otherwise, it moves to the second child. If the child is a leaf, then it has completed its task. If it is another node, it then performs the same check against the plane referenced in this node, and follows the children as before. It therefore traverses the BSP tree until it finds which leaf the viewpoint lies in. The leaves, then, completely divide up the map volume into a set of non-overlapping, convex volumes defined by the planes of their parent nodes.
For more information on how the BSP tree is constructed, see the article «BSP for dummies».
The node array consists of 32-byte structures:
The members mins[] and maxs[] are coordinates of a rough bounding box surrounding the contents of this node. The firstface and numfaces are indices into the face array that show which map faces are contained in this node, or zero if none are. The area value is the map area of this node (see below). There can be a maximum of 65536 nodes in a map (MAX_MAP_NODES).
The leaf array is an array with 56 bytes per element:
The leaf structure has similar contents to the node structure, except it has no children and no reference plane. Additional entries are the contents flags (see the brush lump, above), which shows the contents of any brushes in the leaf, and the cluster number of the leaf (see below). The area and flags members share a 16-bit bitfield and contain the area number and flags relating to the leaf. Firstleafface and numleaffaces index into the leafface array and show which faces are inside this leaf, if any. Firstleafbrush and numleafbrushes likewise index brushes inside this leaf through the leafbrush array.
The ambientLighting element is related to lighting of objects in the leaf, and consists of a CompressedLightCube structure, which is 24 bytes in length. Version 17 BSP files have a modified dleaf_t structure that omits the ambient lighting data, making the entry for each leaf only 32 bytes in length. The same shortened structure is also used for version 20 BSP files, with the ambient lighting information for LDR and HDR probably contained in the new lumps 55 and 56.
All leaves are convex polyhedra, and are defined by the planes of their parent nodes. They do not overlap. Any point in the coordinate space is in one and only one leaf of the map. A leaf which is not filled with a solid brush and can be entered by the player in the usual course of the game has a cluster number set; this is used in conjunction with the visibility information (below).
There are usually multiple, unconnected BSP trees in a map. Each one corresponds to an entry in model array (see below) and the headnode of each tree is referenced there. The first tree is the worldspawn model, the overall geometry of the level. Successive trees are the models of each brush entity in the map.
The creation of the BSP tree is done by the VBSP program, during the first phase of map compilation. Exactly how the tree is created, and how the map is divided into leaves, can be influenced by the map author by the use of HINT brushes, func_details, and the careful layout of all brushes in the map.
LeafFace and LeafBrush
The leafface lump (Lump 16) is an array of unsigned shorts which are used to map from faces referenced in the leaf structure to indices in the face array. The leafbrush lump (also an array of unsigned shorts)(Lump 17) does the same thing for brushes referenced in leaves. Their maximum sizes are both 65536 entries (MAX_MAP_LEAFFACES, MAX_MAP_LEAFBRUSHES).
Textures
The texture information in a map is split across a number of different lumps. The Texinfo lump is the most fundamental, referenced by the face and brushside arrays, and it in turn references the other texture lumps.
Texinfo
The texinfo lump (Lump 6) contains an array of texinfo_t structures:
Each texinfo is 72 bytes long.
The first array of floats is in essence two vectors that represent how the texture is orientated and scaled when rendered on the world geometry. The two vectors, s and t, are the mapping of the left-to-right and down-to-up directions in the texture pixel coordinate space, onto the world. Each vector has an x, y, and z component, plus an offset which is the «shift» of the texture in that direction relative to the world. The length of the vectors represent the scaling of the texture in each direction.
The 2D coordinates (u, v) of a texture pixel (or texel) are mapped to the world coordinates (x, y, z) of a point on a face by:
Furthermore, after calculating (u, v), to convert them to texture coordinates which you would send to your graphics card, divide u and v by the width and height of the texture respectively.
The lightmapVecs float array performs a similar mapping of the lightmap samples of the texture onto the world.
The flags entry contains bitflags which are defined in bspflags.h:
| Name | Value | Notes |
|---|---|---|
| SURF_LIGHT | 0x1 | value will hold the light strength |
| SURF_SKY2D | 0x2 | don’t draw, indicates we should skylight + draw 2d sky but not draw the 3D skybox |
| SURF_SKY | 0x4 | don’t draw, but add to skybox |
| SURF_WARP | 0x8 | turbulent water warp |
| SURF_TRANS | 0x10 | |
| SURF_NOPORTAL | 0x20 | the surface can not have a portal placed on it |
| SURF_TRIGGER | 0x40 | FIXME: This is an xbox hack to work around elimination of trigger surfaces, which breaks occluders |
| SURF_NODRAW | 0x80 | don’t bother referencing the texture |
| SURF_HINT | 0x100 | make a primary bsp splitter |
| SURF_SKIP | 0x200 | completely ignore, allowing non-closed brushes |
| SURF_NOLIGHT | 0x400 | Don’t calculate light |
| SURF_BUMPLIGHT | 0x800 | calculate three lightmaps for the surface for bumpmapping |
| SURF_NOSHADOWS | 0x1000 | Don’t receive shadows |
| SURF_NODECALS | 0x2000 | Don’t receive decals |
| SURF_NOCHOP | 0x4000 | Don’t subdivide patches on this surface |
| SURF_HITBOX | 0x8000 | surface is part of a hitbox |
Texdata
Finally the texdata entry is an index into the Texdata array, and specifies the actual texture.
The texdata array (Lump 2) consists of the structures:
TexdataStringData and TexdataStringTable
The TexdataStringTable (Lump 44) is an array of integers which are offsets into the TexdataStringData (lump 43). The TexdataStringData lump consists of concatenated null-terminated strings giving the texture name.
There can be a maximum of 12288 texinfos in a map (MAX_MAP_TEXINFO). There is a limit of 2048 texdatas in the array (MAX_MAP_TEXDATA) and up to 256000 bytes in the TexdataStringData data block (MAX_MAP_TEXDATA_STRING_DATA). Texture name strings are limited to 128 characters (TEXTURE_NAME_LENGTH).
Model
A Model, in the terminology of the BSP file format, is a collection of brushes and faces, often called a «bmodel». It should not be confused with the prop models used in Hammer, which are usually called «studiomodels» in the SDK source.
The model lump (Lump 14) consists of an array of 24-byte dmodel_t structures:
Mins and maxs are the bounding points of the model. Origin is the coordinates of the model in the world, if set. Headnode is the index of the top node in the node array of the BSP tree which describes this model. Firstface and numfaces index into the face array and give the faces which make up this model.
The first model in the array (Model 0) is always «worldspawn», the overall geometry of the whole map excluding entities (but including func_detail brushes). The subsequent models in the array are associated with brush entities, and referenced from the entity lump.
There is a limit of 1024 models in a map (MAX_MAP_MODELS), including the worldspawn model zero.
Visibility
The visibility lump (Lump 4) is in a somewhat different format to the previously mentioned lumps. To understand it, some discussion of how the Source engine’s visibility system works in necessary.
As mentioned in the Node and leaf lumps section above, every point in the map falls into exactly one convex volume called a leaf. All leaves that are on the inside of the map (not touching the void), and that are not covered by a solid brush can potentially have the player’s viewpoint inside it during normal gameplay. Each of these enterable leaves (also called visleaves) gets assigned a cluster number. In Source BSP files, each enterable leaf corresponds to just one cluster.
Each cluster, then, is a volume in the map that the player can potentially be in. To render the map quickly, the game engine draws the geometry of only those clusters which are visible from the current cluster. Clusters which are completely occluded from view from the player’s cluster need not be drawn. Calculating cluster-to-cluster visibility is the responsibility of the VVIS compile tool, and the resulting data is stored in the Visibility lump.
Once the engine knows a cluster is visible, the leaf data references all faces present in that cluster, allowing the contents of the cluster to be rendered.
The data is stored as an array of bit-vectors; for each cluster, a list of which other clusters are visible from it are stored as individual bits (1 if visible, 0 if occluded) in an array, with the nth bit position corresponding to the nth cluster. This is known as the cluster’s Potentially Visible Set (PVS). Because of the large size of this data, the bit vectors are compressed by run-length encoding groups of zero bits in each vector.
There is also a Potentially Audible Set (PAS) array created for each cluster; this marks which clusters can hear sounds occurring in other clusters. The PAS seems to be created by merging the PVS bits of all clusters in current cluster’s PVS.
The Visibilty lump is defined as:
The first integer is the number of clusters in the map. It is followed by an array of integers giving the byte offset from the start of the lump to the start of the PVS bit array for each cluster, followed by the offset to the PAS array. Immediately following the array are the compressed bit vectors.
The decoding of the run-length compression works as follows: To find the PVS of a given cluster, start at the byte given by the offset in the byteofs[] array. If the current byte in the PVS buffer is zero, the following byte multiplied by 8 is the number of clusters to skip that are not visible. If the current byte is non-zero, the bits that are set correspond to clusters that are visible from this cluster. Continue until the number of clusters in the map is reached.
Example C code to decompress the bit vectors can be found in the «Quake 2 BSP File Format» document.
The maximum size of the Visibility lump is 0x1000000 bytes (MAX_MAP_VISIBILITY); that is, 16 Mb.
Entity
The entity lump (Lump 0) is an ASCII text buffer which stores the entity data in a format very similar to the KeyValue format of uncompiled VMF files. Its general form is:
Entities are defined between opening and closing braces ( < and >) and list on each line a pair of key/value properties inside quotation marks. The first entity is always worldspawn. The classname property gives the entity type, and the targetname property gives the entity’s name as defined in Hammer (if it has one). The model property is slightly special if it starts with an asterisk (*), the following number is an index into the model array (see above) which corresponds to a brush entity ‘model’. Otherwise, the value contains the name of a compiled model. Other key/value pairs correspond to the properties of the entity as set in Hammer.
Depending on the Source engine version, the entity lump can contain 4096 (Source 2004) to 16384 (Alien Swarm) entities ( MAX_MAP_ENTITIES ). These limits are independent from the engine’s actual entity limit. Each key can be a maximum of 32 characters ( MAX_KEY ) and the value up to 1024 characters ( MAX_VALUE ).
Game lump
The Game lump (Lump 35) seems to be intended to be used for map data that is specific to a particular game using the Source engine, so that the file format can be extended without altering the previously defined format. It starts with a game lump header:
where the gamelump directory array is defined by:
Static props
Of interest is the gamelump which is used to store prop_static entities, which uses the gamelump ID of ‘sprp’ ASCII (1936749168 decimal). Unlike most other entities, static props are not stored in the entity lump. The gamelump formats used in Source are defined in the public/gamebspfile.h header file.
The first element of the static prop game lump is the dictionary; this is an integer count followed by the list of model (prop) names used in the map:
Each name entry is 128 characters long, null-padded to this length.
Following the dictionary is the leaf array:
Presumably, this array is used to index into the leaf lump to locate the leaves that each prop static is located in. Note that a prop static may span several leaves.
Next, an integer giving the number of StaticPropLump_t entries, followed by that many structures themselves:
Other
Other gamelumps used in Source BSP files are the detail prop gamelump ( dprp ), and the detail prop lighting lump ( dplt for LDR and dplh for HDR). These are used for prop_detail entities (grass tufts, etc.) automatically emitted by certain textures when placed on displacement surfaces.
There does not seem to be a specified limit on the size of the game lump.
Displacements
Displacement surfaces are the most complex parts of a BSP file, and only part of their format is covered here. Their data is split over a number of different data lumps in the file, but the fundamental reference to them is through the dispinfo lump (Lump 26). Dispinfos are referenced from the face, original face, and brushside arrays.
DispInfo
DispVerts
The DispVerts lump (Lump 33) contains the vertex data of the displacements. It is given by:
where vec is the normalized vector of the offset of each displacement vertex from its original (flat) position; dist is the distance the offset has taken place; and alpha is the alpha-blending of the texture at that vertex.
A displacement of power p references (2^p 1)^2 dispverts in the array, starting from the DispVertStart index.
DispTris
The DispTris lump (Lump 48) contains «triangle tags» or flags related to the properties of a particular triangle in the displacement mesh:
where the flags are:
| Name | Value |
|---|---|
| DISPTRI_TAG_SURFACE | 0x1 |
| DISPTRI_TAG_WALKABLE | 0x2 |
| DISPTRI_TAG_BUILDABLE | 0x4 |
| DISPTRI_FLAG_SURFPROP1 | 0x8 |
| DISPTRI_FLAG_SURFPROP2 | 0x10 |
There are 2x(2^p)^2 DispTri entries for a displacement of power p. They are presumably used to indicate properties for each triangle of the displacement such as whether the surface is walkable at that point (not too steep to climb).
There are a limit of 2048 Dispinfos per map, and the limits of DispVerts and DispTris are such that all 2048 displacements could be of power 4 (maximally subdivided).
Other displacement-related data are the DispLightmapAlphas (Lump 32) and DispLightmapSamplePos (Lump 34) lumps, which seem to relate to lighting of each displacement surface.
Pakfile
The Pakfile lump (Lump 40) is a special lump that can contains multiple files which are embedded into the bsp file. Usually, they contain special texture (.vtf) and material (.vmt) files which are used to store the reflection maps from env_cubemap entities in the map; these files are built and placed in the Pakfile lump when the buildcubemaps console command is executed. The Pakfile can optionally contain such things as custom textures and prop models used in the map, and are placed into the bsp file by using the BSPZIP program (or alternate programs such as Pakrat). These files are integrated into the game engine’s file system and will be loaded preferentially before externally located files are used.
The format of the Pakfile lump is identical to that used by the Zip compression utility when no compression is specified (i.e., the individual files are stored in uncompressed format). If the Pakfile lump is extracted and written to a file, it can therefore be opened with WinZip and similar programs.
The header public/zip_uncompressed.h defines the structures present in the Pakfile lump. The last element in the lump is a ZIP_EndOfCentralDirRecord structure. This points to an array of ZIP_FileHeader structures immediately preceeding it, one for each file present in the Pak. Each of these headers then point to ZIP_LocalFileHeader structures that are followed by that file’s data.
The Pakfile lump is usually the last element of the bsp file.
Cubemap
The Cubemap lump (Lump 42) is an array of 16-byte dcubemapsample_t structures:
The dcubemapsample_t structure defines the location of a env_cubemap entity in the map. The origin member contains integer x,y,z coordinates of the cubemap, and the size member is resolution of the cubemap, specified as 2^(size-1) pixels square. If set as 0, the default size of 6 (32×32 pixels) is used. There can be a maximum of 1024 (MAX_MAP_CUBEMAPSAMPLES) cubemaps in a file.
Version 20 files contain extra cX_Y_Z.hdr.vtf files in the Pakfile lump, containing HDR texture files in RGBA16161616F (16-bit per channel) format.
Overlay
Unlike the simpler decals (infodecal entities), info_overlays are removed from the entity lump and stored separately in the Overlay lump (Lump 45). The structure is reflects the properties of the entity in Hammer almost exactly:
The FaceCountAndRenderOrder member is split into two parts; the lower 14 bits are the number of faces that the overlay appears on, with the top 2 bits being the render order of the overlay (for overlapping decals). The Ofaces array, which is 64 elements in size (OVERLAY_BSP_FACE_COUNT) are the indices into the face array indicating which map faces the overlay should be displayed on. The other elements set the texture, scale, and orientation of the overlay decal. There can be a maximum of 512 overlays per file (MAX_MAP_OVERLAYS). In Dota 2 this limit on the number of overlays is increased significantly.
Lighting
The lighting lump (Lump 8) is used to store the static lightmap samples of map faces. Each lightmap sample is a colour tint that multiplies the colours of the underlying texture pixels, to produce lighting of varying intensity. These lightmaps are created during the VRAD phase of map compilation and are referenced from the dface_t structure. The current lighting lump version is 1.
Each dface_t may have a up to four lightstyles defined in its styles[] array (which contains 255 to represent no lightstyle). The number of luxels in each direction of the face is given by the two LightmapTextureSizeInLuxels[] members (plus 1), and the total number of luxels per face is thus:
(LightmapTextureSizeInLuxels[0] + 1) * (LightmapTextureSizeInLuxels[1] + 1)
Standard RGB format can be obtained from this by multiplying each colour component by 2^(exponent). For faces with bumpmapped textures, there are four times the usual number of lightmap samples, presumably containing samples used to compute the bumpmapping.
Version 20 BSP files contain a second, identically sized lighting lump (Lump 53). This is presumed to store more accurate (higher-precision) HDR data for each lightmap sample. The format is currently unknown, but is also 32 bits per sample.
The maximum size of the lighting lump is 0x1000000 bytes, i.e. 16 Mb (MAX_MAP_LIGHTING).
Occlusion
The occlusion lump (Lump 9) contains the polygon geometry and some flags used by func_occluder entities. Unlike other brush entities, func_occluders don’t use the ‘model’ key in the entity lump. Instead, the brushes are split from the entities during the compile process and numeric occluder keys are assigned as ‘occludernum’. Brush sides textured with tools/toolsoccluder or tools/toolstrigger are then stored together with the occluder keys and some additional info in this lump.
The lump is divided into three parts and begins with a integer value with the total number of occluders, followed by an array of doccluderdata_t fields of the same size. The next part begins with another integer value, this time for the total number of occluder polygons, as well as an array of doccluderpolydata_t fields of equal size. Part three begins with another integer value for the amount of occluder polygon vertices, followed by an array of integer values for the vertex indices, again of the same size.
The doccluderdata_t structure contains flags and dimensions of the occluder, as well as the area where it remains. firstpoly is the first index into the doccluderpolydata_t with a total of polycount entries.
Other
To do: Some of these information are likely guesses and need further research.






