Willkommen zum Workshop"Einfach/e Plugin's mit Delphi" für Einsteiger |
Hinweis: Alle genannten Produkte sind eingetragene Warenzeichen der jeweiligen Hersteller und unterliegen den jeweiligen Copyrightbestimmungen.
Vorbereitungen zu diesem Workshop
Eine einfache Funktion schreiben
Stolperfallen und Fehlermeldungen
Anhang (einige Acknex-Typen, -Strukturen und -Funktionen)
Um ein Plugin für das Conitec 3DGS mit Borland Delphi zu erstellen,
brauchst Du eine unterstützte Version von Borland Delphi (hier Version
7/personal).
Das SDK stellt die notwendigen Ressourcen für Borland Delphi ab der Version
3 sowie für Borland C++ Builder 3/ und Borland 5.5 bereit.
Das SDK wurde von mir für 3DGS Version 6.31 verwendet.
Die gezeigten Bilder von Borland Delphi wurden von der englischen Version personal
7.0 genommen; die gezeigten Bereiche sind in den unterschiedlichen Delphi-Versionen
evtl. anders benannt und/oder woanders zu finden.
Auf der Internetseite von CONITEC (http://www.3dgamestudio.de/) findest du im Bereich Downloads unter Software / Updates das A5 Delphi Plugin SDK.
1. Lade dir diese Datei herunter und entpacke sie auf deinem Rechner in ein beliebiges Verzeichnis.
2. Erstelle in dem Lib-Verzeichnis (z.B.: c:\programme\entwicklung\borland\delphi7\lib\) deiner Delphi-Installation ein Unterverzeichnis mit dem Namen 3dgs und kopiere alle Dateien aus dem SDK-Verzeichnis deiner Delphi-Version (hier delphi7\).
3. Nun musst du noch aus dem SDK-Verzeichnis Delphi_DX8 die Datei A5dll2.pas in das 3dgs-Unterverzeichnis kopieren.
Das sollte dann etwa so aussehen:
4. Starte nun Borland Delphi und starte in der Komponentenverwaltung die Packet-Installation:
Wechsle in das \Lib\3dgs-Verzeichnis und wähle die Datei A5SDK70.bpl aus.
Die Option "Build with runtime package" muss dekativiert werden, da die erzeugten DLL's sonst nicht von der Acknex-Engine erkannt werden!
Damit ist die Installation für der Erstellen einfacher Plugins auch schon erledigt!
Ein Plugin zu erstellen ist sehr einfach:
1. Starte Borland Delphi und erstelle ein neues DLL-Projekt:
2. Nun wird automatisch ein DLL-Grundgerüst erstellt, dass etwa so aussehen sollte:
library Project1; { Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. } uses
SysUtils,
Classes; {$R *.res} begin
end.
Wir benötigen neben dieser library-Definition auch noch ein Unit,
in dem wir unsere Funktionen schreiben.
Hierzu erstellen wir ein neues Unit: (Menue [File]-[New]-[Unit].
Um die Verbindung zu der 3DGS-Welt "zu öffnen" (also deren
Typen und Formate kennen), müssen wir in unser neues unit die Unit A5dll2.pas
einbinden.
Hierzu erweitern wir lediglich die uses-Zeile der Interface-Deklaration
um den Eintrag A5DLL2:
unit unit1; interface uses SysUtils, Classes, A5DLL2; implementation end.
Das Grundgerüst ist nun erstellt und kann vorsorglich abgespeichert
werden.
Ich nenne die library "dll_3dgs.dpr" und das unit
"my_plugin.pas".
Das oben erstellte Grundgerüst ist der Rahmen für all unsere Funktionen, um die wir die Acknex-Engine erweitern wollen.
Denkbar sind u.A. komplexe mathematische Funktionen, Listenverarbeitung,
Dateinhandling, Ressourcenverwaltung, ...
Oder es lassen sich - durch die der Acknex-Engine zugrunde liegenden parallelen
Arbeitsweise - leicht grafische Simulationen erstellen mit hohem parallene Verarbeitungsaufwand
erstellen.
Exemplarisch möchte ich hier nur eine sehr einfach Funktion schreiben,
die lediglich eine Versionsnummer zurück liefert.
Wir erweitern nun unser unit (ich nannte es beim Abspeichern "my_plugin"
um die notwendigen Bestandteile einer DLL-Function:
unit my_plugin; interface uses SysUtils, Classes, A5DLL2; { Prototype }
function GetVersion :gsfixed; cdecl; exports GetVersion; implementation { GetVersion - returns a (version-)number }
function GetVersion() : gsfixed;
begin
result:=INT2FIX(5);
end;
end.
Das war's schon!
Das Projekt noch kompilieren (builden) und die DLL (dll_3dgs.dll) kann in ein 3DGS-Projekt kopiert werden.
Wenn du bis hier gekommen bist - da bin ich mir sicher - kannst du auch eine
WDL (world-definition-language) -Datei lesen und verstehen.
Hier wiederum ein sehr einfaches Beispiel, wie die selbst programmierten Funktionen
eingesetzt werden können:
(Die entscheidenen Stellen sind hervorgehoben)
//-------------------------------------------------------------------------------
// Workshop: Plugins with borland delphi
// author: u.seiffert
// date: 10.05
//-------------------------------------------------------------------------------
var dll_handle; // handle for dll's
var dll_version = 0;
//-------------------------------------------------------------------------------
var video_mode = 6;
var video_screen = 2;
var video_depth = 16;
//-------------------------------------------------------------------------------
font arial_font = "Arial",1,20; // truetype font
text ver_text {
pos_X = 100;
pos_Y = 200;
font = arial_font;
strings = 1;
string = "DLL-Version:";
flags = VISIBLE;
}
//-------------------------------------------------------------------------------
panel ver_info {
pos_X = 240;
pos_y = 200;
digits = 0,0,4,arial_font,1,dll_version;
flags = REFRESH,VISIBLE;
}
//-------------------------------------------------------------------------------
// pre-declaration
dllfunction GetVersion();
//-------------------------------------------------------------------------------
// main-function
function main {
// load dummy-level
level_load("demo.wmb");
wait(3);
// call DLL-function
dll_handle=dll_open("dll_3dgs.dll");
dll_version = GetVersion();
dll_close(dll_handle);
// wait for an end...
while(1){
wait(1);
}
}
Es gibt wenige aber entscheidende Dinge, die bei der Installation und dem
Erzeugen von Plugin-DLL's auftreten können.
Hier ist eine Liste der Fehler, die mir unterlaufen sind:
Typ |
3DGS-Typ |
Delphi-Beispiel |
GSFixed |
Zahlen |
Je nach Verwendung der Hilfsroutinen ein longint oder ein float 22.10: function GetVersion() : gsfixed; |
PA4_STRING |
string |
Struktur mit chars und Länge: str_pascal:=StrPas(str_3dgs^.chars); |
PA4_ENTITY |
entity |
Struktur siehe A5DLL2.PAS |
PA4_TEX |
textur |
Struktur siehe A5DLL2.PAS |
PA4_BMAP |
bitmap (bmp, pcx, tga) |
Struktur siehe A5DLL2.PAS |
PA4_PARTICLE |
particle |
Struktur siehe A5DLL2.PAS |
PA4_FONT |
font |
Struktur siehe A5DLL2.PAS |
PA4_TEXT |
text |
Struktur siehe A5DLL2.PAS |
PA4_PANEL |
panel |
Struktur siehe A5DLL2.PAS |
PA4_VIEW |
view |
Struktur siehe A5DLL2.PAS |
Um mit dem Typ gsfixed arbeiten zu können, hat Conitec eine Hand
voll Funktionen zur Verfügung gestellt,
die den Pascal-Typ Longint in die Acknex-Formate wandelt:
function INT2FIX(i : LongInt) : GSFixed; |
Macht aus einem Pascal-Longint ein Acknex-Fixtype ack_fix = INT2FIX(pas_long); |
function FIX2INT(x : GSFixed) : LongInt; |
Macht aus einem Acknex-Fixtype ein pascal-Longint pas_int := FIX2INT(ack_fix); |
function FIX2FLOAT(x : GSFixed) : Double; |
Macht aus einer Acknex-Kommazahl einen Pascal-Double-Wert pas_double := FIX2FLOAT(ack_fix);pas_double := FIX2FLOAT(ack_fix); |
function FLOAT2FIX(f : double) : GSFixed; |
Macht aus einem Pascal-Double-Wert eine Acknex-Kommazahl ack_fix = FLOAT2FIX(pas_double); |
Stand: 10.2005
Autor: Ulrich Seiffert (3dgs@ulrich-seiffert.de)