Irrlicht - from Noob to Pro: Einen Screenshot erstellen

Screenshots zu erstellen machen ein Spiel viel interessanter und ist, wenn man Irrlicht benutzt gar nicht so schwer, da die Engine einen Großteil der Arbeit abnimmt. Um trotzdem was zu erlernen, erfahren wir in diesem Abschnitt des Buches, wie man einen Screenshot erstellt und ihn mit fortlaufender Nummerierung ähnlich wie bei Irfan View speichert. Wir erstellen uns hierzu eine Funktion takeScreenshot.

bool takeScreenshot(void)
{
	//Die angehängte Zahl im Dateinamen
	u32 imageCounter = 0;

	//Der Dateiname
	stringc filename = "";

	//Eine Schleife, die solange läuft, bis wir einen noch nicht bekannten Dateinamen bekommen
	while(true)
	{
		filename =	"Clipboard";
		filename += stringc(imageCounter);
		filename += ".png";

		//prüft, ob eine Datei mit dem Namen existiert
		if(!device->getFileSystem()->existFile(filename))
		{
			//Bild mit dem Namen existiert nicht
			//dann erzeugen wir diese!
			break;
		}

		//Wir erhöhen den Zähler um eins
		imageCounter++;
	}

	IVideoDriver* driver = device->getVideoDriver();

	//Der Screenshot wird erzeugt
	IImage* screenshot = driver->createScreenShot();
	//Die Datei in die der Screenshot geschrieben wird
	IWriteFile* file = device->getFileSystem()->createAndWriteFile(filename);

	bool success = driver->writeImageToFile(screenshot, file);	//Screenshot speichern

	screenshot->drop();	//Objekt zerstören und Speicher frei geben
	file->drop();		//Datei schließen

	return success;
}

Dabei gehen wir so vor, dass wir davon ausgehen, dass wir noch keine Screenshots im Verzeichnis haben und unseren ersten Screenshot mit dem Namen Clipboard0.png" speichern wollen. Sofern diese Datei wirklich nicht vorhanden ist passiert auch genau das. Ansonsten erhöhen wir den Wert in der Schleife und stoßen so irgendwann an das Ende der Screenshotreihe ClipboardX.png der dann gespeichert wird. Im darauffolgenden Versuch würde der Screenshot mit dem Namen ClipboardX+1.png gespeichert werden.

Nach dem ein gültiger Dateiname gefunden wurde lassen wir von Irrlicht den Screenshot erstellen und erzeugen ein IWriteFile in das das noch virtuelle Bild gespeichert wird. Dieses speichern wir mit Hilfe des VideoDrivers auf die Festplatte und erhalten somit unseren Screenshot, in dem wir die Funktion wie folgt aufrufen:

int main(void)
{
	device = createDevice(EDT_OPENGL, dimension2d<u32>(640,480));

	if(device)
	{
		takeScreenshot();
		device->drop();
	}	

	return 0;
}

Alternativ (und bei Spielen wesentlich sinnvoller) wäre, den Dateinamen aus dem Datum und der Uhrzeit bestehen zu lassen - z.B.: meinSpiel_28_03_161956.png. Das hätte den Vorteil, dass man nicht auf die gültigkeit des Dateinamns prüfen muss, da jeder Dateiname eineindeutig ist. Leider lässt dies sich nur mit Hilfe von Irrlicht nicht bewerkstelligen, da die ITimer Klasse keine Daten wiedergeben kann. Daher erledigen wir das mit der Systemzeit, die zumindest unter Windows im entsprechenden Header liegt.

#include <windows.h>
bool takeScreenshotWithTime()
{
	SYSTEMTIME time;
	GetSystemTime(&time);

	stringc filename = "meinSpiel_";
	filename += stringc(time.wDay);
	filename += "_";
	filename += stringc(time.wMonth);
	filename += "_";
	filename += stringc(time.wHour);
	filename += "_";
	filename += stringc(time.wMinute);
	filename += "_";
	filename += stringc(time.wSecond);
	filename += ".png";

	IVideoDriver* driver = device->getVideoDriver();

	//Der Screenshot wird erzeugt
	IImage* screenshot = driver->createScreenShot();
	//Die Datei in die der Screenshot geschrieben wird
	IWriteFile* file = device->getFileSystem()->createAndWriteFile(filename);

	bool success = driver->writeImageToFile(screenshot, file);	//Screenshot speichern

	screenshot->drop();	//Objekt zerstören und Speicher frei geben
	file->drop();		//Datei schließen

	return success;
}

To-Do: Linux bzw Crossplattformcode posten.