RSC — различия между версиями

Материал из GTAModding.ru
Перейти к: навигация, поиск
 
(не показаны 17 промежуточных версий 3 участников)
Строка 1: Строка 1:
 +
==Формат==
 +
 
Ресурсные файлы GTA IV имеют следующий формат:
 
Ресурсные файлы GTA IV имеют следующий формат:
  
Строка 6: Строка 8:
 
  4 байта - Флаги
 
  4 байта - Флаги
  
Далее следует сами данные ресурса в запакованном формате.
+
Далее следует сами данные ресурса в запакованном формате. ПК-версия игры использует в качестве алгоритма упаковки - Zlib.
  
ПК-версия игры использует в качестве алгоритма упаковки - Zlib.
+
Ресурс содержит два блока памяти - System Memory Segment (CPU) и Graphics Memory Segment (GPU). Размер каждого блока кратен 256. В одном из них хранится сам объект, в другом - используемые данные Direct3D (тексельные, вертексные или индексные буфера).  
  
Распакованный ресурс можно разделить на две части - System Memory Segment и Graphics Memory Segment, размером, кратным 256 каждая.
+
Каждый ресурс содержит один (и только один) объект, со всеми включенными в него подобъектами. (Например, файл с расширением <code>.[[WTD]]</code> содержит в себе объект <code>rage::pgDictionary</code>. При этом, в файле сохраняется не только сама коллекция, но и все включенные в нее объекты текстур, используемые ими хэши, имена и, конечно, пиксельные данные). Все указатели заменяются на смещения в файле. При чтении, смещения заменяются обратно на указатели в памяти.
  
Их конкретные размеры "зашиты" в параметре "флаги" и могут быть вычислены с помощью данного алгоритма:
+
Любой указатель (число вида 0x5xxxxxxx или 0x6xxxxxxx) преобразуется в 32-битное число. Четыре старших бита в нем - код блока (5 - CPU блок, 6 - GPU блок), младшие 28 - смещение в блоке (для GPU блока возможны случаи, когда структура выравнивается на размер страницы, т.е. младшие 12 бит заменяются нулями, а содержавшееся в них значение используется, например, как идентификатор формата данных).
 +
 
 +
Таким образом преобразовать любой указатель в значение оффсета можно простой операцией (пример на '''Delphi''' и '''C++'''):
 +
 
 +
<source lang="Delphi">if (Ptr shr 28 = 5) or (Ptr shr 28 = 6) then Offset:=Ptr and $0FFFFFFF;</source>
 +
 
 +
<source lang="cpp">if ((Ptr >> 28 == 5) | (Ptr >> 28 == 6)) Offset = Ptr & 0x0FFFFFFF;</source>
 +
 
 +
 
 +
