# Wie variable anzahl an Instanzen eines structs zur Laufzeit erstellen?



## Crymes (8. Juni 2012)

Hallo, ich möchte beliebige anzahl an Bällen erstellen, mein struct sieht os aus:

```
[FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]struct[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] kugel[/SIZE][/FONT]
[SIZE=2][FONT=Consolas]{[/FONT][/SIZE]
[/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]float[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] position[2];[/SIZE][/FONT]
[/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]float[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] geschwindigkeit[2]; [/SIZE][/FONT]
[/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]float[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] radius;[/SIZE][/FONT]
[SIZE=2][FONT=Consolas]};[/FONT][/SIZE]
[/SIZE][/FONT]
```
 
Ich habe schon gegoogelt, ich brauche soweit ich gelesen hab einen variablen array, z.B. ball[nummer].
Wo muss aber jetzt das new hin und wie handle ich das wieder mit dem löschen?

Würde so eine Schleife gehen:

for(x=0;x<nummer;x++)
{
ball[x] = new(kugel)
}

Oder hab ich das falsch verstanden?


----------



## bingo88 (8. Juni 2012)

Kleines Beispiel

```
struct Ball
{
    int posX;
    int posY;
};

// erzeugt dynamisch 10 Bälle
Ball *pBaelle = new Ball[10];

// Zugriff auf den 2. Ball (Index beginnt bei 0)
pBaelle[1].posX = 1;
pBaelle[1].posY = 1;

// Löschen (mit [], da es sich um ein Array handelt)
delete[] pBaelle;
```


----------



## Crymes (8. Juni 2012)

Wenn ich jetzt in ner Funktion damit rechnen will, zeige ich dann mit einem Pointer auf einen Pointer?


----------



## xEbo (8. Juni 2012)

Bei dynamischen Objekten empfiehlt es sich aus den Instanzen eine Liste zu machen. Das Problem was auftritt wenn du einenen Array anlegst, du kannst nicht einfach Objekte löschen. Ein Ball der bspw. auf einem Spielfeld ist bleibt nicht zwingend auf dem Spielfeld und muss ggf. "zerstört" werden.
Daher nimmst du deine Struktur und setzt ein oder 2 neue pointer. Die Pointer zeigen dann immer auf das nächste oder vorhergende Objekt. Nennt sich dann verkettete Liste. Du musst dann nurnoch das erste Objekt in der Liste speichern und kannst von dort aus die gesamte Liste durchgehen und deine Attribute setzen. Ein neues Element hinzufügen ist keine Problem, eines entfernen auch nicht. Mit einem new [] ist das so ohne weiteres nicht leicht zu realisieren.

Ein kleiner Hinweis am Rande: der Befehl new ist C++ Sprachraum während struct C Sprachraum ist. Beides vermischen ist kein guter Stil und kann unter anderem die Portierbarkeit deines Codes einschränken. Daher entweder C++ class nehmen oder malloc() für C.


----------



## bingo88 (8. Juni 2012)

> Ein kleiner Hinweis am Rande: der Befehl new ist C++ Sprachraum während  struct C Sprachraum ist. Beides vermischen ist kein guter Stil und kann  unter anderem die Portierbarkeit deines Codes einschränken. Daher  entweder C++ class nehmen oder malloc() für C.


Nein. In C++ ist struct dasselbe wie class, nur das per Default alle Attribute bei struct public sind.


```
struct BlaStruct
{
    int x;
    void methode();
};

class BlaClass
{
public:
    int x;
    void methode();
};
```
Beide Objekte sind in C++ vollkommen äquivalent.




> Wenn ich jetzt in ner Funktion damit rechnen will, zeige ich dann mit einem Pointer auf einen Pointer?


Kannst du machen


```
void funktion(Ball *pBall)
{
   // whatever...
}

void multifunktion(Ball *pBaelle, int anzahl)
{
   for (int i = 0; i < anzahl; ++i)
   {
       pBaelle[i].posX = i;
       pBaelle[i].posY = (i + 1) / 2;
   }
}



Ball *pBaelle = new Ball[10];
// Aufruf für einen Ball (hier muss mittels des Adressoperators & die Adresse übergeben werden, da pBall[0] kein Zeiger mehr ist)
funktion(&pBaelle[0]);

// Aufruf für das gesamte Array
multifunktion(pBaelle, 10);
```


----------



## Crymes (8. Juni 2012)

