CrystalSpace

Использование CS. Концепция двжка. Плагины. (Аналог 4 части оф. туториала)

Автор:

CS – это рабочая база с модульной концепцией. Из-за этого он кажется переутяжелённым по сравнению с другими движками. Взамен, такая структура (подключаемые модули-plug-in’ы) предоставляет широкую сферу применения, и место для полёта фантазии игродельца. В этой главе разрабы попытаются дать нам понять философию их детища. Здесь нет какого-либо кода, весь текст лишь для того, что бы немного «въехать» в суть работы движка.

CS в собранном виде представляет собой набор разнообразных компонентов и библиотек для создания игр. Хотя по большей части двиг заточен под 3Д, такие его части как VFS (Virtual File System) –plug-in или звуковой драйвер ((ага, глючный OpenAL)), Вы можете спокойно воткнуть куда угодно. То есть компоненты как бы не зависят друг от друга – это выдается за главную фичу движка. Например, если Вам не нужна модная физика или скрипты, то можно вообще забыть про соответсвующие plug-in’ы. Все компоненты движка разработаны так, чтобы требовать лишь минимально необходимые для своей работы другие plug-in’ы. Например 3Д движок требует 3Д рендерер, а 3Д рендереру нужнен 2Д фрейм, чтобы туда писать картинку, его предоставляет plug-in canvas. С другой стороны, для 3Д рендеринга 3Д движок вовсе необязателен.

Несмотря на малую зависимоть модулей друг от друга, они легко интегрируются.

Еслы Вы все еще не расхотели создавать свои замечательные проэкты на CS, зарубите себе на носу: CS  - это не какая-то одна монолитная библиотека, это – несколько модулей. Модулями разрабы называют plug-in’ы вкупе с библиотеками, не находя между ними принципиального различия

Для использования plug-in может быть организован в виде динамической или статической библиотеки. Все plug-in’ы подключаются похожим способом (как именно - далее), имеют унитарный интерфейс, и сохраняют его, будучи собранными в библиотеку. Главное отличие plug-in’а от обычной библиотеки – plug-in использует как интерфейс только SCF (Shared Class Facility), а библиотеки и SCF, и обычные классы CPP.

Plug-in’ы можно создавать самому, ознакомившись с тем, как их сделать совместимыми через SCF с остальным движком.

Про SCF:

Главный объект SCF – это интерфейс, т. е. способ без заморочек отделить описание public методов объекта от текста программы, где они реализуются. На выходе получается, что через SCF мы будем иметь только указатель на абстрактный класс (без реальной имплементации), который содержит только «виртуальные»(не virtual) методы. Эта байда пишется в хэдере. Такой объект будет т. н. имплементацией интерфейса. Используя движок, вы будете, вызывать функции, которые  создавают реальные объекты, а возвращают только этот «указательный» объект-интерфейс. Это очень лаконично, удобно и экономично. Раньше, пока разработчики еще не написали свой смарт-пойнтер <CSref>, для передачи ссылки использовался метод IncRef(), для удаления – DecRef(). К выходу CS 2.0 и вовсе обещают отказаться от этих команд, так что их использование нежелательно.
Вообще, CS широко использует [url= http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B1%D1%80%D0%B8%D1%87… 0%B8%D1%8F%29]фабричный метод.[/url]

Подключение plug-inа:

Выполните все следующие действия сперва для тех plug-inов, от которых зависит подключаемый.

Теперь подробнее.

Регистрация (register) plug-in’а.

Если plug-in – статичная библиотека(static library):

SCF_REGISTER_STATIC_CLASS(
  cxx-class,
  scf-name,
  description,
  dependencies)

Где:
cxx-class – имя класса-создателя(factory), то же самое имя передается макросу SCF_IMPLEMENT_FACTORY()
scf-name – имя создаваемого объекта
description – комментарий, строка
dependencies –  SCF объекты других plug-inов, от которых зависит данный plug-in, через запятую

DLL-plug-in регистрируется автоматически по своим метаданным при загрузке.

Загрузка (load) plug-in’а.

Для этого CS предоставляет нам plug-in loader. Это - объект, позволяющий загружать plug-inы по данным / аргументам) из config-файла / командной строки или как- либо еще. Кроме того, он способен зарегистрировать (с помощью другого объекта, plug-in manager) наш plug-in в Object Registry.

Что такое Object Registry? Это «книга регистрации в церкви на цетральной площади деревни, называющейся CrystalSpace»: сюда любой модуль (plug-in loader в том числе) вписывает SCF-объекты, давая им имя-тэг. По умолчанию, объекту будет приписано имя, идентичное названию интерфейса. Например, 3D renderer – plug-in, регистрирующий, среди других, интерфейс iGraphics3D. Однако в память можно загрузить одновременно несколько 3Д – рендереров с разными именами-тэгами (например, для процедурного текстурирования). Но дефолтный 3Д – рендерер будет зарегистрирован как iGraphics3D.

Вернёмся к загрузке плгаина. Итак, есть 3 способа:

Plug-in loader. Принимаемые аргументы имеют следующий приоритет:

csPluginLoader::csPluginLoader (iObjectRegistry* object_reg); /*инициализация*/
void csPluginLoader::RequestPlugin (const char *pluginName, const char *tagName); /*что будем грузить, какое имя-тэг дадим в Object Registry*/
bool csPluginLoader::LoadPlugins (); /*собственно, грузим plug-inы*/
virtual csPluginLoader::~csPluginLoader();/*удоление*/

Класс - csInitializer(), среди прочего также и загружающий plug-inы функцией RequestPlugins():

#include <crystalspace.h>

class Simple : public csApplicationFramework

{
public:
  Simple ();
  ~Simple ();
  bool OnInitialize (int argc, char* argv[]);

};

bool Simple::OnInitialize(int argc, char* argv[])
{
  if (!csInitializer::RequestPlugins(GetObjectRegistry(),
    CS_REQUEST_VFS,
    CS_REQUEST_OPENGL3D,
    CS_REQUEST_ENGINE,
    )) return ReportError("Failed to initialize plugins!");

  return true;
}
//это часть примера, который целиком будет рассмотрен позже

Создание запроса (query) к интерфейсу plug-in’а.

Любой объект (в том числе и plug-in) находится в Object Registry со своим именем-тэгом, и достпен по нему. Как, например, плагин Script:

//запрос по дефолтному имени
csQueryRegistry<iScript>(object_reg)
//или, для запроса по альтернативному имени:
csQueryRegistryTag<iScript_02>(object_reg)

Та же байда, в Питоне:

>>> import sys
>>> from cspace import *
>>> object_reg = csInitializer.CreateEnvironment(sys.argv)
>>> plugin_mgr = object_reg.Get(iPluginManager)
>>> script = CS_LOAD_PLUGIN(plugin_mgr, "crystalspace.script.python", iScript) #да, рекурсия
>>> type(plugin_mgr)
<class 'cspace.core.iPluginManager'>
>>> type(script)
<class 'cspace.ivaria.iScript'>
>>>

Этот код создаст объект cspace.core.iObjectRegistry с именем object_reg и минимальное окружение: часы, 3Д движок, загрузчик изображений, plug-in loader и т. д… Все эти объекты (а точнее, их SCF-интерфейсы) будут вписаны в object_reg. Уже оттуда мы «вытаскиваем»( .Get) plug-in loader по его дефолтному имени-тэгу чтобы использовать дальше.

5 марта 2011