Bilder als Ressourcen

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Vorwort

Eins vorneweg: Da ich noch OpenGL-Frischling bin, sollten die in diesem Artikel beschriebenen Methoden zwar funktionieren, jedoch bin ich fast der Überzeugung, dass sie Speicher- sowie Performancetechnisch eher miserabel sind...

Einleitung

Man kann Bilder (und auch jeglichen anderen Daten) beispielsweise in Ressourcen-Dateien packen, um die .exe möglichst klein zu halten.
Oder aber man freut sich, wenn man immer alle Grafiken in einer Datei zusammen hat.
Oder man verwendet Ressourcen-Dateien, damit "net jeder Wald und Wiesendepp mit Paint die Grafiken verunstalten kann" (Zitat Flash)

Warum auch immer man sich für Ressourcen-Dateien entscheiden sollte, die Herangehensweise ist die selbe - nämlich folgende:


.RES Datei Erstellen...

Als erstes nehmen wir alle Grafiken, die wir brauchen, und packen sie in eine .res Datei.
"packen" weckt hier möglicherweise falsche Hoffnungen, denn die Daten werden dadurch nicht komprimiert, sie kommen bloß alle zusammen in eine Datei.
Um eine solche .res Datei zu erschaffen gibt es mehrere Wege - hier sind zwei:

einfach und schnell

Man benutzt das Programm "PE Ressource Explorer", mit welchem man sich recht bequem seine Ressourcen zusammen klicken kann. (Download: http://www.wilsonc.demon.co.uk/d10ressourceeditor.htm)

selber tippen

Die andere Möglichkeit ist etwas mehr Arbeit: Also schnappst du dir Notepad oder sonst irgendeinen Editor und erstellst eine Datei mit folgendem Format:
<Ressourcenbezeichner> <Ressourcentyp> <Pfad zur Datei>
beispielsweise:
myCharTex BITMAP char.tga

Ressourcenbezeichner: ist der Name, den du der Ressource gibst. Statt einem String kannst du auch ne Zahl hinschreiben, also:
10 BITMAP holla.bmp
Muss man selber wissen, ob man lieber mit Strings oder Integers als Bezeichner arbeitet, hat bestimmt beides Vorzüge...
Ressourcentyp: Es gibt einige vordefinierte Typen (für Bitmaps, Jpgs, Cursor, Icon, usw)
Für alle Sachen, die nicht explizit nen eigenen Typ haben gibt es RCDATA
Das wär dann wohl allgemeine Datenvielfalt, oder so...
Pfad zur Datei: ist selbsterklärend denke ich.
Kann sein, dass man Gänsefüsschen setzen muss, keine Ahnung - testen!

Jetzt hast du im Editor zeilenweise deine Ressourcen angegeben und speicherst das Werk erstmal als Datei mit der Endung ".rc" ab.
Dann gibt es in deinem Delphi Verzeichnis einen Ordner "bin" und in selbigem eine Datei brcc32.exe - die brauchen wir jetzt.
Die .rc Datei enthält ja nur die Dateinamen zu den Ressourcen die du haben willst. brcc32.exe nimmt sich diese Datei und packt die darin angegebenen Ressourcen in eine .res Datei.
Dazu ruft man die brcc32 in der Kommandozeile auf und übergibt als Parameter den Pfad zur .rc Datei
Ipp Zipp Zapp, fertig ist die .res Datei

Dieser zweite Weg ist zwar unter Umständen mehr Arbeit, aber dafür hat man dann auch n bisschen Hintergrundwissen abbekommen - kann ja nicht schaden.


...und einbinden

Soweit so gut, wir haben die Ressourcen alle in einer .res Datei und binden diese mit {$R lemon.RES} in unser Programm ein...
HA! Wenn man die .res Datei in das Hauptprojekt eingebunden hätte, wäre sie beim compilieren mit in die .exe hineinkompiliert worden.
Weil wir das aber nicht wollen, gehen wir her und erstellen in Delphi ein neues DLL Projekt.
Den vorgeschriebenen Quelltext ersetzen wir mit:

library lemon;

{$R lemon.RES}

begin
end.

wobei der Name der Library und "lemon.RES" natürlich auf eure Bedürfnisse angepasst werden sollte.
Wunderbar, jetzt speichern wir das Projekt, compilieren es und der ein oder andere kann auch "Hosianna" rufen, denn jetzt haben wir eine wunderschöne .dll Datei, die all unsere Ressourcen enthält. Und ich denke, jeder gewöhnliche Wald und Wiesen Depp, wird sich denken "Möh? DLL - Wasn datt da? Kann man das essen?? Lass ich mal lieber in Ruhe"
Hehe, aber wir sind noch nicht am Ziel... wir müssen die Daten ja auch wieder aus der DLL rausbekommen.

Ressourcen laden

Zurück in der Hauptanwendung gehen wir folgendermaßen vor:
Erstmal brauchen wir eine Variable vom Typen Papst ääh, Cardinal.
Der weisen wir mittels

var h: cardinal;
h := LoadLibrary('lemon.dll');

die eben erstelle DLL Datei zu.
Wenn man jetzt in LoadFromRessource oder ähnlichen Funktionen als Parameter eine Instance angeben sollst, ist das unsere Cardinal Variable, die ja auf die DLL zeigt.
Bei der glBitmap.pas laden wir allerdings immer aus Streams - und zwar so:

var myStream: TResourceStream
var h: Cardinal;
var foo: TglBitmap2D;

// DLL Laden
h := LoadLibrary('lemon.dll');

// Texturklasse erstellen
foo := TglBitmap2D.Create;

// Stream auf eine Ressource erstellen
myStream := TResourceStream.CreateFromID(h, 10, RT_RCDATA);
try
  // Bild aus Stream laden
  foo.LoadFromStream(myStream);
finally
  // Stream in jedem Falle wieder frei geben
  myStream.Free;
end;

// OpenGL Textur erstellen
foo.GenTexture;

// DLL Wieder entladen wenn sie nicht mehr gebraucht wird
FreeLibrary(h);

damit würden wir aus der Datei lemon.dll eine RCDATA Ressource mit dem Bezeichner 10 laden.
Wenn man den Ressourcen String-Namen gegeben hat, benutzt man "Create" statt "CreateFromId" und gibt den String an.

Nachwort

Sohohohoho, ich hoffe, ich habe alles Erwähneswerte erwähnt und wenn es jemandem hilft, dann bin ich mächtig stolz, auch mal ne Antwort gegeben zu haben, statt immer nur zu Fragen.
Abgesehen davon hoffe ich, dass ich an dieser Stelle Lossy eX für Geduld und Wissen danken darf :)
Ciao

Doppelreim