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.

 

Inhalt:

Vorbereitungen zu diesem Workshop

Installation des SDK

Grundgerüst erstellen

Eine einfache Funktion schreiben

DLL-Funktion in WDL einbinden

Stolperfallen und Fehlermeldungen

Anhang (einige Acknex-Typen, -Strukturen und -Funktionen)


Vorbereitungen zu diesem Workshop

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.


Installation des SDK

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!


Grundgerüst erstellen

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:

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:

Das Grundgerüst ist nun erstellt und kann vorsorglich abgespeichert werden.
Ich nenne die library "dll_3dgs.dpr" und das unit "my_plugin.pas".


Eine einfache Funktion schreiben

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:

Das war's schon!

Das Projekt noch kompilieren (builden) und die DLL (dll_3dgs.dll) kann in ein 3DGS-Projekt kopiert werden. 

Infos:
  1. Im Interface muss ein Prototyp (Funktionskopf) der Funktion/en definiert werden. Der Parameter cdecl; erzeugt in der DLL eine C-konforme Parameterübergabe, exports definiert den Namen der DLL-Funktion.
  2. Im der Implemention werden die Funktionen ausprogammiert.
  3. Die Typen und Formate, sowie wichtige Konvertierungsroutinen sind in der Unit A5DLL2.PAS enthalten, die Wichtigsten sind im Anhang dieses Workshops kurz besprochen.


DLL-Funktion in WDL einbinden

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)

Info:
  1. Es ist erforderlich, die DLL mit einem handle (Pointer) zu öffnen, um die Funktionen darin anzusprechen und die DLL wieder zu schließen.
  2. Es können mehrere DLL gleichzeitig geöffnet werden
  3. Vor dem Verwenden einer DLL-Funktion muss die Funktion mit dem Befehl dllfunction <Funktionsname> bekannt gegeben werden.
  4. Funktionsnamen sind im gegensatz zu der Pascal-Konvention "case-sensitiv" (Groß- und Kleinschreibung wird beachtet!)!


Stolperfallen und Fehlermeldungen 

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:

  1. Die richtigen SDK-Dateien für die Delphi-Version müssen verwendet werden und im lib-Pfad von Delphi sein.
  2. Der aktuellere Acknex A5 DLL interface header (A5DLL2.PAS) aus dem SDK-Verzeichnis Delphi_8DX muss verwendet werden.
  3. Das Packet A5SDK70.bpl muss importiert werden und es dürfen keine runtime-packete erstellt werden!
    1. Kommt es während des Kompilierens zu Fehlermeldungen bzgl. Versionskonflikten, muss das runtime-packet einmal neu erstellt werden.
    2. Eine neu erstellte DLL mit unserer einen Funktion sollte ca. 86kByte groß sein. Ist sie kleiner -> runtime-packet ausschalten.
  4. Die DLL muss von dem WDL-Script "direkt erreichbar" sein. Die DLL also in das 3DGS-Programmverzeichnis kopieren oder mit Pfadangabe in der dll_open()-Anweisung.
  5. Öffne die DLL mit dll_handle=dll_open(...);, bevor du eine Funktion daraus verwendest.
  6. Eine DLL ist bis zu deren Entladen im Speicher: Globale Variablen in der DLL bleiben solange auch (nur) erhalten!


Anhang

Acknex-Typen: (die genauen Strukturen bitte aus Datei A5DLL2.PAS)

Typ

3DGS-Typ

Delphi-Beispiel

GSFixed

Zahlen

Je nach Verwendung der Hilfsroutinen ein longint oder ein float 22.10:

function GetVersion() : gsfixed;
begin
  result:=INT2FIX(5);
end;

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

 

Hilfsfunktionen:

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)