Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DirectX. Продвинутая Анимация (2004) [rus].pdf
Скачиваний:
336
Добавлен:
16.08.2013
Размер:
8.39 Mб
Скачать

Использование формата файла ,Х

вы можете зарегистрировать шаблон, определенный в буфере "Templates", используя следующий код:

pFile->RegisterTemplates(Templates, strlen(Templates));

Вернемся к самой теме - регистрирование стандартных шаблонов. Вы видели, как работает функция RegisterTemplates. Для того чтобы зарегистрировать стандартные шаблоны, вам необходимо включить два добавочных файла в ваш проект - "rmxftmpl.h" и "rmxfguid.h". Эти два файла содержат определения и GUID стандартных шаблонов соответственно.

Внутри файла "rmxftmpl.h" вы найдете буфер данных шаблона D3DRMXTEMPLATES и макрос D3DRM_XTEMPLATE_BYTES. Они используются при вызове RegisterTemplates для регистрирования стандартных шаблонов, как вы можете видеть здесь:

pFile->RegisterTemplates(D3DRM_XTEMPLATES, \ D3DRM_XTEMPLATE_BYTES);

Правильно, просто вызвав приведенный выше кусочек кода, вы успешно зарегистрируете стандартные шаблоны, и вы готовы продолжать! Но сначала небольшой совет: как только вы начнете использовать формат .X для ваших специализированных данных и шаблонов, не забывайте, что RegisterTemplates отлично регистрирует и ваши шаблоны!

Замечание. Отметьте, что в определении шаблона "Templates" используется наклонная черта влево для обозначения новой линии, и после этого следует стандартный заголовок .X файла.

Совет. Для того, чтобы запомнить "rmxftmpl.h" и "rmxfguid.h", просто помните, что "rmxf " это .X файл сохраненного режима, "tmpl" означает шаблон и "guid" означает глобальноуникальный идентификатор.

Открытие .X файла

После того как вы создали интерфейс IDirectXFile и зарегистрировали используемые шаблоны, вам необходимо открыть .X файл и начать просмотр содержащихся в нем объектов. Процессы открытия .X файла и создания объекта просмотра объединены в один, соответствующий вызову функции IDirectXFile::CreateEnumObject.

HRESULT IDirectXfile::CreateEnumObject( LPVOID pvSource, // имя .Х файла

DXFILELOADOPTIONS dwLoadOptions, // параметры загрузки LPDIRECTXFILEENUMOBJECT* ppEnumObj}; // интерфейс перечисления

96

Глава3

Когда вы вызываете функцию CreateEnumObject, укажите ей в качестве параметра pvSource имя загружаемого .X файла, а в качестве ppEnumObj используемый интерфейс. Что же касается dwLoadOptions, вы должны задать значение DXFILELOAD_FROMFILE, которое сообщает DirectX, что файл загружается с диска. Другие возможные значения dwLoadOptions это DXFILELOAD_FROMRESOURCE, DXFILELOAD_FROMMEMORY и DXFILELOAD_FROMURL. Эти значения говорят DirectX загружать файл из ресурсов, буфера памяти или сетевого адреса соответственно. Да, так и есть - вы можете загружать .X файл прямо из Интернета.

Совет.Для загрузки .X файла из Интернета, используя адрес, задайте полный сетевой путь в "pvSource". Для загрузки из ресурса или памяти просто укажите дескриптор ресурса или указатель памяти (оба преобразуются к LPVOID) вpvSource.

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

// Filename = имя загружаемого файла (например "test.x") IDirectXFileEnumObject *pEnum; pFile->CreateEnumObject((LPVOID)Filename, \

DXFILELOAD_FROMFILE, &pEnum);

Из комментариев кода видно, что "Filename" указывает на правильное имя файла - в данном случае "test.x". После успешного вызова функция CreateEnumObject возвращает вам правильный объект перечисления (необходим один на один открытый файл), готовый к перечислению объектов находящихся в файле.

