Programmieren mit dem picture.datatype V43
Der picture.datatype V43, nachfolgend PDT43 genannt, gestattet die
Darstellung von Bildern mit bis zu 24 bit Farbtiefe. Sein Einsatz ist
nur im Zusammenhang mit Grafikkarten möglich. Es gibt unterschiedliche
Versionen des PDT43, die sich dem Vernehmen nach in ihrem Verhalten etwas
unterscheiden. Die nachfolgend geschilderten Erfahrungen beziehen sich auf
den PDT43 der Picasso96-Software. Diese arbeitet übrigens auch mit
CyberVision-Grafikkarten zusammen.
Vor einigen Wochen kaufte ich mir eine CyberVision64-Karte und hatte damit
erstmals die Möglichkeit, die besonderen Fähigkeiten des PDT43 auszutesten.
Zunächst interessierte mich, ob meine alte Routine zur Bilddarstellung
mittels DataTypes funktionierte. Sie tat es! Wie sich aber später
herausstellte war auch etwas Glück dabei, denn nicht alle Methoden, die in
der Dokumentation zum Standard-picture.datatype (Developer CD) empfohlen
werden, eignen sich.
Ich setze voraus, dass das allgemeine Vorgehen, um ein Bild auf den Screen
zu bringen, bekannt ist. Wem das alles neu ist, kann sich an
Beispielproggrammen (mit Sourcecode) orientieren, die sich auf der
Developer CD befinden (dto.c, dtpic.c). Außerdem gibt es im Archiv des
png.datatype von Cloanto ein Beispielprogramm mit gut dokumentierten
Sourcecode (ViewDT).
Der grobe Ablauf bis zum Erscheinen des Bildes ist folgender:
-
Neues Datatype-Objekt erzeugen mit NewDTObjectA().
PDTA_Remap muß auf FALSE gesetzt werden, denn wir wollen alle
Farben haben. Wenn man vorher nicht mit ObtainDataTypA() den
Dateityp geprüft hat, muss man außerdem DTA_GroupID, GID_PICTURE
angeben.
Nach erfolgreichem Aufruf sollte man DoMethodA() mit
DTM_PROCLAYOUT
GInfo = NULL
Initial = 1
aufrufen, was lt. Dokumentation das Layout/Remap auf dem eigenen
Prozess stattfinden lässt und nicht auf Intuitions. Da nun Intuition
gar kein Prozess ist, allenfalls ein Handler, bleibt mir der Sinn
dieser Methode verborgen. Sie schadet jedenfalls nichts und ist in
speziellen Fällen sogar besser.
-
Attribute des Objektes holen mit GetDTAttrsA().
Folgende Tags sollten angegeben werden:
PDTA_BitMap
PDTA_BitMapHeader
PDTA_ModeID
PDTA_CRegs
PDTA_NumColors
Wenn alles gut geht, gibt GetDTAttrs die Zahl der gelieferten
Attribute zurück, in diesem Fall muss es also eine 5 sein.
Wir bekommen einen Zeiger auf die BitMap des Bildes, die im Fall des
PDT43 aber nicht planar sein muss. Aus der BitMapHeader-Struktur
kann man Höhe, Breite und Tiefe des Bildes auslesen. Der Rest ist
nach meine bisherigen Erfahrungen unwichtig. Die CRegs sind ein Array
der Farbewerte in einem Format, das sich für LoadRGB32() eignet.
Jede Farbe ist hier durch 3 LONGs representiert, je eins für Rot,
Grün und Blau. Wenn NumColors beispielsweise 4 ist, enthält CRegs
4x3 LONGs.
-
CustomScreen öffnen mit OpenScreenTagList(), wobei die Werte aus dem
BitMapHeader verwendet werden.
-
Window auf dem Screen öffnen. Für die Bilddarstellung ist das zwar
nicht unbedingt nötig (s. dtpic.c), aber man will ja schließlich
Eingaben des Users empfangen.
-
Bild auf dem Scree/Window darstellen. Dazu gibt es verschiedene
Möglichkeiten, auf die ich später eingehe.
Nun zum Vorgehen mit dem PDT43:
Die Dokumentation dazu (picdt43.doc) ist äußerst spärlich, so dass man sich
vieles zusammenreimen und notfalls austesten muss. 15 Minuten mehr Zeitaufwand
für die Dokumentation hätten Programmierern wie mir viel Zeit erspart.
Über alle Programmierer summiert ergibt das sicher einige tausend Stunden ;-)
Um in den Genuss der besonderen Features des PDT43 zukommen, muss man beim
Aufruf von NewDTObjectA den Tag PDTA_DestMode mit ti_Data=MODE_43 (1) angeben.
Die Alternative, MODE_42 (0), veranlasst den PDT43, eine planare
Standard-BitMap mit der Maximaltiefe von 8 bit zurückzugeben, so jedenfalls
die Dokumentation.
Bevor man den MODE_43 aktivieren will, stellt sich zunächst die Frage:
Liegt der PDT43 überhaupt vor? Um das rauszukriegen, sind drei
Vorgehensweisen denkbar:
-
Prüfen, ob die cybergraphics.library geöffnet ist.
Man könnte das mit OpenLibrary tun, hat dann aber
Overhead, wenn es ein System ohne Grafikkarte ist.
Alternative: FindName verwenden
-
OpenLibrary mit libs:datatypes/picture.datatype,43
aufrufen. Auch hier Overhead, wenn eine ältere Version
vorliegt.
-
PDTA_DestMode auf Verdacht einsetzen und wenn der
vorhandene picture.datatype diesen Tag nicht versteht,
schlägt NewDTObjectA vermutlich fehl. Man könnte dann
einen zweiten Versuch ohne PDTA_DestMode starten.
(Habe ich nicht ausprobiert.)
Methode 1 mit FindName erscheint mir die eleganteste. Die
cybergraphics.library ist auf jeden Fall schon geöffnet, wenn das
System eine Grafikkarte hat. FindName() findet sie also.
Nun das Ergebnis beim Aufruf von NewDTObjectA mit und ohne
PDTA_DestMode + MODE_43: Es gab keinen!
Ob in den V43-Modus geschaltet wird oder nicht, hing offensichtlich nur von
den SubDataTypes und der Bildtiefe ab. Bei SubDataTypes (ilbm.datatype,
gif.datatype...), die den V43-Modus nicht kennen, wird eine planare
Standard-BitMap erzeugt, bei den anderen z. T. schon ab 8 bit Tiefe eine
nicht planare.
Ob die BitMap planar ist oder nicht, entscheidet über das weitere Vorgehen.
Deshalb muss das zunächst geprüft werden. Wenn im BitMapHeader depth > 8 ist,
hat man es auf jeden Fall mit einer Nicht-Standard-BitMap zu tun. Wenn sie
= 8 ist, muss man entweder graphics.library/GetBitMapAttr mit BMA_FLAGS
aufrufen und dann auf BMF_STANDARD prüfen oder die analoge Funktion der
cybergraphics.library GetCyberMapAttr verwenden. Diese liefert auch
Informationen über das Pixelformat, das man aber nicht zu kennen braucht.
Wie bekomme ich nun das Bild - möglichst in True/HighColor - auf den Screen?
Ich erwähnte schon, dass es mehrere Möglichkeiten gibt:
-
OpenScreenTagList mit width, height, depth aus dem BitMapHeader
und den Tags SA_DisplayID, SA_OverScan, SA_Colors32 aufrufen.
Die DisplayID ist die von GetDTAttrsA zurückgelieferte.
SA_Colors32 braucht als Argument einen Zeiger auf einen Array, der
aus dem CRegs-Array erst erzeugt werden muss. Näheres dazu in ViewDT.c
oder graphics/LoadRGB32. Die Angabe von SA_Colors32 ist übrigens
überflüssig, wenn depth größer als 8 ist. Die Farben sind in der
BitMap dann pixelweise verschlüsselt. Bei nichtplanaren BitMaps
mit depth=8 muss SA_Colors32 angegeben werden bzw. die Farben müssen
nach Öffnen des Screens mit LoadRGB32 gesetzt werden.
-
Wenn die BitMap planar ist (und nur dann!), kann man OpenScreenTagList
mit SA_BitMap einen Zeiger auf die BitMap übergeben. Nochmals, weil's
wichtig ist:
!!!SA_BitMap NICHT verwenden, wenn keine planare BitMap vorliegt!!!
Aus diesem Grund stürzen die erwähnten Beispielprogramme mit Ausnahme
von dto, das den WorkbenchScreen und PDTA_Remap=TRUE verwendet, ab,
sobald ein SubDataType eine Nicht-Standard-BitMap liefert. Aber
gesetzt den Fall, man hat eine planare BitMap, dann erscheint das Bild
sofort auf dem (nackten) Screen. Öffnet man anschließend ein Window,
verschwindet das Bild allerdings wieder, und man braucht es doch
unbedingt.
Der Ausweg aus dem Dilemma ist, ein rahmenloses Window von 1x1 Größe
zu öffnen, wodurch nur 1 Pixel des Bildes verdeckt wird. Sinnvoll kann
dieses Vorgehen dann sein, wenn der zu öffnende Screen größer ist als
der DisplayClip (der sichtbare Bereich) und damit voraussichtlich
viel Speicher verschlingt. Man spart nämlich beträchtlich an Speicher
durch Angabe von SA_BitMap, weil OpenScreenTagList dann keine eigene
(leere) BitMap alloziert. Bei "normalen" Amigas würde dies wertvolles
Chip-RAM kosten, bei Amigas mit Grafikkarte wird Fast-RAM alloziert.
-
Auf dem Screen wird ein Fenster geöffnet mit den Dimensionen des
Bildes und anschließend AddDTObject aufgerufen. Das ist die Methode,
von der im picdt43.doc behauptet wird, dass man sich nicht darum zu
kümmern brauche, ob MODE_43 möglich ist oder nicht. Der
picture.datatype erledigt das Rendern des Bildes dann selbst und
verwendet den MODE_43, wenn möglich.
Bevor AddDTObject aufgerufen wird, ist allerdings noch einiges zu
beachten: Das Window muss die IDCMP-Flags IDCMPUPDATE und REFRESHWINDOW
haben, unter den Window-Flags muss(?) SIMPLE_REFRESH sein.
Nach dem Öffnen muss das DataTypeObject noch darüber informiert werden,
wo es sich auf dem Window platzieren soll. Deshalb wird mit
SetDTAttrsA und den Tags GA_Top, GA_Left, GA_Width, GA_Height alles
festgelegt. Außerdem muss es mit ICA_Target, -1 veranlasst werden,
seine Meldungen an den UserPort des Windows zu schicken.
Nach Eintreffen einer IDCMPUPDATE-Message findet sich im Feld IAddress
ein Zeiger auf eine Tagliste, die Einzelheiten über den Typ der
Message enthält (DTA_SYNC, DTA_ERRORNUMBER, DTA_PRINTERSTATUS...).
Man kann diese Tagliste "zu Fuß" durchgehen oder die Funktionen der
utility.libray verwenden.
-
Statt AddDTObject wird das Bild bzw. die BitMap mit BltBitMapRastPort
gerendert. Diese Methode hat bisher immer funktioniert, scheint also
die einfachste zu sein. Wenn man allerdings vor hat, dem User die
Möglichkeit zu geben, das Bild auszudrucken, dann ist Methode 2
besser, weil PrintDTObjectA() eingesetzt werden kann. Der Druck
erfolgt mit dieser Funktion asychron, d. h. das Programm kann sich
anderen Dingen zuwenden und bekommt, wenn der Druck beendet ist oder
fehlschlug, eine UPDATE-Message vom Typ DTA_PrinterStatus.
PrintDTObjectA, ohne AddDTObject vorher aufgerufen zu haben, geht
zwar, ist aber gefährlich, weil man keine UPDATE-Message empfängt,
und ein vorzeitiges DisposeDTObject zu einem Hänger führt, wenn
der Druck noch nicht beendet ist.
So, das war's. Falls jemand andere Erfahrungen gemacht hat und an dieser
Stelle darüber berichtet, würde es mich freuen.
Jürgen Klawitter (25.8.00)
Zurück