Как применить DOP и сохранить хороший пользовательский интерфейс?
В настоящее время я хочу немного оптимизировать свой 3d движок для консолей. Точнее, я хочу быть более дружественным к кешу и выровнять свои структуры, ориентируясь на данные, а также сохранить свой приятный пользовательский интерфейс.
Например:
bool Init()
{
// Create a node
ISceneNode* pNode = GetSystem()->GetSceneManager()->AddNode("viewerNode");
// Create a transform component
ITransform* pTrans = m_pNode->CreateTransform("trans");
pTrans->SetTranslation(0,1.0f,-4.0f);
pTrans->SetRotation(0,0,0);
// Create a camera component
ICamera* pCam = m_pNode->CreateCamera("cam", pTrans);
pCam->LookAt(Math::Vec3d(0,0,0));
// And so on...
}
Таким образом, пользователь может работать с указателями интерфейса в своем коде.
НО
В моем движке в настоящее время я храню указатели на узлы сцены.
boost::ptr_vector<SceneNode> m_nodes
Поэтому в ориентированном на данные проектировании рекомендуется иметь структуры массивов, а не массивы структур. Таким образом, мой узел получает от...
class SceneNode
{
private:
Math::Vec3d m_pos;
};
std::vector<SceneNode> m_nodes;
к этому...
class SceneNodes
{
std::vector<std::string> m_names;
std::vector<Math::Vec3d> m_positions;
// and so on...
};
Поэтому я вижу две проблемы здесь, если я хочу применить DOP. Во-первых, как мне сохранить свой приятный пользовательский интерфейс, не заставляя пользователя работать с идентификаторами, индексами и так далее?
Во-вторых, как мне управлять перемещением свойств, когда некоторые векторы изменяют размер, не позволяя указателям интерфейса пользователя указывать на нирвану?
В настоящее время моя идея заключается в реализации своего рода handle_vector, из которого вы получаете дескриптор для постоянных "указателей":
typedef handle<ISceneNodeData> SceneNodeHandle;
SceneNodeHandle nodeHandle = nodeHandleVector.get_handle(idx);
Поэтому, когда intern std::vector изменяет размеры, он обновляет свои дескрипторы. "Дескриптор" хранит указатель на реальный объект, а оператор "->" перегружен, чтобы получить красивую упаковку. Но этот подход кажется мне сложным?
Как вы думаете? Как сохранить хороший интерфейс, но держать мысли непрерывно в памяти для лучшего использования кэша?
Спасибо за любую помощь!
2 ответа
Вам нужно будет использовать более умные ручки, чем необработанные указатели. Обойтись без DOP невозможно.
Это означает:
class SceneNode
{
public:
std::string const& getName() const { mManager->getSceneName(mId); }
void setName(std::string const& name) { mManager->setSceneName(mId, name); }
// similar with other data
private:
ISceneManager* mManager;
size_t mId;
};
Один очень хороший момент, хотя: пользователь не может случайно позвонить delete
на одном из указателей вы вернулись сейчас. Вот почему умные ручки всегда лучше.
С другой стороны: как вы собираетесь справляться с жизненным циклом mManager
это еще одна проблема:-)
Для тех, кто интересуется практическим примером DOP, взгляните на эту фантастическую презентацию от Никласа Фрикхольма => http://bitsquid.blogspot.com/2010/05/practical-examples-in-data-oriented.html
Это помогло мне реализовать мой граф сцены ориентированным на данные способом.