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

Aktuelle Zeit: Di Apr 16, 2024 19:34

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



Ein neues Thema erstellen Auf das Thema antworten  [ 60 Beiträge ]  Gehe zu Seite 1, 2, 3, 4  Nächste
Autor Nachricht
 Betreff des Beitrags: Screenshot mittels glReadPixels
BeitragVerfasst: Mi Mär 30, 2005 15:14 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Also ich würde gerne in meinem Programm ne Funktion anbieten um Screenshots von der Ausgabe zu machen. Also dacht ich mir:

Code:
  1. procedure OutPutToBitmap;
  2. var Bitmap : TBitmap;  
  3.     Dummi  : Boolean;
  4. begin
  5.    Bitmap := TBitmap.Create;
  6.    Bitmap.Width  := RenderForm.ClientWidth;
  7.    Bitmap.Height := RenderForm.ClientHeight;
  8.  
  9.    HptFenster.IdleHandler(HptFenster, Dummi);
  10.  
  11.    glReadPixels(...
  12.  
  13.    ...
  14. end;


Wie man sieht isses net fertig. Ich scheitere schon an den Paramtern für glReadPixels. Ich möchte die gesamte Ausgabe abspeichern. Dazu wollte ich folgenden Aufruf verwenden:
Code:
  1. glReadPixels(0, 0, Bitmap.Width, Bitmap.Height, GL_RGB, GL_FLOAT, Pixeldata);


Ist das 0, 0 für X bzw. Y richtig? Ist GL_FLOAT richtig? Und vorallem wie muss Pixeldata vereinbart werden?

Wenn einer von euch schonmal sowas gemacht hat (ich bin mir da ziemlich sicher) kann er ja netterweise den restlichen Code einfach posten. Oder seine Ganze Funktion mal zeigen. (Wenn ich das am Laufen hab, schreib ich es als Beispiel zu glReadPixels() ins Wiki.)

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 13:32 
Offline
DGL Member

Registriert: Do Mär 31, 2005 13:29
Beiträge: 3
ich machs immer so:

Code:
  1.  
  2. function TScreenShotUtility.ScreenShot : TBitmap;
  3. var     Pixel : PByteArray;
  4.         X, Y : Integer;
  5.         Temp : Byte;
  6.         Header : PBitmapInfo;
  7. begin
  8.         Result := TBitmap.Create;
  9.         Result.PixelFormat := pf32Bit;
  10.         Result.Width := ClientWidth;
  11.         Result.Height := ClientHeight;
  12.  
  13.         GetMem( Pixel, Result.Width*Result.Height*4 );
  14.         glReadPixels( 0, 0, Result.Width, Result.Height, GL_RGBA, GL_UNSIGNED_BYTE, Pixel );
  15.  
  16.         for Y := 0 to Result.Height-1 do
  17.                 for X := 0 to Result.Width-1 do begin
  18.                         Temp := Pixel^[(Y*Result.Width+X)*4+2];
  19.                         Pixel^[(Y*Result.Width+X)*4+2] := Pixel^[(Y*Result.Width+X)*4];
  20.                         Pixel^[(Y*Result.Width+X)*4] := Temp;
  21.                 end;
  22.  
  23.         GetMem( Header, SizeOf( TBitmapInfoHeader ) );
  24.         with Header^.bmiHeader do begin
  25.                 biSize := SizeOf( TBitmapInfoHeader );
  26.                 biWidth := Result.Width;
  27.                 biHeight := Result.Height;
  28.                 biPlanes := 1;
  29.                 biBitCount := 32;
  30.                 biCompression := BI_RGB;
  31.                 biSizeImage := Result.Width*Result.Height*4;
  32.         end;
  33.  
  34.         SetDIBits( Result.Canvas.Handle, Result.Handle, 0, Result.Height, Pixel, TBitmapInfo( Header^ ), DIB_RGB_COLORS );
  35.  
  36.         FreeMem( Pixel );
  37.         FreeMem( Header );
  38. end;
  39.  


Varan


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 13:58 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Hey danke. Das nenn ich mal nen Ordentlichen Code. ;)

Den Typ PBitmapInfo hast du den selber definiert, oder liegt der irgendwo versteckt bei Delphi bei?

EDIT: Kann es sein, dass die PBitmapInfo ab Delphi Version >5 dabei ist?

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 14:43 
Offline
DGL Member

Registriert: Mo Jan 20, 2003 20:10
Beiträge: 424
Wohnort: nähe Starnberg
Ist eigentlich ein Standardtyp in Windows. Eventuell die Unit Types/Windows einbinden?

Gruß
KidPaddle

_________________
http://www.seban.de


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 14:51 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Die PBitmapInfo ist ein Bestandteil von einem TBitmap und das sollte schon seit anno knips dabei sein. Tippe mal darauf, dass das einfach nur anders heißt. Warum ist das in dem Beispiel eigentlich ein Pointer wo die Methode doch eine var Record haben will? Macht irgendwie nicht so viel sinn für mich.

Ich wollte eigentlich gestern was zu deiner Frage sagen nur irgendwie habe ich es nicht geregelt bekommen. :roll:

Du kannst das ganz sogar noch einfacher gestalten. Anstelle von GL_RGBA solltest du auch GL_BGRA übergeben können. Jedenfalls ab OpenGL 1.2. Dann bekommst du deine Daten schon so wie sie das Bitmap haben will. Dann muss man nicht erst noch umständlich irgendwelche Bytes drehen. Und diese Daten kannst du dann sehr einfach in ein Bitmap packen. Entweder über die API Methode oder eben (was ich persönlich besser finde) über ScanLine.

PS: Ich persönlich würde keine Klassen in einer Methode zurück liefern, da im Falle eines Fehlers (Exception) dort Speicher verlohren geht. Dann lieber die Klasse außerhalb erstellen und übergeben. Dann liegt erzeugen und freigeben in einer Hand und ist nicht so verstreut.

Ich würde es wohl eher so machen. Aber das dürfte wie fast alles reine Ansichtssache sein.
Code:
  1. procedure TForm1.MakeShoot (Bitmap: TBitmap);
  2. var
  3.   Buffer, Source: PByte;
  4.   Size, Y: Integer;
  5. begin
  6.   Bitmap.Width := ClientWidth;
  7.   Bitmap.Height := ClientHeight;
  8.   Bitmap.PixelFormat := pf32bit;
  9.  
  10.   Size := Bitmap.Width * 4;
  11.  
  12.   GetMem(Buffer, Size * Bitmap.Height);
  13.   try
  14.     Source := Buffer;
  15.  
  16.     glReadPixels (0, 0, ClientWidth, ClientHeight, GL_BGRA, GL_UNSIGNED_BYTE, Buffer);
  17.  
  18.     for Y := Bitmap.Height -1 downto 0 do
  19.       begin
  20.         Move (Source^, PByte (Bitmap.ScanLine [Y])^, Size);
  21.         Inc (Source, Size);
  22.       end;
  23.   finally
  24.     FreeMem (Buffer);
  25.   end;
  26. end;

Der Code ist nicht getestet und sollte er auf Systemen laufen die kein OpenGL 1.2 unterstützen, wird er nicht funktionieren. Aber solche system sollte es heutzutage fast nicht mehr geben.


Zuletzt geändert von Lossy eX am Di Apr 19, 2005 13:06, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 14:56 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Seltsam das die Hilfe den nicht kannte. :?

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 15:05 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Das ist bei den ganzen Windowsrecordtypen normal. Habe ich auch schon ein paar mal verflucht. Du solltest aber darauf achten, dass die unit Windows vor der unit Graphics steht. Die haben nämlich genialerweise einen Typen namens TBitmap in der Unit Windows definiert. Und die verdeckt dann das richtige Bitmap. Mit Graphics.TBitmap kann man zwar noch drauf zu greifen. Ist aber lästig und man muss erst einmal suchen warum es nicht mehr geht.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 15:25 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Danke für die Vielfachen Lösungen. Ich hab (weil er der erste war) Varans Lösung eingebaut. Ich liefere dabei kein Bitmap zurück sondern speichere das Bild direkt auf Platte (Filename rein, nix raus).

