Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 18, 2025 08:51

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Dynamische Arrays spinnen.
BeitragVerfasst: Mi Aug 06, 2008 12:20 
Offline
DGL Member

Registriert: Mi Mär 08, 2006 17:38
Beiträge: 153
Wohnort: Rümmelsheim (bei Bingen)
Ich weiß ihr werdet mich dafür hassen ,dass ich hier jetz mit DirectX ankomme, :D aber darum geht es hier jetz nicht :)

Folgendes Programmierproblem, das ich zwar gelöst habe , ich aber nicht verstehe, warum es so auf einmal klappt und anders nicht.

Folgendes Problem. Ich habe ein Dynamisches array von Vertices.
In Einer Procedure wird die länge mit SetLength bestimmt , mit Daten gefüllt und über einen Pointer auf den Vertexbuffer, diese Daten dort reingeschrieben.

Beim Rendern kommt leider nur mist bei raus.

Um zu vermeiden, dass ich selbst beim Erstellen der Vertices einen Fehler gemacht habe, habe ich zunächst den dynamischen Array mal statsich gemacht und voila es hat dann geklappt.
Also liegt es am Dynamischen array : der Quellcode sieht wie folgt aus:


Code:
  1.  
  2. function TD3DHEightmap.GenerateVB( _bytes_vertices, _x_count, _z_count: Cardinal;
  3.                        _width, _depht  : Single; ) : HRESULT ;
  4. var
  5.      pVertices : Pointer ;
  6.      x,y,z : Word ;
  7.     Vertices : array of TD3DLVertex ;
  8. begin
  9.  
  10.  //Zunächst Vertices laden
  11.  SetLength(Vertices,_z_count* _x_count)
  12.  dx := _width / _x_count ;
  13.  dz := _depth / _z_count ;
  14.  for z := 0 to _z_count-1 do
  15.  begin
  16.   for x := 0 to _x_count-1 do
  17.   begin
  18.    SetLength(Vertices,High(Vertices)+2) ;
  19.    hoehe := -(x*dx-(_width/2))*(x*dx-(_width/2))*0.1 + (z*dz-(_depth/2))*(z*dz-(_depth/2))*0.07 ;
  20.    vertices[z*_z_count + x]  := GetTD3DLVertex(x*dx-(_width/2),
  21.                                         hoehe,
  22.                                         z*dz-(_depth/2),
  23.                                         D3DColor_RGBA(round(x*dx*10), round(255-z*dz*10),round((x*dx+z*dz)*10),0)) ;
  24.    end;
  25.   end;
  26.  
  27.  //Dann alles dem Vertexbuffer übergeben.
  28.  result := pdevice.CreateVertexBuffer( _bytes_vertices,
  29.                               D3DUSAGE_WRITEONLY,
  30.                               D3DFVF_TD3DLVertex,
  31.                               D3DPOOL_DEFAULT,
  32.                               vb,nil);
  33.   if result <> D3D_OK then exit ;
  34.    vb.Lock(0, sizeOf(Vertices), pVertices,0);
  35.    Move(Vertices,pVertices^, sizeOf(Vertices)) ;
  36.    vb.unlock ;
  37. end;
  38.  


Quellcode stimmt , da eben alles mit statischem array funktioniert. nur mit dem dynamischen nicht.

Jetzt hab ich etwas rumgebastelt und alles so umgebaut :
Code:
  1.  
  2. function TD3DHEightmap.GenerateVB( _bytes_vertices, _x_count, _z_count: Cardinal;
  3.                        _width, _depht  : Single; _Vertices : array of TD3DLVertex) : HRESULT ;
  4. var
  5.      pVertices : Pointer ;
  6.      x,y,z : Word ;
  7. begin
  8.  result := pdevice.CreateVertexBuffer( _bytes_vertices,
  9.                               D3DUSAGE_WRITEONLY,
  10.                               D3DFVF_TD3DLVertex,
  11.                               D3DPOOL_DEFAULT,
  12.                               vb,nil);
  13.   if result <> D3D_OK then exit ;
  14.    vb.Lock(0, sizeOf(_Vertices), pVertices,0);
  15.    Move(_Vertices,pVertices^, sizeOf(_Vertices)) ;
  16.    vb.unlock ;
  17. end;


Die Vertices werden nun in einer anderen procedur erstellt (Hier auch dymanisches Array) , dann über ein array _Vertices an die Funktion TD3DHEightmap.GenerateVB übergeben und diese läd das dann in den Vertexbuffer.

komischerweise klappt es so ?! WARUM ?! :D
beides mal dynamisches Array Vertices nur nicht in der gleichen Procedure ?! ?! ?!
Kann mir das einer erklären ?

Vielen Dank

Simon


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Dynamische Arrays spinnen.
BeitragVerfasst: Mi Aug 06, 2008 12:57 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
simon1988 hat geschrieben:
Ich weiß ihr werdet mich dafür hassen ,dass ich hier jetz mit DirectX ankomme, :D aber darum geht es hier jetz nicht :)

