Bilder als Ressourcen: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
K (Ressourcen laden: Code angepasst)
K (Der Ausdruck ''<pascal>(.*?)</pascal>'' wurde ersetzt mit ''<source lang="pascal">$1</source>''.)
Zeile 50: Zeile 50:
 
Weil wir das aber nicht wollen, gehen wir her und erstellen in Delphi ein neues DLL Projekt.<br>
 
Weil wir das aber nicht wollen, gehen wir her und erstellen in Delphi ein neues DLL Projekt.<br>
 
Den vorgeschriebenen Quelltext ersetzen wir mit:<br>
 
Den vorgeschriebenen Quelltext ersetzen wir mit:<br>
<pascal>
+
<source lang="pascal">
 
library lemon;
 
library lemon;
  
Zeile 57: Zeile 57:
 
begin
 
begin
 
end.
 
end.
</pascal>
+
</source>
 
wobei der Name der Library und "lemon.RES" natürlich auf eure Bedürfnisse angepasst werden sollte.<br>
 
wobei der Name der Library und "lemon.RES" natürlich auf eure Bedürfnisse angepasst werden sollte.<br>
 
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 Resourcen 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"<br>
 
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 Resourcen 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"<br>
Zeile 66: Zeile 66:
 
Erstmal brauchen wir eine Variable vom Typen Papst ääh, Cardinal.<br>
 
Erstmal brauchen wir eine Variable vom Typen Papst ääh, Cardinal.<br>
 
Der weisen wir mittels<br>
 
Der weisen wir mittels<br>
<pascal>
+
<source lang="pascal">
 
var h: cardinal;
 
var h: cardinal;
 
h := LoadLibrary('lemon.dll');
 
h := LoadLibrary('lemon.dll');
</pascal>
+
</source>
 
die eben erstelle DLL Datei zu.<br>
 
die eben erstelle DLL Datei zu.<br>
 
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.<br>
 
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.<br>
 
Bei der glBitmap.pas laden wir allerdings immer aus Streams - und zwar so:<br>
 
Bei der glBitmap.pas laden wir allerdings immer aus Streams - und zwar so:<br>
<pascal>
+
<source lang="pascal">
 
var myStream: TResourceStream
 
var myStream: TResourceStream
 
var h: Cardinal;
 
var h: Cardinal;
Zeile 99: Zeile 99:
 
// DLL Wieder entladen wenn sie nicht mehr gebraucht wird
 
// DLL Wieder entladen wenn sie nicht mehr gebraucht wird
 
FreeLibrary(h);
 
FreeLibrary(h);
</pascal>
+
</source>
 
damit würden wir aus der Datei lemon.dll eine RCDATA Resource mit dem Bezeichner 10 laden.<br>
 
damit würden wir aus der Datei lemon.dll eine RCDATA Resource mit dem Bezeichner 10 laden.<br>
 
Wenn man den Ressourcen String-Namen gegeben hat, benutzt man "Create" statt "CreateFromId" und gibt den String an.
 
Wenn man den Ressourcen String-Namen gegeben hat, benutzt man "Create" statt "CreateFromId" und gibt den String an.

Version vom 10. März 2009, 19:03 Uhr

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 Resource Explorer", mit welchem man sich recht bequem seine Resourcen zusammen klicken kann. (Download: http://www.wilsonc.demon.co.uk/d10resourceeditor.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> <Resourcentyp> <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 Resourcen 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 Resourcen 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 Resource 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 Resource 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