Designproblem



  • Irgendwie hab ich da gerade nen Balken vorm Kopf 😉

    struct foo
    {
        float data;
        enum { fvf = (D3DFVF_XYZ) };
    };
    
    struct bar : foo
    {
    	float extra_data;
    	enum { fvf = (D3DFVF_XYZ | D3DFVF_TEX1) };
    };
    

    ... jetzt hab ich eine Basisklasse in der ich eine virtuelle Funktion habe, die sizeof und dann foo oder bar braucht. Ob es foo, bar oder ne andere, von foo abgeleitete Struct ist, legt dann aber die abgeleitete Klasse fest... Wie kann ich das am besten machen? 😞



  • (D)Evil schrieb:

    ... jetzt hab ich eine Basisklasse in der ich eine virtuelle Funktion habe, die sizeof und dann foo oder bar braucht. Ob es foo, bar oder ne andere, von foo abgeleitete Struct ist, legt dann aber die abgeleitete Klasse fest...

    Bitte präzisiere das ein wenig.



  • nja hab halt noch ne Klasse fooObj

    class fooObj
    {
        virtual void show_data() { std::cout << sizeof(/* was hier */) << std::endl;
    };
    
    class barObj : public fooObj
    {
        /* was hier */
    };
    

    ... es soll halt erst in barObj das genau spezifiziert werden, wovon ich die Größe(sizeof) haben will ... Dachte erst an Pointer (fooObj hat ptr foo*, barObj setzt diesen dann auf barObj ...) geht aber nicht so gut ... zumindest kommt mir gerade nichtin den Sinn wie ich es am besten realisieren sollte. Templates geht nicht, da fooObj mein Interface ist, das ich im std::vector brauche ...


  • Mod

    Wahrscheinlich schlechtes Design. Aber nichts hindert dich, show_data erst zu definieren, wenn du eine Definition barObj gesehen hast. Man muss ja nicht jede Memberfunktion gleich bei der Definition der Klasse mitdefinieren.



  • ja sicher ich kann es in barObj noch definieren ... wollte aber halt, der faulheit halber, verhindern, dass man die funktion noch selbst schreiben muss ^^



  • ich denke am besten oder einfachsten wäre folgendes:

    class foo
    {
    public:
      foo() : m_Size(sizeof(foo)) { };
      virtual void dosth() { cout << m_size << endl; };
    
    protected:
      size_t m_Size;
    };
    
    class bar : public foo
    {
      bar() : foo() { m_Size = sizeof(bar); };  // init-liste geht hier nicht, weil du in der initlist nicht auf geerbte member kannst.
    }:
    

    wäre ne einfache möglichkeit


  • Mod

    Darf man fragen, wozu das Ganze gut sein soll? sizeof benötigt man typischerweise nur, um bestimmten low-level Zugriff auf Speicher zu erhalten - und gerade das ist dir bei polymorphen Typen sowieso verwehrt.



  • Vermutung:
    Es geht wahrscheinlich darum, dass jede abgeleitete Klasse noch mehr vertexdaten wie texturkoordinaten etc speichert. Wenn man die nun in den vertexbuffer kopieren will, braucht man die größe der Vertexdaten. das Problem ist nur, dass diese Klassen keine PODs mehr sind, und man sie deswegen eh nicht in den Vertexbuffer kopieren kann.


  • Mod

    otze schrieb:

    Vermutung:
    Es geht wahrscheinlich darum, dass jede abgeleitete Klasse noch mehr vertexdaten wie texturkoordinaten etc speichert. Wenn man die nun in den vertexbuffer kopieren will, braucht man die größe der Vertexdaten. das Problem ist nur, dass diese Klassen keine PODs mehr sind, und man sie deswegen eh nicht in den Vertexbuffer kopieren kann.

    Also geht es im Prinzip um den Versuch, eine Basisklasse etwas tun zu lassen, was sie mangels Information (weil diese spezifische Information - wie sind Daten zu kopieren - hier nicht Teil des Interfaces ist) gar nicht in der Lage ist, zu tun.



  • Hmm otze, deine Vermutung ist korrekt. Hab nicht drang gedacht, das es POD's sein müssen. Wie könnte man es denn sonnst effektiv lösen?

    #if !defined(TEST_VERTEX_H__INCLUDED)
    #define TEST_VERTEX_H__INCLUDED
    
    #if (_MSC_VER >= 1300)
    #pragma once
    #endif // (_MSC_VER >= 1300)
    
    struct TestVertex
    {
        FLOAT x;
    	FLOAT y;
    	FLOAT z;
    	std::size_t	data_size;
    	enum { fvf = (D3DFVF_XYZ) };
    	TestVertex(std::size_t data_size = sizeof(TestVertex)) : x(0.0f), y(0.0f), z(0.0f), data_size(data_size) {}
    };
    
    struct TestVertexTexture : TestVertex
    {
    	FLOAT texture_x;
    	FLOAT texture_y;
    	enum { fvf = (D3DFVF_XYZ | D3DFVF_TEX1) };
    	TestVertexTexture() : texture_x(0.0f), texture_y(0.0f), TestVertex(sizeof(TestVertexTexture)) {}
    };
    
    struct TestVertexDiffuse : TestVertex
    {
    	DWORD color;
    	enum { fvf = (D3DFVF_XYZ | D3DFVF_DIFFUSE) };
    	TestVertexDiffuse() : color(D3DCOLOR_XRGB(0, 0, 0)), TestVertex(sizeof(TestVertexDiffuse)) {}
    };
    
    #endif // TEST_VERTEX_H__INCLUDED
    

    edit
    hatte quatsch geschrieben 😉


  • Mod

    (D)Evil schrieb:

    wie soll ich es sonnst lösen? Wie sehe dein Vorschlag aus?

    Zeig bitte erst mal, wie es angewendet werden soll. Schließlich ist das ja der eigentliche Ausgangspunkt jedes Designs.



  • Nja ... halt Basis TestVertex ... kommt immer drauf an, was man braucht ... manchmal einfach farbe, nen anderes mal soll ne textur drauf ... dann wiederum brauch ich noch normalen usw.

    class TestRenderableObject : public TestObject
    

    ...

    void TestRenderableObject::render() const
    {
    	if (m_ppVertexBuffer == NULL || m_ppIndexBuffer == NULL)
    		throw direct3d_error("Invalid data buffer!");
    
    	TestDirect3D& inst = TestDirect3D::instance();
    	inst.get_device()->SetStreamSource(0, m_ppVertexBuffer, 0, sizeof(/*VertexType*/));
    	inst.get_device()->SetFVF(/*VertexType*/::fvf);
    	inst.get_device()->SetIndices(m_ppIndexBuffer);
    	inst.get_device()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_countVertex, 0, m_countIndex);
    }
    

    ... könnte natürlich auch jedes Objekt seine render-funktion selbst schreiben lassen ... muss nicht ...



  • IMO gehört die Render Funktion sowieso nicht ins 3D-Objekt rein, sondern das 3D-Objekt sollte genügend Daten nach aussen zugänglich machen dass man "von extern" rendern kann.
    Spätestens wenn ein Objekt mal aus mehreren Meshes bestehen kann, du nach Textur(en) sortieren willst, oder Alpha-Blending verwenden, wird das wohl lästig werden wenn das Objekt sich selbst rendert.

    Wenn du dabei bleiben willst mach doch einfach eine virtuelle Funktion:

    // ...
        struct VertexFormatInfo
        {
            size_t m_vertexSize;
            uint32_t m_vertexFormat;
        };
        virtual void GetVertexFormat(VertexFormatInfo& vfi) = 0;
        // ...
    


  • Hmm ... naja vom logischen her, ist es eine Funktion des Objektes. Natürlich könnte ich den Vertex und Index-Buffer per Getter/Setter in ObjectManager beim rendern abfragen und dann nutzen ... aber wäre unlogisch 😕



  • am besten wäre es, wenn du den Vertexbuffern überlässt, wie sie die daten, die sie verwalten zu rendern haben. Die Buffer verwalten dann einfach nur einen Datenblock mit den informationen, welches format und welche größe die Daten haben.

    Direktzugriff auf die Daten ist dann ein wenig Kniffliger, zumindest wenns typsicher sein soll, aber das kriegt man auch noch irgendwie hin 🙂



  • ? Wie meinst de jetzt? Soll ich ne Vertex und Index-Buffer-Klasse anlegen, die dann selbst das Format ihrer Daten speichert? Hmm ...


Anmelden zum Antworten