Comment appliquer DOP et de garder une interface utilisateur agréable?
-
28-09-2019 - |
Question
Actuellement je veux optimiser mon moteur 3D pour les consoles un peu. Plus précisément, je veux être plus convivial cache et aligner mes structures plus orientées données, mais veulent aussi garder ma belle interface utilisateur.
Par exemple:
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...
}
Ainsi, l'utilisateur peut travailler avec des pointeurs d'interface dans son code.
et Dans mon moteur, je stocke actuellement des pointeurs vers des noeuds de scène.
boost::ptr_vector<SceneNode> m_nodes
Ainsi, dans la conception orientée données, il est bon d'avoir struct de tableaux et non des tableaux de struct. Donc, mon noeud obtient de ...
class SceneNode
{
private:
Math::Vec3d m_pos;
};
std::vector<SceneNode> m_nodes;
à cette ...
class SceneNodes
{
std::vector<std::string> m_names;
std::vector<Math::Vec3d> m_positions;
// and so on...
};
Je vois deux problèmes ici si je veux appliquer DOP. Tout d'abord comment pourrais-je garder ma belle interface utilisateur sans avoir à l'utilisateur de travailler avec les ID, index, etc.?
En second lieu, comment puis-je gérer la délocalisation des propriétés lorsque certains vecteurs redimensionnez sans laisser l'interface utilisateurs pointeurs pointer vers le nirvana?
Actuellement, mon idée est de mettre en œuvre une sorte de handle_vector à partir duquel vous obtenez une poignée pour « pointeurs » persistants:
typedef handle<ISceneNodeData> SceneNodeHandle;
SceneNodeHandle nodeHandle = nodeHandleVector.get_handle(idx);
Alors, quand le stagiaire std :: vecteur redimensionne, il met à jour ses poignées. A magasins « poignée » un pointeur sur l'objet réel et le « -> » opérateur est surchargée pour achive un emballage agréable. Mais cette approche semble un bis compliqué pour moi?!
Que pensez-vous? Comment garder une interface agréable, mais gardez pense contigus dans la mémoire pour une meilleure utilisation du cache?
Merci pour toute aide!
La solution
Vous aurez besoin d'utiliser des poignées plus intelligent que les pointeurs premières. Il n'y a pas moyen de contourner avec DOP.
Cela signifie:
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;
};
Un très bon point cependant: l'utilisateur ne peut pas appeler par mégarde sur un delete
du pointeur vous revenez maintenant. C'est pourquoi les poignées intelligentes sont toujours mieux.
D'autre part: comment allez-vous faire face à la durée de vie du mManager
de est pointée une autre question: -)
Autres conseils
Pour les personnes intéressées par un exemple concret de DOP, jetez un oeil à cette présentation fantastique de Niklas Frykholm => http://bitsquid.blogspot.com/2010/05/practical-examples-in-data-oriented.html
Cela m'a aidé à mettre en œuvre mon graphe de scène d'une manière orientée données.