На данный момент вы открыли .X файл и зарегистрировали используемые шаблоны (такие как стандартные шаблоны DirectX). Создали объект перечисления и теперь готовы к извлечению данных из .X файла.
На данный момент созданный вами объект IdirectXFileEnumObject указывает на первый объект данных в файле, которым обычно является "Header". Все объекты данных верхнего уровня являются родственниками объекта "Header" (или первого объекта в файле). Каждый прочитанный вами объект данных может содержать встроенные (дочерние) объекты или ссылки на другие объекты, которые вы можете получить.
Объект перечисления сам по себе не содержит объектов данных. Вместо этого вам необходимо получить интерфейс IDirectXFileData для доступа к данным. Чтобы получить интерфейс IDirectXFileData, вам необходимо вызвать функцию IDirectXFileEnumObject::GetNextDataObject.
HRESULT IDirectXFileEnumObject::GetNextDataObject( \ LPDIRECTXFILEDATA* ppDataObj) ;
Имея всего лишь один параметр, GetNextDataObject очень проста в использовании. Вам просто необходимо создать экземпляр объекта IDirectXFileData и использовать его при вызове GetNextDataObject.
IDirectXFileData *pData;
HRESULT hr = pEnum->GetNextDataObject(&pData);
Заметили, как я сохраняю значение, возвращаемое функцией GetNextDataObject? Если возвращаемый результат является ошибкой (что проверяется макросом FAILED), то это означает, что перечисление закончено. Если же вызов функции GetNextDataObject успешен, тогда вы получаете новый интерфейс для доступа к данным объекта!
Прежде чем вы начнете работать с данными объекта, давайте закончим обсуждение перечисления. Пока что вы можете получить первый объект в файле и его интерфейс данных. Что делать, если вы хотите получить остальные объекты из .X файла или встроенные объекты?
После того как вы закончили с одним объектом, вам необходимо освободить его и перейти к следующему объекту. Простой вызов IDirectXFileData::Release освободит интерфейс данных, и повторяющимися вызовами IDirectXFileEnumObject::GetNext-DataObject вы можете получить следующий перечисленный объект данных родственника (высокоуровневого). Вы можете представить перечисление всех родственников (получая их интерфейсы данных) с помощью следующего кода:
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) { // Сделать что-нибудь с объектом pData
// Освободить интерфейс данных для продолжения pData->Release();
}
Все что остается, это добавить возможность получать дочерние (нижнеуровневые) объекты, перечислить их и сделать доступными. Для получения дочернего объекта используйте сначала функцию IDirectXFileData::GetNextObject, чтобы посмотреть содержит ли объект встроенные объекты.
HRESULT IDirectXFileData::GetNextObject ( \ LPDIRECTXFILEOBJECT* ppChildObj) ;
Это еще одна простая функция с одним параметром - указателем на интерфейс IDirectXFileObject. Если вызов GetNextObject был успешным, тогда вам необходимо обработать дочерний объект. После того как вы завершите это, можете освободить его
(вызвав Release) и продолжать вызывать GetNextObject, пока она не вернет ошибку, что означает, что больше не осталось объектов.
Вы можете реализовать циклические вызовы GetNextObject, как я сделал здесь
IDirectXFileObject *pObject;
while(SUCCEEDED(pData->GetNextObject(&pObject))) {
// Дочерний объект существует, необходимо получить его
/ / Освободить интерфейс объекта файла pObject->Release() ;
}
После того как вы получили правильный интерфейс IDirectFileObject (после вызова GetNextObject), вы можете быстро определить, какой дочерний объект перечисляется (используя приемы описанные ниже). Однако есть небольшое препятствие. Объект может быть как ссылкой, так и экземпляром, и манера доступа к нему зависит от его типа.
Для экземпляров объектов (которые определяются обычно в .X файлах) вы можете получить IDirectXFileObject для интерфейса IDirectXFileData.
IDirectXFileData *pSubData;
//Проверить,является ли дочерний объект экземпляром(если нет,то ошибка) if(SUCCEEDED(pObject->QueryInterfaсe( \
IID_IDirectXFileData, (void**)&pSubData))) { // Дочерний объект существует, сделать что-нибудь с ним
// Освободить объект pSubData->Release() ;
}
Вы видели, как использовать объект IDirectXFileData раннее в этой главе. Используя только что приобретенные навыки, вы можете получать дочерние объекты IDirectXFileData для их собственных встроенных дочерних объектов.
Что касается ссылочных объектов, вам необходимо сначала получить объект IDirectXFileDataReference, а затем переделать ссылку в объект IDirectXFileData. Нижеследующий код преобразовывает ссылки на объекты для вас.
Совет. Если экземпляр объекта не существует, когда вы его получаете, вызов Query-Interface окончится неудачей. Это быстрый способ определения типа объекта. Таким же образом определяются ссылочные объекты — запрос окончится неудачей, если объект не ссылочный.
IDirectXFileDataReference *pRef; IDirectXFileData *pSubData;
// Проверить является ли объект ссылочным (если нет, то неудача) 1г(8иССЕЕЕЕЕ(р8иЪОЪ]->С>иегу1пгеггасе( \
IID_IDirectXFileDataReference, \ (void**)&pRef))) { // Ссылочный объект существует. Преобразовать ссылку pRef->Resolve(&pSubData);
// Сделать что-нибудь с объектом
// Освободить используемый интерфейс pRef->Release(); pSubData->Release();
}
Вы поверите мне, если я скажу, что самая сложная часть закончена? Перечисление объектов данных и дочерних объектов очень просто, и если это так же сложно, как оно понимается, тогда вам будет все просто! Чтобы облегчить вашу работу программиста, я предлагаю реализовать перечисление объектов данных в двух простых функциях.
Первая функция (названная Parse) будет открывать .X файл, создавать объект перечисления и просматривать все объекты верхнего уровня. Функция будет брать каждый перечисленный объект и передавать его второй функции (ParseObject), которая будет обрабатывать данные объектов на основе типа их шаблона и просматривать встроенные дочерние объекты. Функция ParseObject будет вызывать себя всякий раз, когда найдет дочерний объект, таким образом обрабатывая встроенные в дочерние объекты.
Вот код функции Parse.
// Need to include rmxftmpl.h and rmxfguid.h
// Необходимо подключить "rmxftmpl.h" и "rmxfguid.h"
BOOL Parse(char *Filename) {
IDirectXFile *pFile = NULL;
IDirectXFileEnumObject *pEnum = NULL;
IDirectXFileData *pData = NULL;
// Создать объект перечисления, вернуть ошибку
if(FAILED(DirectXFileCreate(&pFile))) return FALSE;
// Зарегистрировать стандартные шаблоны, вернуть ошибку
if(FAILED(pFile->RegisterTemplates( \
(LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
return FALSE;
// Создать объект перечисления, вернуть ошибку if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, \
&pEnum))) { pFile->Release();
return FALSE;
// Пройтись по всем верхнеуровневым объектам
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
// Анализировать объект, вызвав ParseObject ParseObject(pData) ;
// Освободить объект pData->Release();
}
// Освободить использованные COM объекты pEnum->Release(); pFile->Release();
return TRUE;
}
Функция Parse не содержит ничего особенного и, конечно же, не является очень сложной. Я уже объяснил все аспекты, встречающиеся в функции, так что нет нужды повторяться. Вместо этого перейдем к функции ParseObject, которая берет объект и просматривает его дочерние объекты.
void ParseObject(IDirectXFileData *pData)
{
IDirectXFileObject *pObject = NULL; IDirectXFileData *pSubData = NULL; IDirectXFileDataReference *pRef = NULL;
// Просмотр встроенных объектов
while(SUCCEEDED(pData->GetNextObject(&pObject))) {
// Искать ссылочные объекты if(SUCCEEDED(pObject->QueryInterface( \
IID_IDirectXFileDataReference, (void**)&pRef))) {
// Преобразовать объект pRef->Resolve(&pSubData);
// Анализировать объект, вызвав ParseObject ParseObject(pSubData) ;
// Освободить интерфейсы объектов pSubData->Release(); pRef->Release();
}
// Искать экземплярные объекты if(SUCCEEDED(pObject->QueryInterfaсe( \
IID_IDirectXFileData, (void**)&pSubData))) {
// Анализировать объект, вызвав ParseObject
ParseObject(pSubData);
/ / Освободить интерфейсы объектов pSubData->Release ();
}
// Освободить интерфейс для следующего используемого объекта pObject->Release();
}
}
Опять же, функция ParseObject не содержит ничего нового. Единственное что вы заметите в этих двух функциях это то, что они на самом деле не делают ничего кроме перечисления всех объектов находящихся в .X файле. Когда придет время работать с данными объекта, что вы будете делать?
⇐Открытие .X файла || Оглавление || Получение данных объекта⇒