|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 21.11.2007, 13:17 Titel: PNG Dateien schnell und einfach laden |
|
|
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
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 |
|
|
Fallen JLI MVP
Alter: 40 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 21.11.2007, 18:11 Titel: |
|
|
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.
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 21.11.2007, 18:20 Titel: |
|
|
jo das gefällt mir auch, das kleine ding 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 |
|
|
|
|
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
|