JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=e00a58758f091ed7c8fa814477d71355Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

PNG Dateien schnell und einfach laden

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 21.11.2007, 14:17    Titel: PNG Dateien schnell und einfach laden Antworten mit Zitat

Heute möchte ich euch einmal zeigen, wie man sehr leicht PNG-Bilddateien in seinem Spiel verwenden kann. Als Sprache wird C++ verwendet, mit dem geladenen Bild kann man dann machen, was man will (OpenGL oder DX Textur und so weiter).

Warum PNG? Nun PNG ist ein weit verbreitetes Format, um Rastergrafiken (solche die aus einzelnen Pixel bestehen) komprimiert abspeichern zu können. Im Gegensatz zum ebenfalls weit verbreiteten JPEG-Formats ist PNG aber absolut verlustfrei. Außerdem kann es einen Alphawert speichern, was bei 2D Spielen und auch in vielen Situationen bei 3D Spielens sehr wichtig ist.

Zum Laden von PNG-Dateien gibt es eine Referenz Bibliothek, names libpng. Diese ist allerdings ein ziemlich Klotz und will erst einmal verstanden werden. In diesem Tutorial benutze ich aber nicht libpng, sondern picopng.

PicoPNG ist eine sehr kompakte Bibliothek. Obwohl Bibliothek eigentlich das falsche Wort ist, es handelt sich nur um eine einzige C++ Funktion. Das schöne an ihr ist, das keine externen Abhängigkeiten wie libpng oder zlib (PNG benutzt zlib zur Kompression) benötigt werden. Man hat in einer einzigen Funktion alles was man benötigt! Daher ist diese „Bibliothek“ auch so enorm klein, der gesamte Quelltext hat nur 33 kb (kompiliert dementsprechend noch kleiner).
Netterweise steht das ganze unter einer sehr liberalen OpenSource Lizenz, man kann damit so gut wie alles machen (benutzen, verbreiten, verändern, verkaufen, usw.).

Diese eine „magische“ Funktion heißt decodePNG. Sie erwartet einen Zeiger auf die PNG-Daten und liefert ein std::vector mit dem geladenen 32 Bit Bild. Daher müssen wir selber erst die Bilddatei in unseren Speicher laden und diesen dann decodePNG übergeben. Das hat den Vorteil, dass man nicht nur echte Dateien laden kann, sondern die Bilder auch aus einem Archiv oder aus einer Ressource oder direkt aus dem Internet geladen speichern kann. Fangen wir also an:

Als erstes laden wir PicoPNG runter. Zu finden ist das ganze unter:
http://members.gamedev.net/lode/projects/LodePNG/

Nun fügen wir unserem Projekt die picopng.cpp unserem Projekt hinzu. Die Mainfunktion, die sich ganz am Ende der Datei befindet, wird gelöscht oder auskommentiert, sie dient nur als Beispiel. Zusätzlich sollte man noch eine picopng.h anlegen, in der man den Prototypen der decodePNG schreibt.
Nun benutzen wir decodePNG um eine OpenGL Textur zu erstellen:

CPP:
GLuint LoadPNG(std::string Filename)
{
   std::ifstream File;
   File.open(Filename.c_str(), std::ios::in | std::ios::binary);

   File.seekg(0, std::ios::end);//zum ende der datei springen
   int FileLength=File.tellg();
   File.seekg(0, std::ios::beg);

   std::vector<unsigned char> Buffer, Image;
   Buffer.resize(FileLength);

   File.read((char*)(&Buffer[0]), FileLength);

   File.close();

   unsigned long XSize=0, YSize=0;

   decodePNG(Image, XSize, YSize, &Buffer[0], (unsigned long)Buffer.size());

   //jetzt die Textur erstellen

   GLuint NewTexture;
   glGenTextures(1, &NewTexture);
   glBindTexture(GL_TEXTURE_2D, NewTexture);
   glTexImage2D(GL_TEXTURE_2D, 0, 4, XSize, YSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, &Image[0]);

   return NewTexture;
}


Und das wars auch schon Very Happy
Wie man sieht, wird keinerlei Fehlerkontrolle vorgenommen, das sollte natürlich nicht so bleiben. So und jetzt noch ein paar Erläuterungen, was dieser Code den so macht:
Zuerst wird die Bilddatei geöffnet, und zwar im Binarymode. Das ist wichtig, da es sonst zu kleinen, aber schwerwiegenden Fehlern kommen kann. Dann springen wir zum Ende der Datei (seekg) hohlen uns die Adresse des Lesezeigers (tellg) und speichern diese. Den genau das ist ja unsere Dateigröße. Anschließend springen wir wieder zurück zum Anfang. Nun werden 2 Buffer angelegt, einen für die Rohdaten, und einen für das decodierte Bild. Wir lesen also die gesamte Datei (mit read) in den Buffer, und schließen sie anschließend wieder.
Die decodePNG erwartet 3 Referenzen, nämlich auf den Vector für das fertige Bild, und auf 2 Variablen, in denen später die Bildgröße stehen wird. Das Format ist beim laden immer RGBA, also muss uns das decodePNG nicht mehr mitteilen. Wir erstellen also die 2 Variablen um die Größe zu speichern, und rufen decodePNG auf. Der vierte Parameter ist der Zeiger auf die Rohdaten, der fünfte die Größe.
Jetzt haben wir also die fertige PNG Datei in unserem Speicher und können damit machen, was wir wollen. Ich habe hier mal eine einfache OpenGL Textur erstellt, aber mit wenig mehr Aufwand ließe sich auch eine D3D Textur oder ein Ddraw Surface erzeugen. Daher gehe ich hier auch nicht näher auf die erstellung der OpenGL Textur ein, sämtliche Funktionen sind ja im Internet ausreichend dokumentiert.

So und nun viel Spaß beim Laden von PNG Dateien!

PS: Ich weiß selber, dass es keine tolle Leistung ist, ein Tutorial über eine einzige Funktion zu schreiben. Ich hoffe lediglich ein paar Leuten zeigen zu können, wie schnell und einfach mal PNG-Dateien laden kann, ohne gleich Tonnen an fremden Code mitschleppen zu müssen.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 21.11.2007, 19:11    Titel: Antworten mit Zitat

Ich finde das Tutorial ganz nett

Nur hättest du das was du nach dem Quelltext über den Quelltext geschrieben hast auch als kommentar in den Quelltext schreiben können, sio hätte man gleich einen bezugpunkt zum Code selbst. Wink

mfg Mark
_________________
"I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse."
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 21.11.2007, 19:20    Titel: Antworten mit Zitat

jo das gefällt mir auch, das kleine ding Wink was mir bes. gefällt ist der schöne nebeneffekt, dass endlich mal gezeigt wird wie man mit c++ solche dateien handhaben kann. Viele benutzen bei so etwas fread etc., weil man nicht so leihct auf die umsetzung in c++ kommt. Das kommt daher dass streams zwar sehr mächtig sind und noch viel mehr können, es aber nicht so leicht ist sie in dieser weise zu benutzen (bzw. darauf zu kommen). Gibt des weiteren auch nicht viel stoff dazu.

Gruß DXer

PS: picoPNG ist ja ganz was feines, kannte ich vorher noch nicht so =)
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum