*
* IFF-/ILBM-Saver (für nicht gepackte Bilder)
*
* inklusive Demoprogramm (was für ein Service!) -
* es wird der aktuell sichtbare Workbench-Screen
* gespeichert. Sie können ihn dann in ein Malprogramm
* einladen, ausdrucken und vor Ihren Monitor hängen ...
* oder Sie zeichnen einfach Icons für Geräte, die
* Sie überhaupt nicht besitzen, hinzu (15. Laufwerk,
* 5 000 000 000 GByte-CD-Drive (schön wär's), zehn
* verschiedene resetfeste RAM-Disks, eine Workbench 5.0-
* Diskette ... be creative!)
*
* created on 15/10/89 16:16:19 by Holger Gzella
*

                incdir "asm:"
                include "exec/exec_lib.i"
                include "graphics/graphics_lib.i"
                include "intuition/intuition_lib.i"
                include "libraries/dos_lib.i"

*
* Hier werden die ganzen Libraries geöffnet: DOS, Graphics, Intuition
*

                lea     DosName,a1              * DOS öffnen
                moveq.l #0,d0
                CALLEXEC OpenLibrary
                move.l  d0,DosBase

                lea     GfxName,a1              * Graphics öffnen
                moveq.l #0,d0
                CALLEXEC OpenLibrary
                move.l  d0,GfxBase

                lea     IntuiName,a1            * Intuition öffnen
                moveq.l #0,d0
                CALLEXEC OpenLibrary
                move.l  d0,IntuiBase

*
* Nun wird der Name, unter dem die Grafik gespeichert
* werden soll, von Tastatur eingelesen.
*

                move.l  DosBase,a6              * DosBase holen
                jsr     _LVOOutput(a6)          * Output-Handle holen
                move.l  d0,d1                   * nach d1
                move.l  #Text,d2                * Text-Adr. holen
                move.l  #12,d3                  * Länge: 12 Zeichen
                jsr     _LVOWrite(a6)           * und ausgeben!

                jsr     _LVOInput(a6)           * Input-Handle holen
                move.l  d0,d1                   * nach d1
                move.l  #Name,d2                * Namensspeicher holen
                move.l  #255,d3                 * Länge: max. 255 Zeichen
                jsr     _LVORead(a6)            * und lesen!

*
* Jetzt muß noch das Linefeed-Zeichen im Filenamen
* ausgemerzt werden!
*

                lea     Name,a0                 * Adresse laden
                subq.w  #1,d0                   * Zähler - 1
                move.b  #0,0(a0,d0.w)           * Linefeed löschen

*
* Die Intuition-Funktion OpenWorkBench versucht,
* eine ggf. geschlossene Workbench zu öffnen.
* Egal, ob das Öffnen nun klappte oder nicht, es wird
* auf jeden Fall ein Zeiger auf die Screen-Struktur
* des Workbench-Screens in D0 zurückgeliefert.
* OpenWorkBench benötigt keine Parameter und ist in
* einem Grafikbuch so unwichtig, wie nur wer weiß was.
* Daher habe ich im Fließtext auf eine nähere Besprechung
* verzichtet. Dies sei mir verziehen, da ich hier soetwas
* wie eine Besprechung nachhole.
*

                move.l  IntuiBase,a6            * IntuiBase laden
                jsr     _LVOOpenWorkBench(a6)   * Workbench öffnen
                move.l  d0,a1                   * Screen-Zeiger nach a1
                lea     44(a1),a1               * ViewPort holen
                lea     Name,a0                 * Filenamen holen
                move.l  #0,d0                   * x1: 0
                move.l  #0,d1                   * y1: 0
                move.l  #640,d2                 * x2: 640
                move.l  #256,d3                 * y2: 256
                move.l  #2,d4                   * Planes: 2
                bsr     SaveIFF                 * und sichern!

*
* Das Ende vom Lied: Libraries schließen und zurück!
*

                move.l  IntuiBase,a1
                CALLEXEC CloseLibrary

                move.l  GfxBase,a1
                CALLEXEC CloseLibrary

                move.l  DosBase,a1
                CALLEXEC CloseLibrary

                moveq.l #0,d0                   * das war's denn auch!
                rts

*
* Dies ist die Speicherroutine für nicht gepackte
* IFF-Bilder. Folgende Parameter müssen übergeben werden:
*
* A0: Zeiger auf den Namen der Datei
* A1: Zeiger auf den ViewPort des Bildes
* D0: x-Koordinate der linken, oberen Ecke des Ausschnittes.
* D1: y-Koordinate der linken, oberen Ecke des Ausschnittes.
* D2: x-Koordinate der rechten, unteren Ecke des Ausschnittes.
* D3: y-Koordinate der rechten, unteren Ecke des Ausschnittes.
* D4: Anzahl der zu speichernden Bitplanes
*

SaveIFF:        move.l  a0,FileName             * alle wichtigen
                move.l  a1,ViewPort             * Parameter
                move.l  4(a1),ColorMap          * sichern ...
                move.w  24(a1),pageWidth
                move.w  26(a1),pageHeight
                move.w  32(a1),viewModes
                move.l  36(a1),RasInfo

                move.w  d0,x
                move.w  d1,y
                move.w  d2,width
                move.w  d3,height
                move.b  d4,nPlanes

*
* Nun wird das Zielfile geöffnet.
*

                move.l  DosBase,a6
                move.l  FileName,d1
                move.l  #1006,d2
                jsr     _LVOOpen(a6)
                tst.l   d0
                beq     FileFault
                move.l  d0,FileHandle

*
* Jetzt werden die Längen berechnet und gesetzt.
*

                moveq.l #0,d0
                move.l  RasInfo,a0
                move.l  4(a0),a0
                move.l  a0,BitMap               * BitMap sichern
                move.w  0(a0),d0                * Bytes pro Zeile
                mulu.w  2(a0),d0                * mal Anzahl Zeilen
                mulu.w  d4,d0                   * mal Anzahl Planes
                move.l  d0,BODYlength           * ist gleich BODY-Länge
                add.l   #60,d0                  * + 60 (Länge aller Chunks)
                move.l  ColorMap,a0             * ColorMap holen
                move.w  2(a0),d5                * Anzahl Farben
                mulu.w  #3,d5                   * mal 3 (wg. Komponenten)
                add.l   d5,d0                   * addieren
                move.l  d0,FORMlength           * und das entspricht der
                                                * FORM-Länge!

*
* Hier wird der FORM-Chunk geschrieben.
*

                move.l  FileHandle,d1
                move.l  #FORM,d2
                move.l  #12,d3
                jsr     _LVOWrite(a6)

*
* Nun wird der BMHD-Chunk geschrieben.
*

                move.l  FileHandle,d1
                move.l  #BMHD,d2
                move.l  #28,d3
                jsr     _LVOWrite(a6)

*
* Erstmal muß CMAP angepaßt werden.
*

                moveq.l #0,d5                   * d5 zurücksetzen
                move.l  ColorMap,a0             * ColorMap laden
                move.w  2(a0),d5                * Anzahl Farben holen
                move.w  d5,d0                   * in d0 sichern
                mulu.w  #3,d0                   * mal 3 (wg. Komponenten)
                move.l  d0,CMAPlength           * ist die CMAP-Länge

*
* An dieser Stelle wird der CMAP-Chunk geschrieben.
*

                move.l  #CMAP,d2
                move.l  FileHandle,d1
                move.l  #8,d3
                jsr     _LVOWrite(a6)

*
* Nun müssen die Farben vom Amiga-Format ins
* CMAP-IFF-Format konvertiert werden.
*

                move.l  d5,d2                   * Anzahl Farben holen
                moveq.l #0,d0                   * Registerzähler auf 0

GetEntry:       movem.l d0,-(SP)                * d0 sichern
                move.l  ColorMap,a0             * ColorMap holen
                move.l  GfxBase,a6              * GfxBase nach a6
                jsr     _LVOGetRGB4(a6)         * Amiga-Farbe holen
                move.l  d0,d3                   * und nach d3 sichern
                movem.l (SP)+,d0                * d0 zurückholen

                move.l  d3,d4                   * d3 nach d4 kopieren
                lsr.w   #8,d4                   * durch 256 (Rotkomponente
                                                * isolieren)
                lsl.w   #4,d4                   * mal 16 (IFF-Abstufungen)
                move.b  d4,ActualRed            * und sichern!

                move.l  d3,d5                   * d3 nach d5 kopieren
                lsr.w   #4,d5                   * durch 16 (Grünkomponente
                                                * isolieren)
                lsl.w   #4,d4                   * Rot mal 16 (urspr.)
                sub.l   d4,d5                   * Rotkomponente abziehen
                lsl.w   #4,d5                   * Grün mal 16 (IFF-Abstuf.)
                move.b  d5,ActualGreen          * Grünkomponente sichern

                move.l  d3,d6                   * d3 nach d6 kopieren
                lsl.w   #4,d5                   * Grün mal 16 (urspr.)
                sub.l   d5,d6                   * von Blau abziehen
                lsl.w   #4,d4                   * Rot mal 16 (urspr.)
                sub.l   d4,d6                   * von Blau abziehen
                lsl.w   #4,d6                   * Blau mal 16 (IFF-Abstuf.)
                move.b  d6,ActualBlue           * und sichern ...

*
* An dieser Stelle wird die entsprechende Farbe
* - zerlegt in ihre Komponenten - in den CMAP geschrieben.
*

                movem.l d0/d2,-(SP)             * Register sichern
                move.l  DosBase,a6              * DosBase nach a6
                move.l  FileHandle,d1           * FileHandle laden
                move.l  #ActualRed,d2           * Rotkomponente laden
                moveq.l #1,d3                   * 1 Byte schreiben
                jsr     _LVOWrite(a6)           * und ins File!
                move.l  FileHandle,d1           * FileHandle laden
                move.l  #ActualGreen,d2         * Grünkomponente laden
                moveq.l #1,d3                   * 1 Byte schreiben
                jsr     _LVOWrite(a6)           * ab in die Datei!
                move.l  FileHandle,d1           * FileHandle laden
                move.l  #ActualBlue,d2          * Blaukomponente laden
                moveq.l #1,d3                   * nur 1 Byte
                jsr     _LVOWrite(a6)           * und ab!
                movem.l (SP)+,d0/d2             * Register holen

                addq.l  #1,d0                   * Registerzähler + 1
                cmp.w   d0,d2                   * fertig?
                bne     GetEntry                * nein!

*
* Nun wird der CAMG-Chunk geschrieben.
*

                move.l  #CAMG,d2
                move.l  FileHandle,d1
                move.l  #12,d3
                move.l  DosBase,a6
                jsr     _LVOWrite(a6)