Nur mein Delphi meckert nen Fehler bei der Bereichsprüfung an. Und zwar in dem RGB->BGR Abschnitt an. Ich bin aber wohl zu unkonzentriert um zu sehen, woran das liegt. Siehts von euch einer?

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 15:30 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Dez 28, 2002 11:13
Beiträge: 2244
Paßt zwar nicht ganz zur Frage, aber da die meistens hier eher skeptisch sind, wollte ich mal zeigen, dass auch ganz normale Sachen mit .Net recht elegant gehen. Bei diesem Pixelformat liegen die Daten laut Hilfe in einem Block im Speicher, daher kann man sich das Kopieren und die Zeigerarithmetik sparen. Das Objekt kann dank GC ebenfalls nicht verloren gehen.

Code:
  1. function MakeScreenshot(x,y,width,height:Integer):Bitmap;
  2. var
  3.  data:BitmapData;
  4. begin
  5.   result:=Bitmap.Create(width,height);
  6.   data:=result.LockBits(Rectangle.Create(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  7.   try
  8.     glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data.Scan0);
  9.   finally
  10.     result.UnlockBits(data);
  11.   end;
  12. end;


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 31, 2005 16:23 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Ich tippe mal darauf, dass es daran liegt wie das PByteArray deklariert ist.

Code:
  1.   PByteArray = ^TByteArray;
  2.   TByteArray = array[0..32767] of Byte;


Sobald du auf das Element nach 32767 zugreifen möchtest meckert Delphi einen Bereichsfehler, da der Typ legal nur bis 32767 gehen dürte. Es aber in Wirklichkeit nicht tut, da er nur misbraucht wird. Abhelfen kannst du dem indem du vorher die Bereichsprüfung ausstellst. {$R-} und anschließend wieder aktivierst {$R+}
Das ist die Quick und Dirty Lösung. Eine andere Lösung wäre du definierst einen eigenen Typ der entsprechend größer ist. Oder du stellst den Algorithmus um. Ich würde im übrigen auch empfehlen die Berechnungen in den Schleifen auf ein Minimum zu reduzieren. Also in Temporäre Variablen ablegen. Dort wird 4 Mal fast das selbe Offset berechnen. Das ist alles andere als Optimal!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Apr 01, 2005 13:11 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Wie soll ich denn den Algorithmus umstellen, und wieso wird das Bytearray misbraucht? Bitte klär mich auf. :?:

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Apr 01, 2005 13:26 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mai 14, 2004 18:56
Beiträge: 804
Wohnort: GER/OBB/TÖL-WOR/Greiling
bezieht sich wohl auf varans post??

_________________
Bild

"User Error. Replace User and hit Continue."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Apr 01, 2005 13:44 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Zitat:
Bitte klär mich auf.

Hmmm. Hätten das deine Eltern nicht tun sollen? Tschuldige. Das konnte ich mir nicht verkneifen. Sonst wäre ich an Herzdrücken gestorben. ;-)

Aber zurück zum Thema. In dem Quellcode wird ein Pointer mit der Größe des Bildes erstellt. Dieser Pointer wird aber Anhand des Types auf ein Array [0..32767] of Byte gecastet. Somit kann man es ermöglichen, dass Delphi glaubt es handele sich um einen Pointer auf ein richtiges Array. Was aber nicht stimmt. Wenn du normalerweise ein PByteArray erstellst, dann hätte das auch nur genau 32768 Stellen. Aber an der Stelle wird ja nur danach gecastet. Wenn man jetzt (wie jeder das eigentlich haben sollte) die Bereichsprüfung an hat, dann knallt es. Zu recht.