Перечисление объектов данных

На данный момент вы открыли .X файл и зарегистрировали используемые шаблоны (такие как стандартные шаблоны DirectX). Создали объект перечисления и теперь готовы к извлечению данных из .X файла.

На данный момент созданный вами объект IdirectXFileEnumObject указывает на первый объект данных в файле, которым обычно является "Header". Все объекты данных верхнего уровня являются родственниками объекта "Header" (или первого объекта в файле). Каждый прочитанный вами объект данных может содержать встроенные (дочерние) объекты или ссылки на другие объекты, которые вы можете получить.

Объект перечисления сам по себе не содержит объектов данных. Вместо этого вам необходимо получить интерфейс IDirectXFileData для доступа к данным. Чтобы получить интерфейс IDirectXFileData, вам необходимо вызвать функцию IDirectXFileEnumObject::GetNextDataObject.

Использование формата файла .X

HRESULT IDirectXFileEnumObject::GetNextDataObject( \

LPDIRECTXFILEDATA* ppDataObj);

Имея всего лишь один параметр, GetNextDataObject очень проста в использовании. Вам просто необходимо создать экземпляр объекта IDirectXFileData и использовать его при вызове GetNextDataObject.

IDirectXFileData *pData;

HRESULT hr = pEnum->GetNextDataObject(&pData);

Заметили, как я сохраняю значение, возвращаемое функцией GetNextDataObject? Если возвращаемый результат является ошибкой (что проверяется макросом FAILED), то это означает, что перечисление закончено. Если же вызов функции GetNextDataObject успешен, тогда вы получаете новый интерфейс для доступа к данным объекта!

Прежде чем вы начнете работать с данными объекта, давайте закончим обсуждение перечисления. Пока что вы можете получить первый объект в файле и его интерфейс данных. Что делать, если вы хотите получить остальные объекты из .X файла или встроенные объекты?

После того как вы закончили с одним объектом, вам необходимо освободить его и перейти к следующему объекту. Простой вызов IDirectXFileData::Release освободит интерфейс данных, и повторяющимися вызовами IDirectXFileEnumObject::GetNextDataObject вы можете получить следующий перечисленный объект данных родственника (высокоуровневого). Вы можете представить перечисление всех родственников (получая их интерфейсы данных) с помощью следующего кода:

while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {

//Сделать что-нибудь с объектом pData

//Освободить интерфейс данных для продолжения pData->Release();

}

Все что остается, это добавить возможность получать дочерние (нижнеуровневые) объекты, перечислить их и сделать доступными. Для получения дочернего объекта используйте сначала функцию IDirectXFileData::GetNextObject, чтобы посмотреть содержит ли объект встроенные объекты.

HRESULT IDirectXFileData::GetNextObject ( \

LPDIRECTXFILEOBJECT* ppChildObj);

Это еще одна простая функция с одним параметром - указателем на интерфейс IDirectXFileObject. Если вызов GetNextObject был успешным, тогда вам необходимо обработать дочерний объект. После того как вы завершите это, можете освободить его

98

Глава3

(вызвав 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. Нижеследующий код преобразовывает ссылки на объекты для вас.

Совет. Если экземпляр объекта не существует, когда вы его получаете, вызов QueryInterface окончится неудачей. Это быстрый способ определения типа объекта. Таким же образом определяются ссылочные объекты — запрос окончится неудачей, если объект не ссылочный.

IDirectXFileDataReference *pRef;

IDirectXFileData *pSubData;

// Проверить является ли объект ссылочным (если нет, то неудача) if(SUCCEEDED(pSubObj->QueryInterfaсe( \

Использованиеформатафайла.X

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;

100

// Пройтись по всем верхнеуровневым объектам while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {

//Анализировать объект, вызвав ParseObject ParseObject(pData);

//Освободить объект

pData->Release();

}

// Освободить использованные CОМ объекты 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);

Соседние файлы в предмете Программирование на C++