*
* Die ersten acht BODY-Bytes werden schon mal gesichert.
*

                move.l  #BODY,d2
                move.l  FileHandle,d1
                move.l  #8,d3
                move.l  DosBase,a6
                jsr     _LVOWrite(a6)

*
* Jetzt wird der gesamte BODY-Chunk gesichert.
*

                moveq.l #0,d5                   * Zeilenzähler auf 0
                move.l  BitMap,a5               * BitMap laden
                move.b  nPlanes,d4              * Anzahl Planes laden
                ext.w   d4                      * auf Word-Größe bringen
                lea     8(a5),a5                * Planetabelle laden

LineLoop:       moveq.w #0,d6                   * Planezähler auf 0

PlaneLoop:      asl     #2,d6                   * Planeoffset mal 4
                move.l  0(a5,d6.w),d2           * entspr. Plane holen
                asr     #2,d6                   * Offset wieder durch 4

                move.l  FileHandle,d1           * FileHandle laden
                move.w  width,d3                * Breite in Pixeln laden
                lsr     #3,d3                   * durch 8 (=Bytes)
                mulu.w  d5,d3                   * mal Höhe
                add.l   d3,d2                   * zur Ursprungsadresse der
                                                * entsprechenden Plane
                                                * hinzuaddieren
                move.w  width,d3                * Breite in Pixeln laden
                lsr     #3,d3                   * durch 8 (=Bytes)
                jsr     _LVOWrite(a6)           * schreiben!

                addq.w  #1,d6                   * Planezähler + 1
                cmp.w   d6,d4                   * alle Planes?

                bne.s   PlaneLoop               * nein, noch nicht!