Ich habe schon Konstrukte gesehen die haben auf ein Array [0..MAXINT] of Byte gecastet. Das ist dann aber auch nur casten geeignet, weil man Typen mit solche einer Große gar nicht erstellen kann. Ich persönlich mag so etwas aber auch nicht. Das ist aber auch eine Möglichkeit wie du das machen könntest. Bei dem Erstellen einer Windowsfarbpalette musst man ähnliches machen dort haben die ein array [0..0] of TPaletteEntry definiert. :evil:

Zum Thema Algorithmus umstellen. Da gibt es zahlreiche Möglichkeiten. Entweder du erweiterst den Arraytypen siehe oben. Oder eben du stellst direkt auf einen Pointer um. Da würde ich einen PRGBQuad empfehlen. (bei RGB dann ein PRGBTriple) Einen solchen Pointer setzte du auf den Anfang des Speicherbereiches und kannst dann mittels rgb^.rgbBlue etc auf die entsprechenden Bytes zugreifen. Wenn du dann Inc(rgb) machst dann springt er ein Pixel (4Bytes) weiter. Er weiß ja wie groß der Typ ist.

Also in etwa so.
Code:
  1. var
  2.   rgb: PRGBQuad
  3. begin
  4.   ...
  5.   rgb := Buffer;
  6.   for Idx := 0 to Width * Height -1 do
  7.     begin
  8.       Temp := rgb^.rgbBlue;
  9.       rgb^.rgbBlue := rgb^.rgbRed;
  10.       rgb^.rgbRed := Temp;
  11.       Inc(rgb);
  12.     end;


@Luke: eher auf den Fehler der bei aktivierter Bereichprüfung auftritt.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Apr 03, 2005 17:05 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Mär 09, 2005 12:26
Beiträge: 53
Wohnort: Dornbirn
Hmm also wenn ich einen Screenshot machen muss, benutze ich immer diese Methode (zwar nicht mit glReadPixels) aber ist trotzdem recht perfomant.
Also in diesem Fall mach ich in meinem Programm einen Screenshot vom Level um eine Minimap (gesamtübersicht) zu zeichnen.
Dazu zeichne ich nur das Level ohne Panzer, SeitenMenü, etc... Scaliere dies auf die Größe von 256x256 Pixel runter (brechne ich durch die Fenstergröße) und mach dann denn Screenshot in eine 256x256 Pixel große Textur.

Ich hoffe es nützt etwas

Code:
  1.  
  2. float scalex, scaley;
  3. int miniMapSize = 256;
  4.  
  5. scalex = ((float)10 / (float)tilesx) * ((float)miniMapSize / (float)windowSizex);
  6. scaley = ((float)10 / (float)tilesy) * ((float)miniMapSize / (float)windowSizey);
  7. glGenTextures(1, &miniMapTexture);
  8.    
  9. glPushMatrix();
  10. glLoadIdentity();
  11. glTranslatef(-1 + scalex*6.425,-1 + scaley*6.4, 0.0);
  12. glScalef(scalex, scaley, 0.0);
  13. renderOnlyLevel();
  14. glBindTexture(GL_TEXTURE_2D, miniMapTexture);
  15. glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, miniMapSize, miniMapSize, 0);
  16. glPopMatrix();
  17. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  18. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

_________________
Good software is like sex, it's best when it's free


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Apr 03, 2005 22:59 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7804
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Hey danke, die Idee is gut auch wenns nicht das ist was ich machen will. Ich will das Bitmap später auf Platte speichern ;)
Aber danke für die Idee. Kann man sicherlich gut für minimaps benutzen. 8)

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 60 Beiträge ]  Gehe zu Seite 1, 2, 3, 4  Nächste
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 29 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:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.093s | 19 Queries | GZIP : On ]