Nö. Es wird nur im Laufe des Tages dein Benutzeraccount gelöscht. :P Quatsch. Wir sind offen für alles. Nur wird man dir bei richtigen DirectX Fragen in einem OpenGL Forum wohl nicht so gut helfen können wie in einem DirectX Forum.

Arrays: Es gibt einen wirklich markannten Unterschied zwischen statischen und dynamischen Arrays. Bei einem statischem Array befinden sich dessen Daten direkt an der Stelle der Variable. Bei einem dynamischen aber handelt es sich um einen Pointer. Dessen Daten liegen aber irgendwo im Heap. Und da zeigt der Pointer hin. Wenn du darauf zugreifst weiß Delphi das und löst den Pointer selbsttätig auf.

Bei einem Befehl wie Move musst du aber einen Speicherbereich übergeben. Bei einem Statischen ist die Variable gleich der Speicherbereich. Deswegen geht das. Bei Dynamischen musst du aber auf das erste Element des Arrays verweisen, da du damit dann explizit den Datenbereich des Arrays meinst. Bei Strings gilt im übrigen das Gleiche. Die sind mit einem dynamischem array of char vergleichbar.
Code:
  1. Move(Vertices[0], pVertices^, sizeOf(Vertices);

Das mache ich im übrigen grundsätzlich immer so. Egal ob es sich dabei um ein statischen oder dynamisches Array handelt. Ich geben immer genau die Stelle an die ich meine.

Warum die zweite Variante allerdings funktioniert kann ich dir nicht sagen. Denn normal sollte sie die gleichen Einschränkungen haben wie die Erste. Mit anderen Worten das dürfte genau so wenig funktionieren wie die erste Variante. Und das solltest du ändern, da es möglicherweise ein Compilerfehler ist der irgendwann behoben wurde etc. Also ich würde mich nicht darauf verlassen, dass es imme funktionieren wird.

Und wenn du so etwas (Var: array of TD3DLVertex) häufiger brauchst solltest dafür einen extra Typen definieren und diesen benutzen.


PS: Statische Arrays als lokale Variablen liegen auf dem Stack. Da der Stack aber normal auf 1 MB begrenzt ist würdest du so bei größeren Datenmengen einen Stackfehler bekommen. Dynamische liegen im Heap und könnten somit den vollen Speicher des Systems ausnutzen. Das ist in der Praxis zwar nicht möglich aber das ist ein anderes Thema.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 06, 2008 13:39 
Offline
DGL Member

Registriert: Mi Mär 08, 2006 17:38
Beiträge: 153
Wohnort: Rümmelsheim (bei Bingen)
Danke für die Antwort. HAb mir Pointern noch nicht so viel am Hut gehabt. alles was ich bisher dazu gefunden habe , war sehr knapp erklärt. zu knapp .

vllt. kennt einer ne gute seite , wo das erklärt ist ?


aber ich hab das jetz wieder so umgeswchrieben und leider kommt schon wieder mist bei raus .. hmpf
Code:
  1.  
  2. function TD3DHEightmap.GenerateVB( _bytes_vertices, _x_count, _z_count: Cardinal;
  3.                        _width, _depth  : Single) : HRESULT ;
  4. var
  5.      pVertices : Pointer ;
  6.      x,y,z : Word ;
  7.      Vertices : array of TD3DLVertex ;
  8.      hoehe     : Single ;
  9.      dx, dz : Single ;
  10. begin
  11. //Vertexdaten laden
  12.  SetLength(Vertices,_x_count * _z_count);
  13.  dx := _width / _x_count ;
  14.  dz := _depth / _z_count ;
  15.  for z := 0 to _z_count-1 do
  16.  begin
  17.   for x := 0 to _x_count-1 do
  18.   begin
  19.    hoehe := -(x*dx-(_width/2))*(x*dx-(_width/2))*0.1 + (z*dz-(_depth/2))*(z*dz-(_depth/2))*0.07 ;
  20.    vertices[z*_z_count + x]  := GetTD3DLVertex(x*dx-(_width/2),
  21.                                         hoehe,
  22.                                         z*dz-(_depth/2),
  23.                                         D3DColor_RGBA(round(x*dx*10), round(255-z*dz*10),round((x*dx+z*dz)*10),0)) ;
  24.    end;
  25.   end;
  26.  
  27.   result := pdevice.CreateVertexBuffer( _bytes_vertices,
  28.                               D3DUSAGE_WRITEONLY,
  29.                               D3DFVF_TD3DLVertex,
  30.                               D3DPOOL_DEFAULT,
  31.                               vb,nil);
  32.   if result <> D3D_OK then exit ;
  33.    vb.Lock(0, sizeOf(Vertices), pVertices,0);
  34.    Move(Vertices[0],pVertices^, sizeOf(Vertices)) ;
  35.    vb.unlock ;
  36. end;
  37.  


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 06, 2008 14:27 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Stimmt. Denn SizeOf liefert bei einem statischen Array die Große der Daten, da die Variable alle Daten enthält. Allerdings bei einem dynamischen Array liefert SizeOf den Wert 4, da es sich ja eigentlich um einen Pointer handelt. Und der hat die Größe 4. In 32 Bit Programmen versteht sich.

Die Größenberechnung musst du dann selbst in die Hand nehmen. Aber das ist recht simpel. Und du musst das beim Locken des VBOs auch berücksichtigen.
Code:
  1. Length(DynArray) * SizeOf(TD3DLVertex)


Ansonsten hat delphi-treff.de recht umfangreiche Tutorials über die Sprache etc. Allerdings gehen diese Tutorials eher nicht unter die Oberfläche. Also wie verschiedene Dinge intern funktionieren. Das ist aber genau das was in diesem Falle wichtig ist. Das ist etwas was man irgendwie alles mal selber erlebt haben muss. Das alles in Tutorials fassen zu wollen wäre zu viel arbeit, da jeder Fall auch ganz speziell ist.



Ich persönlich arbeite bei so etwas mittlerweile lieber komplett per Hand. Also keine dynamischen Arrays sondern direkt den Speicherbereich mit GetMem erstellen und mit FreeMem dann wieder löschen. Aber in deinem Fall geht das auch noch ein Stück einfacher. Denn du kannst auch gleich den Speicherbereich des VBOs benutzen. Anstelle erst selber einen Speicherbereich zu erstellen und die Daten dann rüber zu kopieren. Das Sparrt zu mindest ein mal die Menge des Speichers und die Arbeit des Kopieren.
Code:
  1. type
  2.   PD3DLVertex = ^TD3DLVertex;  // Pointertypen definieren, falls nicht vorhanden
  3. var
  4.   pBuffer: PD3DLVertex
  5.   Size: Integer;
  6. begin
  7.   Size := X_size * Y_size * SizeOf(TD3DLVertex); // größe berechnen
  8.  
  9.   vb.Lock(0, Size, pBuffer, 0); // Speicherbereich erstellen
  10.  
  11.   for x := ... begin
  12.     for y := ... begin
  13.       pBuffer^ := GetTD3DLVertex(...); // einzelnen Feld zuweisen
  14.       inc(pBuffer); // erhöht den Pointer um die Größe auf dessen was er zeigt. Also um SizeOf(TD3DLVertex)
  15.     end;
  16.   end;
  17.  
  18.   vb.unlock;
  19. end;

Das ist dann für Faule, da bei jedem Inc der Pointer um die Größe der Daten (SizeOf(TD3DLVertex)) erhöht wird. So brauche ich mich nur darum kümmern, dass die Eingangsgröße stimmt und die Indexzählung/Berechnung geschieht automatisch. Funktioniert aber nur sofern die Position immer fortlaufend ist. Und das ist wenn ich das gesehen habe bei dir der Fall. Die Variable Size benutze ich deswegen um nicht jedes mal die Größe berechnen zu müssen. Eine Variable spart Rechenleistung und verhindert, dass ich irgendwann mal eine andere Rechnung habe. In diesem Beispiel würde sie nur ein mal benutzt werden aber kann ja auch mehrfach passieren.

Aber das nur Kurz in Sachen Pointer. Die dynamischen Arrays funktionieren genau so gut und vereinfachen manche Dinge auch. Man muss sich nicht um alles selber kümmern.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 06, 2008 15:51 
Offline
DGL Member

Registriert: Mi Mär 08, 2006 17:38
Beiträge: 153
Wohnort: Rümmelsheim (bei Bingen)
ah perfekt es funktioniert :)

Vielen Dank. so langsam steig ich auch hinter die Pointer :)

einge Frage noch .. Woher weiß Delphi bei Inc(pVertices) das er um SizeOf(TD3DLVertex) weiter gehen muss ?
Weil ich in der Zeile Davor ihn mit der größe beschrieben habe ?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 06, 2008 16:06 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Das funktioniert, weil der Pointer typisiert ist. Also PD3DLVertex = ^TD3DLVertex. Und da weiß der Kompiler wie groß TD3DLVertex ist. Wenn du inc(pByte(PD3DLVertex_Variable)); machen würdest, dann würde der Kompiler den Pointer um 1 Byte erhöhen. Und bei einem "Pointer" (untypisiert) würde der Aufruf sogar fehl schlagen (Kompilerfehler).


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Aug 06, 2008 16:30 
Offline
DGL Member

Registriert: Mi Mär 08, 2006 17:38
Beiträge: 153
Wohnort: Rümmelsheim (bei Bingen)
ah ok .. also muss ich den Pointer vorher nem best. Typ zuweisen.

bei mir ist er ja noch vom Typ Pointer.


Danke schön :)


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 16 Queries | GZIP : On ]