Размеры блоков хранятся в RSC-заголовке (параметр "флаги), их можно вычислить следующим образом (пример на '''Delphi''' и '''C++'''):
  
 
<source lang="delphi" line>
 
<source lang="delphi" line>
{Flags - переменная, содержащее соответственное значение} 
 
 
  CPUSize:= (Flags AND $7FF) shl (((Flags shr 11) AND $F) + 8); //расчет размера System Memory Segment
 
  CPUSize:= (Flags AND $7FF) shl (((Flags shr 11) AND $F) + 8); //расчет размера System Memory Segment
 
  GPUSize:= ((Flags shr 15) AND $7FF) shl (((Flags shr 26) AND $F)+8); //расчет размера Graphics Memory Segment
 
  GPUSize:= ((Flags shr 15) AND $7FF) shl (((Flags shr 26) AND $F)+8); //расчет размера Graphics Memory Segment
 +
</source>
  
 +
<source lang="cpp" line>
 +
CPUSize = (Flags & 0x7FF) << (((Flags >> 11) & 0xF) + 8); //расчет размера System Memory Segment
 +
GPUSize = ((Flags >> 15) & 0x7FF) << (((Flags >> 26) & 0xF)+8); //расчет размера Graphics Memory Segment
 
</source>
 
</source>
  
'''Версии и типы ресурсов:'''
+
Каждый блок памяти представляет собой набор страниц. В поле флагов кодируется размер и количество страниц. Ресурс должен содержать как минимум одну большую страницу и от нуля до четырех страниц меньшего размера. Любой непрерывный блок не должен пересекать границы страницы.
{|{{Таблица}}
+
 
!Идентификатор
+
Допустим, соответствующая часть поля flags, содержит значение 0x1045. Получаем базовый размер страницы 1024 байта (1 << ((0x1145 >> 11)+8)) и количество страниц - 0x45.
!Название
+
Верно? Не совсем. На самом деле, будет создано шесть страниц: 4 страницы по 16 килобайт, одна - 4 килобайта и одна - размером в килобайт.
!Характеристика
+
 
!Расширения
+
На количество страниц отводится всего 11 бит. Из них старшие семь - это действительно количество страниц (больших страниц), а четрые младших - определяют необходимость выделения страниц меньшего размера (каждый бит отвечает за страницу своего размера). Размер страницы всегда является степенью двойки (если это не так, он округляется вверх).
|-
+
 
|1|| Windows/XENON Animation Dictionary ||Анимации (PC и Xbox360)|| <code>.[[WAD]]</code> <code>.XAD</code>
+
Полное вычисление всех значений параметра флагов (пример на '''Delphi''' и '''C++'''):
|-
+
 
|7|| XENON Texture Dictionary ||Текстуры (Xbox360)|| <code>.XTD</code>
+
<source lang="cpp" line>WORD vpageCount = dwRscFlags & 0x7FF;
|-
+
WORD largeVpageCount = vpageCount >> 4;
|8|| Windows Texture Dictionary ||Текстуры (PC) ||<code>.[[WTD]]</code>
+
DWORD vpageSize = ((dwRscFlags >> 11) & 15)+8;
|-
+
WORD ppageCount = (dwRscFlags >> 15) & 0x7FF;
|32|| Bounds || ? (PC и Xbox360) ||<code>.[[WBD]]</code> <code>.XBD</code>
+
WORD largePpageCount = ppageCount >> 4;
|-
+
DWORD ppageSize = ((dwRscFlags >> 26) & 15)+8;</source>
|109|| XENON Model || Модели (Xbox360)||<code>.XDR</code>
+
<source lang="Delphi" line>{WORD} vpageCount := dwRscFlags and $7FF;
|-
+
{WORD} largeVpageCount := vpageCount shr 4;
|110|| Windows Model || Модели (PC) ||<code>.[[WDR]]</code>
+
{DWORD} vpageSize := ((dwRscFlags shr 11) and 15)+8;
|-
+
{WORD} ppageCount := (dwRscFlags shr 15) and $7FF;
|112|| Windows/XENON Model Frag || Модели (PC и Xbox360)||<code>.[[WFT]]</code> <code>.XFT</code>
+
{WORD} largePpageCount := ppageCount shr 4;
|}
+
{DWORD} ppageSize := ((dwRscFlags sgr 26) and 15)+8;</source>
 +
 
 +
Если загрузка ресурса получается очень простой, то с записью не все так гладко. При записи мало просто посчитать размер блока, нужно еще и найти относительно оптимальную раскладку структур по блокам.
 +
 
 +
<source lang="cpp" line>#define RSC_PAGED 0x80000000
 +
#define RSC_COMPRESSED 0x40000000
 +
#define RSC_PHYS_PAGE_COUNT_MASK 0x3C000000
 +
#define RSC_PHYS_TOTAL_PAGES_MASK 0x03FF8000
 +
#define RSC_PHYS_LARGE_PAGES_MASK 0x03F80000
 +
#define RSC_PHYS_S2_PAGE_MASK 0x00040000
 +
#define RSC_PHYS_S4_PAGE_MASK 0x00020000
 +
#define RSC_PHYS_S8_PAGE_MASK 0x00010000
 +
#define RSC_PHYS_S16_PAGE_MASK 0x00008000
 +
#define RSC_VIRT_PAGE_COUNT_MASK 0x00007800
 +
#define RSC_VIRT_TOTAL_PAGES_MASK 0x000007FF
 +
#define RSC_VIRT_LARGE_PAGES_MASK 0x000007F0
 +
#define RSC_VIRT_S2_PAGE_MASK 0x00000008
 +
#define RSC_VIRT_S4_PAGE_MASK 0x00000004
 +
#define RSC_VIRT_S8_PAGE_MASK 0x00000002
 +
#define RSC_VIRT_S16_PAGE_MASK 0x00000001</source>
 +
 
 +
 
 +
 
 +
<div class="NavFrame collapsed"><div class="NavHead">''Существующий алгоритм "подбора" значения флагов является некорректным, но он позволяет в некоторых случаях подобрать значение поля флагов, исходя из имеющихся размеров блоков. (пример на Delphi)''</div>
 +
<div class="NavContent">
 +
<source lang="delphi" line>
 +
function getCompactSize(size: longword): word; //вспомогательная функция
 +
var
 +
  i: word;
 +
begin
 +
  Assert(size mod 256 = 0); //не забудьте про проверку кратности на 256
 +
  size := size shr 8;
 +
  i := 0;
 +
  while (size mod 2 = 0) and (size >= 32) and (i < 15) do begin
 +
    i := i + 1;
 +
    size := size shr 1;
 +
end;
 +
result := ((i and $F) shl 11) or (size and $7FF);
 +
end;
 +
 +
function getFlags(sysSegSize, gpuSegSize: longword): longword; //основная функция
 +
begin
 +
  result := (getCompactSize(sysSegSize) and $7FFF)
 +
        or (getCompactSize(gpuSegSize) and $7FFF) shl 15
 +
        or 3 shl 30;
 +
end;
 +
</source>
 +
</div></div>
 +
 
 +
 
 +
==Версии и типы ресурсов==
 +
 
 +
Тип ресурса определяется расширением (и только расширением), для каждого типа, определен объект, который содержится в этом ресурсе и набор обработчиков для загрузки, инициализации, освобождения, поиска и прочих рутинных операций.
 +
 
 +
{| border="1"
 +
| Название
 +
| Платформа
 +
| Расширение файла
 +
| Версия объекта
 +
| Содержащийся объект
 +
| Описание
 +
|-  
 +
|rowspan="2" | Animation Dictionary
 +
| Windows
 +
| <code>[[WAD|*.wad]]</code>
 +
|rowspan="2" | 1
 +
|rowspan="2" | <code>rage::pgDictionary<rage::crAnimation></code>
 +
|rowspan="2" | Коллекция анимаций, содержит преобразованные в ресурсы файлы типа <code>[[*.anim]]</code>
 +
|-
 +
| Xbox360 
 +
| <code>*.xad</code>
 +
|-  
 +
|rowspan="2" | Texture Dictionary  
 +
| Windows 
 +
| <code>[[WTD|*.wtd]]</code>
 +
| 8
 +
| <code>rage::pgDictionary<rage::grcTexturePC></code>
 +
|rowspan="2" | Коллекция текстур, содержит преобразованные в ресурсы файлы типа <code>*.DDS</code>
 +
|-  
 +
| Xbox360 
 +
| <code>*.xtd</code>
 +
| 7
 +
| <code>rage::pgDictionary<rage::grcTextureXenon></code> 
 +
|-
 +
|rowspan="2" | Physics store ( Bound Dictionary )  
 +
| Windows 
 +
| <code>[[WBD|*.wbd]]</code>
 +
|rowspan="2" | 32  
 +
|rowspan="2" | <code>rage::pgDictionary<rage::phBound></code> 
 +
|rowspan="2" | Коллекция содержащая несколько границ (Bound), для нескольких разных объектов.
 +
|-
 +
| Xbox360 
 +
| <code>*.xbd</code>
 +
|-
 +
|rowspan="2" | Drawble
 +
| Windows 
 +
| <code>[[WDR|*.wdr]]</code>
 +
| 110
 +
| <code>rage::gtaDrawable</code>
 +
|rowspan="2" | Ресурс "простой" модели, помимо информации о самой моделе, информации о шейдерах, также может содержать текстуры используемые только в этой моделе.
 +
|-  
 +
| Xbox360 
 +
| <code>*.xdr</code>
 +
| 109
 +
| <code>rage::gtaDrawable</code> 
 +
|-
 +
|rowspan="2" | Frag Type
 +
| Windows 
 +
| <code>[[WFT|*.wft]]</code>
 +
| 112
 +
|
 +
|rowspan="2" |Ресурс "комплексной" модели, кроме собственно самой модели также содержит информацию о границах (Bounds), анимациях и другое...
 +
|-
 +
| Xbox360 
 +
| <code>*.xft</code>
 +
| 112
 +
 +
|-  
 +
|rowspan="2" | HTML Document
 +
| Windows
 +
| <code>[[WHM|*.whm]]</code>
 +
| 1
 +
| <code>rage::CHtmlDocument</code>
 +
| "HTML" страница внутреннего интернета
 +
|-
 +
| Xbox360 
 +
| <code>*.xhm</code>
 +
| 1
 +
| <code>rage::CHtmlDocument</code>
 +
| "HTML" страница внутреннего интернета
 +
|-
 +
|rowspan="2" | Drawable Dictionary
 +
| Windows 
 +
| <code>[[WDD|*.wdd]]</code>
 +
| 110
 +
|rowspan="2" | <code>rage::pgDictionary<rage::gtaDrawable></code>
 +
|rowspan="2" | Коллекция содержащая несколько "простых" моделей
 +
|-
 +
| Xbox360 
 +
| <code>*.xdd</code>
 +
| 109
 +
|-
 +
|rowspan="2" | Static bound ( Bound )
 +
| Windows
 +
| <code>[[WBN|*.wbn]]</code>
 +
|rowspan="2" | 32
 +
|rowspan="2" | <code>rage::pgBaseWrapper<rage::datOwner<rage::phBound>></code>
 +
|rowspan="2" | Ресурс содержит описание границ (Bound) объекта игрового мира, используется для определения физичиских границ объекта.
 +
|-
 +
| Xbox360 
 +
| <code>[[XBN|*.xbn]]</code>
 +
|}
  
[[Категория: GTA_4]][[Категория: Форматы файлов]]
+
[[Категория: GTA_4]][[Категория: Форматы файлов]][[Категория: Ресурсы]]

Текущая версия на 19:05, 15 августа 2010

Формат

Ресурсные файлы GTA IV имеют следующий формат:

Заголовок

4 байта - Сигнатура RSC (52 53 43 05)
4 байта - Версия ресурса
4 байта - Флаги

Далее следует сами данные ресурса в запакованном формате. ПК-версия игры использует в качестве алгоритма упаковки - Zlib.

Ресурс содержит два блока памяти - System Memory Segment (CPU) и Graphics Memory Segment (GPU). Размер каждого блока кратен 256. В одном из них хранится сам объект, в другом - используемые данные Direct3D (тексельные, вертексные или индексные буфера).

Каждый ресурс содержит один (и только один) объект, со всеми включенными в него подобъектами. (Например, файл с расширением .WTD содержит в себе объект rage::pgDictionary. При этом, в файле сохраняется не только сама коллекция, но и все включенные в нее объекты текстур, используемые ими хэши, имена и, конечно, пиксельные данные). Все указатели заменяются на смещения в файле. При чтении, смещения заменяются обратно на указатели в памяти.

Любой указатель (число вида 0x5xxxxxxx или 0x6xxxxxxx) преобразуется в 32-битное число. Четыре старших бита в нем - код блока (5 - CPU блок, 6 - GPU блок), младшие 28 - смещение в блоке (для GPU блока возможны случаи, когда структура выравнивается на размер страницы, т.е. младшие 12 бит заменяются нулями, а содержавшееся в них значение используется, например, как идентификатор формата данных).

Таким образом преобразовать любой указатель в значение оффсета можно простой операцией (пример на Delphi и C++):

if (Ptr shr 28 = 5) or (Ptr shr 28 = 6) then Offset:=Ptr and $0FFFFFFF;
if ((Ptr >> 28 == 5) | (Ptr >> 28 == 6)) Offset = Ptr & 0x0FFFFFFF;


Размеры блоков хранятся в RSC-заголовке (параметр "флаги), их можно вычислить следующим образом (пример на Delphi и C++):

  1.  CPUSize:= (Flags AND $7FF) shl (((Flags shr 11) AND $F) + 8); //расчет размера System Memory Segment
  2.  GPUSize:= ((Flags shr 15) AND $7FF) shl (((Flags shr 26) AND $F)+8); //расчет размера Graphics Memory Segment
  1.  CPUSize = (Flags & 0x7FF) << (((Flags >> 11) & 0xF) + 8); //расчет размера System Memory Segment
  2.  GPUSize = ((Flags >> 15) & 0x7FF) << (((Flags >> 26) & 0xF)+8); //расчет размера Graphics Memory Segment

Каждый блок памяти представляет собой набор страниц. В поле флагов кодируется размер и количество страниц. Ресурс должен содержать как минимум одну большую страницу и от нуля до четырех страниц меньшего размера. Любой непрерывный блок не должен пересекать границы страницы.

Допустим, соответствующая часть поля flags, содержит значение 0x1045. Получаем базовый размер страницы 1024 байта (1 << ((0x1145 >> 11)+8)) и количество страниц - 0x45. Верно? Не совсем. На самом деле, будет создано шесть страниц: 4 страницы по 16 килобайт, одна - 4 килобайта и одна - размером в килобайт.

На количество страниц отводится всего 11 бит. Из них старшие семь - это действительно количество страниц (больших страниц), а четрые младших - определяют необходимость выделения страниц меньшего размера (каждый бит отвечает за страницу своего размера). Размер страницы всегда является степенью двойки (если это не так, он округляется вверх).

Полное вычисление всех значений параметра флагов (пример на Delphi и C++):

  1. WORD vpageCount = dwRscFlags & 0x7FF;
  2. WORD largeVpageCount = vpageCount >> 4;
  3. DWORD vpageSize = ((dwRscFlags >> 11) & 15)+8;
  4. WORD ppageCount = (dwRscFlags >> 15) & 0x7FF;
  5. WORD largePpageCount = ppageCount >> 4;
  6. DWORD ppageSize = ((dwRscFlags >> 26) & 15)+8;
  1. {WORD} vpageCount := dwRscFlags and $7FF;
  2. {WORD} largeVpageCount := vpageCount shr 4;
  3. {DWORD} vpageSize := ((dwRscFlags shr 11) and 15)+8;
  4. {WORD} ppageCount := (dwRscFlags shr 15) and $7FF;
  5. {WORD} largePpageCount := ppageCount shr 4;
  6. {DWORD} ppageSize := ((dwRscFlags sgr 26) and 15)+8;

Если загрузка ресурса получается очень простой, то с записью не все так гладко. При записи мало просто посчитать размер блока, нужно еще и найти относительно оптимальную раскладку структур по блокам.

  1. #define RSC_PAGED 0x80000000
  2. #define RSC_COMPRESSED 0x40000000
  3. #define RSC_PHYS_PAGE_COUNT_MASK 0x3C000000
  4. #define RSC_PHYS_TOTAL_PAGES_MASK 0x03FF8000
  5. #define RSC_PHYS_LARGE_PAGES_MASK 0x03F80000
  6. #define RSC_PHYS_S2_PAGE_MASK 0x00040000
  7. #define RSC_PHYS_S4_PAGE_MASK 0x00020000
  8. #define RSC_PHYS_S8_PAGE_MASK 0x00010000
  9. #define RSC_PHYS_S16_PAGE_MASK 0x00008000
  10. #define RSC_VIRT_PAGE_COUNT_MASK 0x00007800
  11. #define RSC_VIRT_TOTAL_PAGES_MASK 0x000007FF
  12. #define RSC_VIRT_LARGE_PAGES_MASK 0x000007F0
  13. #define RSC_VIRT_S2_PAGE_MASK 0x00000008
  14. #define RSC_VIRT_S4_PAGE_MASK 0x00000004
  15. #define RSC_VIRT_S8_PAGE_MASK 0x00000002
  16. #define RSC_VIRT_S16_PAGE_MASK 0x00000001



Версии и типы ресурсов

Тип ресурса определяется расширением (и только расширением), для каждого типа, определен объект, который содержится в этом ресурсе и набор обработчиков для загрузки, инициализации, освобождения, поиска и прочих рутинных операций.

Название Платформа Расширение файла Версия объекта Содержащийся объект Описание
Animation Dictionary Windows *.wad 1 rage::pgDictionary<rage::crAnimation> Коллекция анимаций, содержит преобразованные в ресурсы файлы типа *.anim
Xbox360 *.xad
Texture Dictionary Windows *.wtd 8 rage::pgDictionary<rage::grcTexturePC> Коллекция текстур, содержит преобразованные в ресурсы файлы типа *.DDS
Xbox360 *.xtd 7 rage::pgDictionary<rage::grcTextureXenon>
Physics store ( Bound Dictionary ) Windows *.wbd 32 rage::pgDictionary<rage::phBound> Коллекция содержащая несколько границ (Bound), для нескольких разных объектов.
Xbox360 *.xbd
Drawble Windows *.wdr 110 rage::gtaDrawable Ресурс "простой" модели, помимо информации о самой моделе, информации о шейдерах, также может содержать текстуры используемые только в этой моделе.
Xbox360 *.xdr 109 rage::gtaDrawable
Frag Type Windows *.wft 112 Ресурс "комплексной" модели, кроме собственно самой модели также содержит информацию о границах (Bounds), анимациях и другое...
Xbox360 *.xft 112
HTML Document Windows *.whm 1 rage::CHtmlDocument "HTML" страница внутреннего интернета
Xbox360 *.xhm 1 rage::CHtmlDocument "HTML" страница внутреннего интернета
Drawable Dictionary Windows *.wdd 110 rage::pgDictionary<rage::gtaDrawable> Коллекция содержащая несколько "простых" моделей
Xbox360 *.xdd 109
Static bound ( Bound ) Windows *.wbn 32 rage::pgBaseWrapper<rage::datOwner<rage::phBound>> Ресурс содержит описание границ (Bound) объекта игрового мира, используется для определения физичиских границ объекта.
Xbox360 *.xbn