*
* Jetzt sind alle Planes einer Zeile geschrieben.
* Weiter geht's mit der nächsten Zeile (das ist
* momentan der Dinge Lauf!) ...
*

                addq.w  #1,d5                   * Zeilenzähler erhöhen
                cmp.w   height,d5               * alle Zeilen durch?
                bne.s   LineLoop                * nö, warum auch?!

*
* Das Bild ist nun gespeichert. Ein gewaltiges Werk!
*

                move.l  FileHandle,d1           * Datei schließen
                jsr     _LVOClose(a6)

*
* Und zurück ...
*

FileFault:      rts

*
* Der Datenteil ...
*

FileName:       dc.l    0                       * Name des Files
FileHandle:     dc.l    0                       * FileHandle
ViewPort:       dc.l    0                       * ViewPort
ColorMap:       dc.l    0                       * ColorMap
RasInfo:        dc.l    0                       * RasInfo
BitMap:         dc.l    0                       * BitMap

GfxBase:        dc.l    0                       * GfxBase
IntuiBase:      dc.l    0                       * IntuitionBase
DosBase:        dc.l    0                       * DosBase

ActualRed:      dc.b    0                       * Rotkomponente einer Farbe
ActualGreen:    dc.b    0                       * Grünkomponente einer Farbe
ActualBlue:     dc.b    0                       * Blaukomponente einer Farbe

*
* Systemkonstanten ...
*

GfxName:        dc.b    "graphics.library",0
 even
IntuiName:      dc.b    "intuition.library",0
 even
DosName:        dc.b    "dos.library",0
 even

*
* Der auszugebende Text:
*

Text:           dc.b    10,"Filename: ",0
 even

Name:           ds.b    256                     * für einen Filenamen

*
* Hier stehen die Daten der einzelnen Chunks ...
*

FORM:           dc.b    "FORM"                  * FORM-Chunk
FORMlength:     dc.l    0                       * FORM-Länge
                dc.b    "ILBM"                  * IFF-Typus

*
* Der BMHD-Chunk ...
*

BMHD:           dc.b    "BMHD"                  * Kennung
                dc.l    20                      * Länge
width:          dc.w    0                       * diverse Daten
height:         dc.w    0
x:              dc.w    0
y:              dc.w    0
nPlanes:        dc.b    0,0,0,0,0,0,10,11
pageWidth:      dc.w    0
pageHeight:     dc.w    0

*
* Der CMAP-Chunk ...
*

CMAP:           dc.b    "CMAP"                  * Kennung
CMAPlength:     dc.l    0                       * Länge

*
* CAMG ...
*

CAMG:           dc.b    "CAMG"                  * CAMG-Kennung
                dc.l    4                       * CAMG-Länge
                dc.w    0                       * 1. Word (unbenutzt)
viewModes:      dc.w    0                       * 2. Word (View-Modi)

*
* Der BODY-Chunk ...
*

BODY:           dc.b    "BODY"                  * Kennung
BODYlength:     dc.l    0                       * BODY-Länge

*
* Das Ende ...
*

                END