Es soll darauf hinaus, dass ich bei dem Druck eioner Taste einen Bal hinzufüg und bei dem Druck auf eine andere einen löschen kann.
Ich werde das mit den Listen ma nachschauen.


----------



## xEbo (8. Juni 2012)

Dann sind Listen genau das richtige weil die Anzahl Bälle variabel ist und du sonst immer ein Array brauchst mit einer statischen Anzahl Felder.


----------



## Crymes (8. Juni 2012)

Kann mir jemand ne gute Quelle nennen, wo die Listen gut erklärt sind?


----------



## retarDeD.aNiMaL (8. Juni 2012)

http://perlgeek.de/de/artikel/doppelt-verkettete-listen

Ansonsten bieten modernere Programmiersprachen auch schon fertige Konstrukte dazu. Z.b. List<> in c#. Da kann man einfach mit "add" was hinzufügen.


----------



## hardware_fanatiker (8. Juni 2012)

Ich weiss nicht genau, wie es mit der Performance bei c++ aussieht, aber arbeiten lässt sich auf jeden fall sehr schön mit vector.(http://www.highscore.de/cpp/aufbau/cppstandard.html#cppstandard_container) und wenn du das gelesen hast, kannste dir die restlichen nützlichen Funktionen außen Standard zusammen suchen.


----------



## Mashed (8. Juni 2012)

Crymes schrieb:


> Wenn ich jetzt in ner Funktion damit rechnen will, zeige ich dann mit einem Pointer auf einen Pointer?


 
Kannst du machen, ist aber nicht notwendig und verwirrt eher. Es reicht, wenn du den Pointer direkt übergibst. Ein Pointer ist ja nichts anderes als eine bestimmte Adresse im Speicher, also eine natürliche Zahl, die du als Wert übergeben kannst. Einen Pointer auf einen Pointer bräuchtest du nur, wenn du was daran ändern willst, wo der Pointer hin zeigt.
Dieses Beispiel verdeutlicht den Zusammenhang(einfach mal ausprobieren):

```
#include <iostream>
using namespace std;
int* array; // wird dynamisch angelegt
void f(int* ptr)
{
  *ptr = 1234;
  cout << ptr << endl << array <<endl;
}
int main(void)
{
   array = new int[3];
   array[0] = 0;
   cout << array;
   f(array);
   return 0;
}
```


----------



## retarDeD.aNiMaL (10. Juni 2012)

Crymes, alles hinbekommen? ansonsten nochmal melden


----------



## Crymes (10. Juni 2012)

Ich schau mir das grad mit dem vector Template an, da ist ja eigentlich alles, was ich brauche schon vordefiniert.
Hab aber grad nicht so viel Zeit, da ich mit 2 Vorträgen ein bisschen spät dran bin .


----------



## Crymes (12. Juni 2012)

Kann mir jemand sagen, warum bei folgender Zeile der Modulu Operator nicht funktioniert? (Ich will aus dem Container vector(ball) ein zufälliges element löschen)

ball.erase((rand() % ball.end()));


----------



## bingo88 (12. Juni 2012)

end() liefert einen Iterator und keine Zahl, daher klappt das nicht. Die Anzahl der Elemente erhälst du mit size().


----------



## Crymes (12. Juni 2012)

ballliste.erase(rand() % ballliste.size());

Dann kommt der Fehler:  
error C2664: 'std::_Vector_iterator<_Myvec> std::vector<_Ty>::erase(std::_Vector_const_iterator<_Myvec>)': Konvertierung des Parameters 1 von 'unsigned int' in 'std::_Vector_const_iterator<_Myvec>' nicht möglich

Ist es hier vll. ratsam, eine funktion für dien zufallszahlern zu Schreiebn? Dann hätt ich halt wieder eine unnötige Variable mehr


----------



## bingo88 (12. Juni 2012)

Top, der braucht für erase einen Iterator, das habe ich grade übersehen -.-

Versuch das mal:

```
Vector v;
// ...

// Position bestimmen
size_type pos = rand() % v.size();
// löschen
v.erase(v.begin() + pos);
```


----------



## Crymes (12. Juni 2012)

size_type wird rot unterstrichen, is bei ihm nicht definiert.
Das würde gehen:

int x = rand() % ballliste.size();
ballliste.erase(ballliste.begin() + x );

Dann hab ich halt wieder eine überflüssige Variable.

Edit: Wenn ich es folgendermaßen mache, dann können doch alle Elemente des vectors ausgewählt werden, oder?

unsignedshortint zufallszahl = rand() % (ballliste.size()+1);
ballliste.erase(ballliste.begin() + zufallszahl );


Edit 2: Habs nachgerechnet, ohne das +1 stimmts, sonst würde er ein Element zu viel im vector vermuten, richtig?


----------



## bingo88 (12. Juni 2012)

Ich dachte, size_type wäre ein typedef wie size_t. Normalerweise zeigt das auf unsigned int, daher ist das ok.


----------



## Crymes (12. Juni 2012)

Das ist jetzt meine fertige Lösch -Funktion:


```
[FONT=Consolas][SIZE=2][COLOR=#008000][FONT=Consolas][SIZE=2][COLOR=#008000][FONT=Consolas][SIZE=2][COLOR=#008000]
//funktion Ball entfernen[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]void[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] deleteball()
{
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]unsigned[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]short[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]int[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] zufallszahl = ballliste.size(); 
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]if[/SIZE][/FONT][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2](zufallszahl > 0)
{
zufallszahl = rand() % zufallszahl; 
ballliste.erase(ballliste.begin() + zufallszahl);
}
}
[/SIZE][/FONT][/SIZE][/FONT]
```
 
Sollte fehlerfrei funktionieren.
Die addball Funktion wird deutlich komplizierter, da ich erst npoch prüfen muss, wo auf dem Bildschirm genug Platz für einen neuen Ball ist.


----------



## Crymes (16. Juni 2012)

Nochmal ne Frage, bin grad auf Fehlersuche bei meinem Programm, an Quelltext hätte ich jetzt alles zusammen und vernetzt:
Funktioniert folgender Code bzw. wofür brauche ich die Klammern hinter ball? (Ball ist ein structure)


```
[FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2]
ballliste.push_back(ball());
[/SIZE][/FONT][/SIZE][/FONT]
```


----------



## DarkMo (18. Juni 2012)

bingo88 schrieb:


> Kleines Beispiel
> 
> ```
> struct Ball
> ...


 hi, ich hatte schon ne andere (ähnliche) lösung probiert und jetzt nochmal die hier, aber er will bei mir die so erzeugten arrays einfach nich gescheit füllen :/

zur "vorgeschichte":
ich hab ne klasse die objekt daten vorhält. also koordinaten, farben, tex koords usw. das wird entweder aus ner *.obj datei gelesen (nach deren struktur ich mich auch orientiert hatte) oder aber aus create... funkrionen. hab testweise ne createCube() gebaut und die punktdaten usw stimmen auch, so wie ich mir das erstmal gedacht hatte. joa, die klasse besitzt nun mehrere listen. einmal die vektorenliste (pointlist), wo alle punktdaten halt gespeichert sind und dann noch listen für texcoords, normalen und farben (auch wenn die später wohl wieder rausfliegt um nahe bei der obj-datei struktur zu bleiben). das sin dann die vnlist (normalen), vtlist (texcoords) und vclist (colors). so, jede dieser listen beinhaltet alles nur einmalig. also wenn 3 flächen den selben punkt nutzen, is er dennoch nur einmal aufgeführt. desweiteren gibts eine flist für die flächen, und hier wird nur der index jeweils gespeichert. also bei den punkten hat man dann eben flist.points[0]=0. soll bedeuten, der punkt 1 (0) der fläche (points is nen int[3]) ist der punkt mit dem index 0 aus pointlist (vector liste) -> pointlist[0]. mit all den anderen dingern das selbe.

najut, jedenfalls fülle ich nun mittels for schleifen (eine äussere, die die flächenliste durchgeht und innere, die dann die werte raussuchen) diese pointer-arrays, die mittels calloc oder deiner methode da gebastelt wurden. allerdings wird jedesmal nur der allererste wert gespeichert, und das wars :/


```
struct Face
{
public:
    Texture tex;                        // textur der fläche
    int Points[3];                        // indizes der 3 punkte
    int TexCoords[3];                    // indizes der 3 texcoords
    int Normals[3];                        // indizes der 3 normalen
    int Colors[3];                        // indizes der 3 farben
    M3DVector3f vNormal;                // berechnete flächennormale
    Edge vEdges[3];                        // kanten, aus denen die fläche besteht
    ...
};

void Objectloader::generateBatch(void) {
    // wir haben flist.size flächen
    // pro fläche haben wir 3 vertizes
    // jedes vertex besteht aus 3d punkt, 3d normale, 2d texcoord und 4d farbe - jeweils float
    int vCount = this->flist.size() * 3 * 3;
    int nCount = this->flist.size() * 3 * 3;
    int tCount = this->flist.size() * 3 * 2;
    int cCount = this->flist.size() * 3 * 4;

    float *vPtr = (float*)calloc(vCount, sizeof(float));
    float *nPtr = (float*)calloc(nCount, sizeof(float));
    float *tPtr = (float*)calloc(tCount, sizeof(float));
    float *cPtr = (float*)calloc(cCount, sizeof(float));

    /*float *vPtr = new float[vCount];
    float *nPtr = new float[nCount];
    float *tPtr = new float[tCount];
    float *cPtr = new float[cCount];*/

    // arrays mit daten der flächen füllen
    for(int i = 0; i < this->flist.size(); i++) {
        for(int j = 0; j < 3; j++) {
            vPtr[(i*9)+(j*3)]   = this->pointlist[this->flist[i].Points[j]].x;
            vPtr[(i*9)+(j*3)+1] = this->pointlist[this->flist[i].Points[j]].y;
            vPtr[(i*9)+(j*3)+2] = this->pointlist[this->flist[i].Points[j]].z;

            nPtr[(i*9)+(j*3)]   = this->vnlist[this->flist[i].Normals[j]].x;
            nPtr[(i*9)+(j*3)+1] = this->vnlist[this->flist[i].Normals[j]].y;
            nPtr[(i*9)+(j*3)+2] = this->vnlist[this->flist[i].Normals[j]].z;
        }
        for(int j = 0; j < 3; j++) {
            tPtr[(i*6)+(j*2)]   = this->vtlist[this->flist[i].TexCoords[j]].x;
            tPtr[(i*6)+(j*2)+1] = this->vtlist[this->flist[i].TexCoords[j]].y;
        }
        for(int j = 0; j < 3; j++) {
            cPtr[(i*12)+(j*4)]   = this->vclist[this->flist[i].Colors[j]].x;
            cPtr[(i*12)+(j*4)+1] = this->vclist[this->flist[i].Colors[j]].y;
            cPtr[(i*12)+(j*4)+2] = this->vclist[this->flist[i].Colors[j]].z;
            cPtr[(i*12)+(j*4)+3] = this->vclist[this->flist[i].Colors[j]].w;
        }
    }

    glGenVertexArrays(1, &this->vertexArrayObjID);            // objekt
    glGenBuffers(1, &this->vertexBufferObjID);                // geometriedaten (vertizes), texcoords, normalen, farbe - all in one
    glBindVertexArray(this->vertexArrayObjID);

    GLuint offset = 0;
    // VBO für alle daten vorbereiten
    glBindBuffer(GL_ARRAY_BUFFER, this->vertexBufferObjID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vPtr)+sizeof(nPtr)+sizeof(tPtr)+sizeof(cPtr), NULL, GL_STATIC_DRAW);
    // vertex daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vPtr), vPtr);
    offset += sizeof(vPtr);
    // normal daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(nPtr), nPtr);
    offset += sizeof(nPtr);
    // texcoord daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(tPtr), tPtr);
    offset += sizeof(tPtr);
    // color daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(cPtr), cPtr);
    offset += sizeof(cPtr);

    glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)sizeof(vPtr));
    glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(vPtr) + sizeof(nPtr)));
    glVertexAttribPointer((GLuint)3, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(sizeof(vPtr) + sizeof(nPtr) + sizeof(tPtr)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);

    glBindVertexArray(0);

    free(vPtr); vPtr = NULL;
    free(nPtr); nPtr = NULL;
    free(tPtr); tPtr = NULL;
    free(cPtr); cPtr = NULL;
    /*delete[] vPtr;
    delete[] nPtr;
    delete[] tPtr;
    delete[] cPtr;*/
}
```
hmm, ich habs mal als php code gebastelt - farben lassens vllt leichter erkennen. deine version der umsetzung is - wie man unschwer erkennt - gerade auskommentiert gewesen. aber keine version hat wirklich erfolge erzielt :/ weis einer, was ich falsch mache so als neuling in dieser disziplin? ^^



mal zu deiner letzten frage (eh ich als thread-napper gelte  ):


Crymes schrieb:


> Nochmal ne Frage, bin grad auf Fehlersuche bei  meinem Programm, an Quelltext hätte ich jetzt alles zusammen und  vernetzt:
> Funktioniert folgender Code bzw. wofür brauche ich die Klammern hinter ball? (Ball ist ein structure)
> 
> 
> ...


 is ball ein objekt des structs oder is ball der struct an sich (also ball = typname und nicht variablen name)? wenn zweiteres der fall is: vllt müssen deswegen die klammern da hin dann, weil er dann szs den konstruktor (eine parameterlose funktion) aufruft. besser wäre es wohl, wenn du ein objekt von ball anlegst, es mit sinnvollen werten füllst und dann an die liste anhängst.


----------



## DarkMo (20. Juni 2012)

hab übrigens rausgefunden, woran es lag. man darf nich sizeof(myPointerVar) nehmen - dann nimmt er quasi nur das erste von vielen elementen, sondern man muss explizit sagen arrayMemberCount * arrayMemberType -> bei mir zum bsp dann vCount * sizeof(float). das ganze überall so angepasst, und es funzt ><


```
void Objectloader::generateBatch(void) {
    // wir haben flist.size flächen
    // pro fläche haben wir 3 vertizes
    // jedes vertex besteht aus 3d punkt, 3d normale, 2d texcoord und 4d farbe - jeweils float
    int vCount = this->flist.size() * 3 * 3;
    int nCount = this->flist.size() * 3 * 3;
    int tCount = this->flist.size() * 3 * 2;
    int cCount = this->flist.size() * 3 * 4;

    float *vPtr = 0; vPtr = new float[vCount];
    float *nPtr = 0; nPtr = new float[nCount];
    float *tPtr = 0; tPtr = new float[tCount];
    float *cPtr = 0; cPtr = new float[cCount];

    // arrays mit daten der flächen füllen
    for(int i = 0; i < this->flist.size(); i++) {
        for(int j = 0; j < 3; j++) {
            vPtr[(i*9)+(j*3)]   = this->pointlist[this->flist[i].Points[j]].x;
            vPtr[(i*9)+(j*3)+1] = this->pointlist[this->flist[i].Points[j]].y;
            vPtr[(i*9)+(j*3)+2] = this->pointlist[this->flist[i].Points[j]].z;

            nPtr[(i*9)+(j*3)]   = this->vnlist[this->flist[i].Normals[j]].x;
            nPtr[(i*9)+(j*3)+1] = this->vnlist[this->flist[i].Normals[j]].y;
            nPtr[(i*9)+(j*3)+2] = this->vnlist[this->flist[i].Normals[j]].z;
        }
        for(int j = 0; j < 3; j++) {
            tPtr[(i*6)+(j*2)]   = this->vtlist[this->flist[i].TexCoords[j]].x;
            tPtr[(i*6)+(j*2)+1] = this->vtlist[this->flist[i].TexCoords[j]].y;
        }
        for(int j = 0; j < 3; j++) {
            cPtr[(i*12)+(j*4)]   = this->vclist[this->flist[i].Colors[j]].x;
            cPtr[(i*12)+(j*4)+1] = this->vclist[this->flist[i].Colors[j]].y;
            cPtr[(i*12)+(j*4)+2] = this->vclist[this->flist[i].Colors[j]].z;
            cPtr[(i*12)+(j*4)+3] = this->vclist[this->flist[i].Colors[j]].w;
        }
    }

    glGenVertexArrays(1, &this->vertexArrayObjID);            // objekt
    glGenBuffers(1, &this->vertexBufferObjID);                // geometriedaten (vertizes), texcoords, normalen, farbe - all in one
    glBindVertexArray(this->vertexArrayObjID);

    GLuint offset = 0;
    // VBO für alle daten vorbereiten
    glBindBuffer(GL_ARRAY_BUFFER, this->vertexBufferObjID);
    glBufferData(GL_ARRAY_BUFFER, ((vCount + nCount + tCount + cCount) * sizeof(float)), NULL, GL_STATIC_DRAW);
    // vertex daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, (vCount * sizeof(float)), vPtr);
    glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    offset += (vCount * sizeof(float));
    // normal daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, (nCount * sizeof(float)), nPtr);
    glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset);
    offset += (nCount * sizeof(float));
    // texcoord daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, (tCount * sizeof(float)), tPtr);
    glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset);
    offset += (tCount * sizeof(float));
    // color daten ins VBO kopieren
    glBufferSubData(GL_ARRAY_BUFFER, offset, (cCount * sizeof(float)), cPtr);
    glVertexAttribPointer((GLuint)3, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)offset);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);

    glBindVertexArray(0);

    delete[] vPtr; vPtr = NULL;
    delete[] nPtr; nPtr = NULL;
    delete[] tPtr; tPtr = NULL;
    delete[] cPtr; cPtr = NULL;
}
```


----------

