Simplizität vs. Flexibilität
-
hallo zusammen,
habe ein mächtiges design problem. vorab der thread könnte auch in "rund um" oder "spiele programmierung" stehen falls die mod's der meinung sind dann tut euch keinen zwang an.

so wie so ziemlich alle suche ich nach einem guten design für eine bibilothek.
mein problem das ich meine engine nach einem "herkömmlichen" engine design, wie
zb: ogre, ursprünglich mit abstrakten klassen oder virtuellen klassen geplant war und vom benutzer mittels plugin's oder benutzer klassen überschrieben werden sollte. dieses steht natürlich voraus das der benutzer objekte selber erstellt und diese dann entsprechend verteilt.
in etwa soclass Engine // abstrakte klasse { public: Engine(); virtual ~Engine(); protected: WindowUserInterface *m_pWUI; Renderer *m_pRenderer; SceneGraph *m_pSceneGraph; }; class Game : public Engine { public: bool Init() { // objekt entweder von einer benutzer klasse // oder plugin oder defaultklasse // der bibilothek erstellen m_pWUI = new WindowUserInterfaceWin32; // .. m_pRenderer = new Renderer(); m_pRenderer->SetTargetWindow(m_pWUI); // .. m_pSceneGraph = new SceneGraph(); // .. m_pSceneGraph->SetRenderer(m_pRenderer); // .. } };jetzt würde ich zweite möglichkeit, mittels poliycs im weittesten sinne, vorziehen
template< class _Wui, template <class, class> class _Renderer, class _RendererSettings, template <class> class _SceneGraph> class Engine { public: Engine() : m_Renderer(&m_WUI), m_SceneGraph(&m_Renderer) { } virtual ~Engine() { } protected: _Wui m_WUI; _Renderer<_Wui, _RendererSettings> m_Renderer; _SceneGraph<_Renderer<_Wui, _RendererSettings> > m_SceneGraph; }; typedef Engine< DefaultWui, Renderer, DefaultRendererSettings, SceneGraph> DefaultEngine; class Game : public DefaultEngine { // .. };meine bedenken liegen darin das ich den benutzer mittels den vielen templates erschlage. zb würde ich render eigenschaften über poliycs festlegen statt zur laufzeit diese zu bestimmen. wie zb culling modus der renderes, shading modus, buffer (stencil usw), usw usw. mir ist auch klar das einige dinge nicht schlecht wären wenn man sie zur laufzeit änderen aber diese könnte man ja wieder in policys packen. somit würde ich für den renderer sechs bis zehn templates parameter schätzen was natürlich sehr viel ist.
welches design würde ihr vorziehen? eine begründung wäre nicht schlecht

vielleicht fällt irgend jemanden ein entscheidenen vor- bzw nachteil ein.
-
Nimm nen Generator.
Du schreibst ne GeneratorKlasse die mit wenigen eingabedaten dir eine Config Klasse ausspuckt die alle nötigen typedefs hat.
So kann jeder der will selber so eine Config Klasse machen und die richtigen typedefs setzen, und wer das nicht will verwendet den Generator:
class Game : public Engine <BasicOpenGLGenerator<DynamicEffects::True, Shader::Level1, NullPolicy, NullPolicy> > {...}sowas ist super benutzbar.
solche Generatoren werden aber leider viel zu selten verwendet

-
hab ich mir schon das du dafür bist.

Shade Of Mine schrieb:
Du schreibst ne GeneratorKlasse die mit wenigen eingabedaten dir eine Config Klasse ausspuckt die alle nötigen typedefs hat.
So kann jeder der will selber so eine Config Klasse machen und die richtigen typedefs setzen, und wer das nicht will verwendet den Generator:so etwas ähnliches hätte ich dann auch vorgehabt zu erstellen bzw ich habe so etwas ähnliches für die einstellungen des renderes gemacht (auf papier)
ich werde natürlich auch mehrere mögliche "einstellungen" mittels typedefs
vorschlagen in der der user einfach auswählt und trotzdem flexibel für eigene ideen bleibt falls im etwas nicht zusagt.
aber nach wie vor drängt sich mir die frage nach der template flut auf die auch bei einer solchen generator klasse ziemlich hoch ist.
-
miller_m schrieb:
aber nach wie vor drängt sich mir die frage nach der template flut auf die auch bei einer solchen generator klasse ziemlich hoch ist.
Du meinst die ganzen Policies?
Für dich ist es eine Flut, aber für den Anwender nicht, weil du ja schon die meisten Sachen implementierst.Oder meinst du die vielzahl der Templateparameter?
Ja, dafür hast du die Generatoren die jeweils nur 3 - 5 params haben also nicht so kompliziert sind.Du kannst natürlich auch ein paar Policies zusammen legen, wenn sie einander ähnlich sind. Beispiel:
Kein CompareLess, CompareEqual, CompareGreater sondern nur 1 Policy Compare.Oder meinst du mit Templateflut doch etwas anderes...?
-
Shade Of Mine schrieb:
Oder meinst du die vielzahl der Templateparameter?
Ja, dafür hast du die Generatoren die jeweils nur 3 - 5 params haben also nicht so kompliziert sind.genau das meine ich, ich bin der meinung das ich damit einen user der bibilothek überforden könnte. oder ich mach mir einfach nur zu viele gedanken. die frage ist nur wieder warum machen es dann zb die leute von ogre, irrlicht oder neo oder was auch immer nicht so? bsp: wieso sollte meine engine shader unterstützen wenn gerade nichst mit shadern gemacht wird, natürlich ist dies zur laufzeit meistens nur eine abfrage aber genau diese macht keinen sinn. den die template variante bringt meiner meinung nach nur vorteile bis auf meine bedenken mit der anzahl der parameter die sich aber langsam verflüchtigen.
-
miller_m schrieb:
die frage ist nur wieder warum machen es dann zb die leute von ogre, irrlicht oder neo oder was auch immer nicht so?
Kenne mich da leider nicht aus, aber viele Libraries sind alt und nutzen die Features von C++ nicht besonders gut aus.
Manche wollen auch übermäßig kompatibel mit alten Compilern sein...
Ich würde ein Policybased Design aber erstmal als gut betrachten. Denn was spricht denn wirklich dagegen? Dass der User den es interessiert sich mit zig Template parameter rumschlagen muss: ja. Aber das macht man genau 1mal, danach hat man die richtigen Parameter. Und wenn ich das nicht will, nehme ich eins von deinen Defaultsets.
Wie handhabt man denn die Features die aktiviert sein sollen bei anderen Engines? Habe noch nichts mit Grafikprogrammierung gemacht.
bsp: wieso sollte meine engine shader unterstützen wenn gerade nichst mit shadern gemacht wird, natürlich ist dies zur laufzeit meistens nur eine abfrage aber genau diese macht keinen sinn.
Hängt davon ab. Viele sachen will man sicher erst zur runtime setzen, weil der user sie ein und abschalten kann. aber da kenne ich mich nicht aus...
den die template variante bringt meiner meinung nach nur vorteile bis auf meine bedenken mit der anzahl der parameter die sich aber langsam verflüchtigen.
WIe gesagt: ein paar Defaultsets + ein paar gute Generatoren und der User hat es nicht mehr mit Templates zu tun, sondern mit einem Config Framework.
Ich finde nämlich folgendes kein bisschen abschreckend:
class Game : public Engine < DefaultConfig< VisualEffects::enabled, Audio::ThreeD, SomeStuff::disabled > >dass DefaultConfig sehr komplex ist merkt der User garnicht, er setzt die Parameter einfach. Da ist eigentlich nichts kompliziertes dabei.
Ist genau wie
vector<shared_ptr<int> > v;
sort(v.begin(), v.end());das ist auch extrem komplex, weil du ja templates, iteratoren, refcounting etc. hast. aber der user merkt nichts...
-
Shade Of Mine schrieb:
Kenne mich da leider nicht aus, aber viele Libraries sind alt und nutzen die Features von C++ nicht besonders gut aus.
Manche wollen auch übermäßig kompatibel mit alten Compilern sein...könnten natürlich gründe sein
Shade Of Mine schrieb:
Wie handhabt man denn die Features die aktiviert sein sollen bei anderen Engines? Habe noch nichts mit Grafikprogrammierung gemacht.
ich kenne es, von ein paar open source engines die ich mir angeschaut habe,
das so ziemlich jede technik und feature implementiert wird und der benutzer
mittels enums entscheidet was er wie benutzen möchte, sprich nen haufen getter/setterShade Of Mine schrieb:
Hängt davon ab. Viele sachen will man sicher erst zur runtime setzen, weil der user sie ein und abschalten kann. aber da kenne ich mich nicht aus...
ist klar aber ich denke das sich vieles auch von anfang an mit einer vernüftigen planung umsetzen lässt. shader waren jetzt ein blödes beispiel.
bsp: culling mode. warum sollte ich den culling modus zur laufzeit verändern
sollen, macht meiner meinung nach keinen sinn ich könnte ja meine modele alle
einheitlich erstellen somit wäre dieses problem gelösst.noch ein punkt fällt mir, das updaten.
folgendes szenario (gehe zwar nicht davon aus das irgend jemand meine engine benutzen wird, aber gedanken sollte man sich trotzdem machen):ein benutzer meiner "herkömmlichen" engine erstellt ein spiel mit dieser und
stellt einen bug fest, teilt mir diesen mit und ich ändere dieses und lasse
im dann die geänderte dll zukommen die er dann weiter an seinen kunden gibt.
nicht sehr viel probleme und alle ist gut.bei der template variante könnte ich keine dll erzeugen sondern müsste dem benutzer die entsprechenden dateien zukommen lassen und dieser kompiliert sein spiel auf ein neues und gibt dieses weiter. egal wie ich es mache er müsste die
neuen dateien immer mit reinkompilieren.was hälst du davon?
-
miller_m schrieb:
das so ziemlich jede technik und feature implementiert wird und der benutzer
mittels enums entscheidet was er wie benutzen möchte, sprich nen haufen getter/setterDachte ich mir. Da hast du doch auch einen enormen umfang an settern, oder? Da sind die Generatoren sogar freundlicher

noch ein punkt fällt mir, das updaten.
Klar, durch Templates verlierst du die modularitaet. Daran hatte ich nicht gedacht, ich bin Programmiertechnischer Sicht an die Sache gegangen.
Sowas ist bei Spielen vermutlich ein grosses Problem, weil man oefter Patches released als bei einer normalen Anwendung. Da musst du halt echt abwegen...
Aber wie gesagt: auf diesem Gebiet kenne ich mich nicht aus.
-
Shade Of Mine schrieb:
Dachte ich mir. Da hast du doch auch einen enormen umfang an settern, oder?
im moment noch nicht da ich noch so viele features habe.

aber es würde wohl darauf hinausgelaufen.naja du hast mir schon weitergeholfen ich werde mich vermutlich, noch eine nacht darüber schlafen, für das template design entscheiden.

-
hey shade,
bräucht nochmal deine hilfe oder falls jemand anders sich auch damit beschäftigen möchte nur zu.
mein scenegraph war im groben zügen in etwa so aufgebaut das der scenegraph alle nodes instanziert. jedes node kann verschiedene objekte annehmen die alle von der abstrakten klasse Obj erben. im groben so (nicht auf fehler oder design achten habe jetzt einfach mal schnell zusammengeschrieben)class Obj { public: virtual ~Obj() { }; virtual void Render(Renderer *pRenderer) = 0; }; class Bar : public Obj { public: void Render(Renderer *pRenderer) { std::cout << "nur nen test" << std::endl; } }; class Node { public: bool AddChild(const std::string &strName, Node *pChild) { return m_ChildNodes.insert(NodeList::value_type(strName, pChild)).second; } bool AttachObject(const std::string &strName, Obj *pObj) { return m_ObjLstName.insert(ObjectList::value_type(strName, pObj)).second; } void Render() { ObjectList::const_iterator itObj; for(itObj = m_ObjLstName.begin(); itObj != m_ObjLstName.end(); ++itObj) itObj->second->Render(); NodeList::iterator itChild; for(itChild = m_ChildNodes.begin(); itChild != m_ChildNodes.end(); ++itChild) itChild->second->Render(); } private: typedef std::map<std::string, Node*> NodeList; typedef std::map<std::string, Obj*> ObjectList; ObjectList m_ObjLstName; NodeList m_ChildNodes; }; class SceneGraph { public: SceneGraph() { m_pRootNode = CreateSceneNode("root"); } Node *CreateSceneNode(const std::string &strName) { Node *pNode = new Node(); m_SceneNodes.insert(SceneNodeList::value_type(strName, pNode)); return pNode; } Node *GetRootNode() { return m_pRootNode; } private: typedef std::map<std::string, Node*> SceneNodeList; SceneNodeList m_SceneNodes; Node *m_pRootNode; };das ganze hatte den vorteil das der graph alle nodes kannte und ich für die schatten berechnung nicht den ganzen baum nochmal zu travieriseren musste sondern alle nodes schon parat habe. (war noch nicht implementiert aber so gedacht
)
jetzt habe ich ein problem mit dem templatesieren (neues wort
) diesen graphen
bsp: die renderer klasse wurde jetzt mit policys erweitert somit würde meine pure virtuelle methode in obj nicht mehr hinhauen denn ich müsste ja eine template als parameter übergeben, aber templates und virtual gehen ja afaik nicht, den templates werden zur compiletime aufgelösst während das virtual ja erst von der laufzeitumgebung überschrieben wird. jetzt zerbreche ich mir schon ne ganze weile den kopf wie ich den graphen und die nodes möglichst einfach und generisch umbauen kann, aber mir fällt nichst ein. ich erwarte mit sicherheit keine musterlösung sondern nur ein wink in die richtig
-
Vielleicht hilft das: http://schornboeck.net/artikel/virtual_template.htm
-
ich werd es mir mal durchlesen. danke
[ot]
warum wird die seite nicht in deiner inhalt.htm angezeigt
bis jetzt bin ich noch nicht darauf gestossen