summaryrefslogtreecommitdiff
path: root/Source/SaveClip.S
diff options
context:
space:
mode:
authorChristian A. Weber <chris@gna.ch>1992-05-12 22:26:12 +0000
committerChristian A. Weber <chris@gna.ch>1992-05-12 22:26:12 +0000
commit36c824864c02f0a3f62c8a1d365d1670835c8c96 (patch)
treef3f433e4af522925d4c91f56865d38efaf83a456 /Source/SaveClip.S
downloadiff-library-36c824864c02f0a3f62c8a1d365d1670835c8c96.tar.gz
iff-library-36c824864c02f0a3f62c8a1d365d1670835c8c96.tar.bz2
iff-library-36c824864c02f0a3f62c8a1d365d1670835c8c96.zip
Initial revision
Diffstat (limited to 'Source/SaveClip.S')
-rw-r--r--Source/SaveClip.S490
1 files changed, 490 insertions, 0 deletions
diff --git a/Source/SaveClip.S b/Source/SaveClip.S
new file mode 100644
index 0000000..eb2fbaf
--- /dev/null
+++ b/Source/SaveClip.S
@@ -0,0 +1,490 @@
+**
+** $Id: $
+** $Revision: $
+**
+** $Filename: SaveClip.S $
+** $Author: Christian A. Weber $
+** $Release: 19.1 $
+** $Date: 92/05/11 21:11:27 $
+**
+** iff.library/IFFLib_SaveClip
+**
+** COPYRIGHT (C) 1987-1992 BY CHRISTIAN A. WEBER, BRUGGERWEG 2,
+** CH-8037 ZUERICH, SWITZERLAND. ALL RIGHTS RESERVED. NO PART
+** OF THIS SOFTWARE MAY BE COPIED, REPRODUCED, OR TRANSMITTED
+** IN ANY FORM OR BY ANY MEANS, WITHOUT THE PRIOR WRITTEN PER-
+** MISSION OF THE AUTHOR. USE AT YOUR OWN RISK.
+**
+
+
+ IDNT IFFLib_SaveClip
+ SECTION text,CODE
+
+ INCLUDE "IFFLib.i"
+
+ XREF SetError,ClearError,CalcViewModes
+ XDEF SaveClipFunc
+
+
+******* iff.library/IFFLib_SaveClip *****************************************
+*
+* NAME
+* IFFLib_SaveClip -- save a part of a BitMap as an IFF-file
+*
+* SYNOPSIS
+* result = IFFLib_SaveClip
+* D0 ( filename, bitmap, coltab, flags, xoff, yoff, width, height )
+* A0 A1 A2 D0 D1 D2 D3 D4
+*
+* FUNCTION
+* Save a part of a BitMap as an IFF file
+*
+* INPUTS
+* filename - Name of the IFF file to create
+* bitmap - Pointer to the BitMap holding your picture
+* colortable - Pointer to an Amiga ColorTable structure or zero
+* (if colortable = 0, no CMAP chunk will be generated).
+* flags - Bit 0: 1 = Use the "CmpByteRun1" compression algorythm,
+* 0 = Save the file uncompressed
+* Bit 7: 1 = This is a HAM (Hold and modify) picture
+* 0 = This is a normal or Extra-Halfbrite picture
+* xoff - X offset of the clip to be saved (bytes from the left)
+* yoff - Y offset of the clip to be saved (lines from the top)
+* width - width in bytes of the rectangle
+* height - height in lines of the rectangle
+*
+* RESULTS
+* Non-zero if successful, 0 if error, Call IFFLib_IFFError() to
+* know more about the reason of the failure
+*
+* NOTE
+* This routine needs 620 bytes of stack space
+*
+* BUGS
+* The width of the rectangle will be rounded to WORD boundaries,
+* because DPAINT wants it!
+*
+* SEE ALSO
+* IFFLib_SaveBitMap()
+*
+*****************************************************************************
+
+MAXPLANES: EQU 24 ; Höchstens 24 Bitplanes
+
+iffhd: equ 0 ; FORM
+iffsize: equ 4 ; .... ILBM
+
+bmhdchunk: equ iffsize+8 ; BMHD
+bmhdsize: equ bmhdchunk+4 ; ....
+bmhd: equ bmhdsize+4 ; bmhd-Struktur
+
+camgchunk: equ bmhd+bmh_SIZEOF ; CAMG
+camgsize: equ camgchunk+4 ; ....
+camg: equ camgsize+4 ; 0000ViewModes
+
+cmapchunk: equ camg+4 ; CMAP
+cmapsize: equ cmapchunk+4 ; ....
+cmap: equ cmapsize+4 ; Farbwerte
+
+bodychunk: equ cmap+(3*512) ; BODY
+bodysize: equ bodychunk+4 ; ....
+
+xoffset: equ bodysize+4
+yoffset: equ xoffset+2
+width: equ yoffset+2
+height: equ width+2
+
+sb_datasize: equ height+2 ; Gesamt-Datengrösse
+
+
+SaveClipFunc: movem.l d2-d7/a2-a6,-(SP)
+ suba.w #sb_datasize,SP ; Speicher reservieren
+ movea.l a6,a5 ; IFFBase
+ move.l a0,d6 ; D6 : Filename
+ movea.l a1,a3 ; A3 : BitMap
+ movea.l SP,a4 ; A4 : wird BitMapHeader
+
+ move.w d1,xoffset(SP)
+ move.w d2,yoffset(SP)
+ bclr #0,d3 ; Breite WORD align für DPaint
+ move.w d3,width(SP)
+ move.w d4,height(SP)
+
+ *** FORM....ILBM-Header & BMHD-Chunk initialisieren (im Speicher)
+
+ move.l #'FORM',(a4)+ ; Ein IFF-Formular
+ moveq.l #cmap,d7 ; 'ILBM'+BMHD+CAMG+CMAP+BODY
+ move.l d7,(a4)+ ; eintragen
+ move.l #'ILBM',(a4)+ ; File-Typ
+
+ move.l #'BMHD',(a4)+ ; Chunk-Name eintragen
+ moveq.l #bmh_SIZEOF,d7
+ move.l d7,(a4)+ ; Chunk-Size eintragen
+ move.b d0,bmh_Compression(a4) ; Cruncher-Typ merken
+
+ clr.b bmh_Masking(a4)
+ clr.b bmh_Pad1(a4)
+ clr.w bmh_TranspCol(a4)
+ move.w xoffset(SP),d0
+ lsl.w #3,d0 ; Pixel
+ move.w d0,bmh_XPos(a4) ; X-Position
+ move.w yoffset(SP),bmh_YPos(a4) ; X-Position
+ move.w #$0A0B,bmh_XAspect(a4) ; X- und Y-Aspect zusammen!
+ move.b bm_Depth(a3),bmh_nPlanes(a4)
+
+ lsl.w #3,d3 ; Breite mal 8
+ move.w d3,bmh_Width(a4) ; gibt Breite in Pixel
+ move.w d3,bmh_PageWidth(a4)
+
+ move.w d4,bmh_Height(a4) ; Bildhöhe eintragen
+ move.w d4,bmh_PageHeight(a4)
+
+ *** CAMG-Chunk generieren (immer)
+
+ move.l #'CAMG',camgchunk(SP) ; Chunk-Name
+ moveq #4,d7
+ move.l d7,camgsize(SP) ; Chunk-Size
+ movea.l a4,a0 ; struct BitMapHeader
+ bsr CalcViewModes ; ViewModes nach d0
+ bclr.b #7,bmh_Compression(a4) ; HAM gewünscht ?
+ beq.s 1$ ; nein --->
+ bset #11,d0 ; HAM-Bit setzen
+1$: move.l d0,camg(SP) ; ViewModes eintragen
+
+ *** CMAP-Chunk generieren, falls notwendig (im Speicher)
+
+ move.l #-8,cmapsize(SP) ; falls no CMAP: -'CMAP....'
+
+ move.l a2,d0 ; tst.l a2
+ beq.s nocmap
+
+ lea cmapchunk(SP),a1 ; Hierhin will ich den Chunk
+ move.l #'CMAP',(a1)+ ; Chunkname
+ moveq #1,d0
+ moveq #0,d1
+ move.b bm_Depth(a3),d1
+ cmpi.b #24,d1 ; Ist's ein 24-Bitplane-Bild ?
+ bne.s .No24 ; nein --->
+ moveq #8,d1 ; Sonst immer 256 Farben
+.No24:
+ lsl.w d1,d0 ; d0 := 2 ^ D1 = Anzahl Farben
+ move.w d0,d2 ; D2 : Anzahl Farben
+ mulu.w #3,d0 ; 3 Bytes pro Farbe
+ addq.l #2,d0
+ andi.w #~3,d0 ; auf LONG alignen
+ move.l d0,(a1)+ ; Chunklänge
+
+ subq.w #1,d2 ; für dbf
+3$: move.w (a2)+,d0
+ lsl.w #4,d0
+ move.b d0,2(a1) ; blau
+ lsr.w #4,d0
+ andi.b #$f0,d0
+ move.b d0,1(a1) ; grün
+ lsr.w #4,d0
+ andi.b #$f0,d0
+ move.b d0,(a1) ; rot
+ addq.w #3,a1
+ dbf d2,3$
+
+ *** File öffnen, IFF-Header auf Disk schreiben (vorläufig!)
+
+nocmap: move.l d6,d1 ; FileName
+ move.l #MODE_NEWFILE,d2
+ movea.l ib_DOSBase(a5),a6
+ JSRLIB Open
+ move.l d0,d7 ; D7 : FileHandle
+ beq writeerror
+
+ move.l cmapsize(SP),d0 ; CMAP-Grösse
+ add.l d0,iffsize(SP) ; zu Header-Grösse dazu
+
+ move.l d7,d1 ; File
+ move.l SP,d2 ; Adr : IFF-Header
+ moveq #cmap+8,d3 ; Länge des Headers + 8
+ add.l cmapsize(SP),d3 ; Plus Länge des CMAP-Chunks
+ JSRLIB Write ; schreiben
+ tst.l d0 ; Fehler ?
+ bmi.s writeerror ; ja!
+
+ *** BODY-Daten schreiben, evtl. komprimiert
+
+ tst.b bmh_Compression(a4) ; compacten ?
+ bne.s 1$ ; ja!
+ bsr VanillaSave
+ bra.s 2$
+1$: bsr CrunchSave
+2$: tst.l d0 ; Fehler ?
+ bmi.s writeerror ; ja!
+
+ move.l d0,d3 ; Body-Länge
+ addq.l #3,d3 ; auf nächstes LONG aufrunden
+ and.b #%11111100,d3 ; und LONG-alignen
+ move.l d3,bodysize(SP) ; aligned BODY-Grösse
+ add.l d3,iffsize(SP) ; zu Header-Grösse dazu
+ sub.l d0,d3 ; D3 := Wieviele Bytes zuviel
+
+ tst.l d3 ; Align-Grösse = 0 ?
+ beq.s 3$ ; ja -> nichts schreiben
+ move.l d7,d1 ; File
+ clr.l -(SP) ; Nullen machen
+ move.l SP,d2 ; adr
+ JSRLIB Write ; schreiben
+ addq.l #4,SP ; Stack cleanen
+ tst.l d0 ; Fehler ?
+ bmi.s writeerror ; ja!
+
+ *** IFF-Header nochmals schreiben & BODY-Header, diesmal korrekt
+
+3$: move.l d7,d1 ; File
+ moveq.l #0,d2 ; Position
+ moveq.l #OFFSET_BEGINNING,d3 ; Modus
+ JSRLIB Seek
+
+ move.l d7,d1 ; File
+ move.l SP,d2 ; Adr : IFF-Header
+ moveq.l #cmap,d3 ; Länge des Headers
+ add.l cmapsize(SP),d3 ; Plus Länge des CMAP-Chunks
+ JSRLIB Write ; schreiben
+ tst.l d0 ; Fehler ?
+ bmi.s writeerror ; ja!
+
+ lea bodychunk(SP),a0
+ move.l #'BODY',(a0) ; Chunk-Namen eintragen
+ move.l d7,d1 ; File
+ move.l a0,d2 ; Adr
+ moveq #8,d3 ; Len
+ JSRLIB Write ; Body-Header schreiben
+ tst.l d0 ; Fehler ?
+ bmi.s writeerror ; ja!
+
+ move.l d7,d1 ; File
+ JSRLIB Close
+ ;; moveq.l #0,d7 ; File ungültig
+
+ bsr ClearError ; Error löschen, D0 := 1
+ bra.s SaveClip_End
+
+writeerror: move.l d7,d1 ; File
+ beq.s 1$ ; schon / nochzu!
+ JSRLIB Close
+1$: moveq #IFF_WRITEERROR,d0
+ bsr SetError ; Error setzen, D0 := 0
+
+SaveClip_End: adda.w #sb_datasize,SP ; Speicher wirder freigeben
+ movem.l (SP)+,d2-d7/a2-a6
+ rts
+
+
+***************************************************************************
+************** V A N I L L A S A V E ************************************
+***************************************************************************
+
+vs_planes: equ 0 ; ARRAY[0..MAXPLANES-1] OF PlanePtr
+vs_chunksize: equ vs_planes+4*MAXPLANES
+vs_linksize: equ vs_chunksize+4
+
+VanillaSave: movem.l d2-d6/a2-a4,-(SP) ; 8 Register retten
+ lea 8*4+4(SP),a4 ; A4 : Global data Ptr
+ suba.w #vs_linksize,SP ; lokalen Datenraum schaffen
+
+ *** Chunk-Grösse berechnen und merken
+
+ move.w width(a4),d0 ; Breite in Bytes
+ moveq #0,d1
+ move.b bm_Depth(a3),d1
+ mulu d1,d0 ; mal Anzahl Planes
+ move.w height(a4),d1
+ mulu d1,d0 ; mal Anzahl Linien
+ move.l d0,vs_chunksize(SP) ; merken
+
+ *** PlanePtrs kopieren & X,Y-Offsets dazuaddieren
+
+ move.w yoffset(a4),d1 ; Y-Offset im Bild
+ mulu bm_BytesPerRow(a3),d1 ; mal Bildbreite
+ moveq #0,d0
+ move.w xoffset(a4),d0
+ add.l d0,d1 ; plus X-Offset
+
+ lea bm_Planes(a3),a0 ; Source
+ move.l SP,a1 ; Destination
+ moveq #MAXPLANES-1,d0 ; Alle PlanePtrs
+1$: move.l (a0)+,d2 ; PlanePtr
+ add.l d1,d2 ; Offset dazu
+ move.l d2,(a1)+ ; speichern
+ dbf d0,1$
+
+ moveq #0,d3
+ moveq #0,d4
+ moveq #0,d5
+ move.w bm_BytesPerRow(a3),d5 ; D5 : BytesPerRow (linesize)
+ move.b bm_Depth(a3),d3 ; move.b ea,Ax geht ja nicht
+ move.w d3,a3 ; A3 : Depth (lieber D8 als A3)
+ move.w width(a4),d3 ; D3 : BytesPerRow (to write)
+ move.w height(a4),d4 ; D4 : Rows (to write)
+
+ subq.w #1,d4 ; für dbf
+ subq.w #1,a3 ; für dbf
+vs_loop1: movea.l SP,a2 ; Zeiger auf Planes
+ move.l a3,d6 ; d6 : Depth für dbf
+
+vs_loop2: move.l d7,d1 ; File
+ move.l (a2),d2 ; Adr : Nächste Linie/Plane
+ JSRLIB Write ; (len ist schon in D3)
+ tst.l d0 ; Fehler ?
+ bmi.s vs_error ; ja!
+ add.l d5,(a2)+ ; auf nächste Linie
+ dbf d6,vs_loop2 ; next plane
+ dbf d4,vs_loop1 ; next row
+
+ move.l vs_chunksize(SP),d0 ; Return-Wert: Chunk-Länge
+vs_error: adda.w #vs_linksize,SP ; Datenraum freigeben
+ movem.l (SP)+,d2-d6/a2-a4
+ rts
+
+
+***************************************************************************
+************** C R U N C H S A V E **************************************
+***************************************************************************
+
+cs_planes: equ 0 ; ARRAY[0..MAXPLANES-1] OF PlanePtr
+cs_buffer: equ cs_planes+4*MAXPLANES ; ARRAY[0..511] OF BYTE
+cs_bodysize: equ cs_buffer+512 ; LONG bodysize
+cs_linksize: equ cs_bodysize+4
+
+CrunchSave: movem.l d2-d6/a2-a4,-(SP) ; 8 Register retten
+ lea 8*4+4(SP),a4 ; A4 : Global data Ptr
+ suba.w #cs_linksize,SP ; lokalen Datenraum schaffen
+
+ clr.l cs_bodysize(SP)
+
+ *** PlanePtrs kopieren & X,Y-Offsets dazuaddieren
+
+ move.w yoffset(a4),d1 ; Y-Offset im Bild
+ mulu bm_BytesPerRow(a3),d1 ; mal Bildbreite
+ moveq #0,d0
+ move.w xoffset(a4),d0
+ add.l d0,d1 ; plus X-Offset
+
+ lea bm_Planes(a3),a0 ; Source
+ movea.l SP,a1 ; Destination (unsauber!)
+ moveq #MAXPLANES-1,d0 ; Alle Planeptrs
+1$: move.l (a0)+,d2 ; PlanePtr
+ add.l d1,d2 ; Offset dazu
+ move.l d2,(a1)+ ; speichern
+ dbf d0,1$
+
+ moveq #0,d3
+ moveq #0,d4
+ moveq #0,d5
+ move.w bm_BytesPerRow(a3),d5 ; D5 : BytesPerRow (linesize)
+ move.b bm_Depth(a3),d3 ; move.b ea,Ax geht ja nicht
+ move.l d3,a3 ; A3 : Depth (lieber D8 als A3)
+ move.w width(a4),d3 ; D3 : BytesPerRow (to write)
+ move.w height(a4),d4 ; D4 : Rows (to write)
+
+ subq.w #1,d4 ; für dbf
+ subq.l #1,a3 ; für dbf
+
+cs_loop1: move.l SP,a2 ; PlanePtr
+ move.l a3,d6 ; d6 : Depth für dbf
+
+cs_loop2: move.w d3,d0 ; Len für CrunchRow()
+ move.l (a2),a0 ; Source für CrunchRow()
+ lea cs_buffer(SP),a1 ; Destination für CrunchRow()
+ bsr.s CrunchRow
+ add.l d0,cs_bodysize(SP) ; für calcbodysize()
+
+ move.l d7,d1 ; File
+ lea cs_buffer(SP),a1 ; Daten-Puffer
+ move.l a1,d2 ; Adr : cs_buffer(SP)
+ move.l d3,-(SP)
+ move.l d0,d3 ; Länge, von CrunchRow()
+ JSRLIB Write
+ move.l (SP)+,d3
+ tst.l d0 ; Fehler ?
+ bmi.s cs_error ; ja!
+
+ add.l d5,(a2)+ ; auf nächste Linie
+ dbf d6,cs_loop2 ; next plane
+ dbf d4,cs_loop1 ; next row
+
+ move.l cs_bodysize(SP),d0 ; return-value
+cs_error: adda.w #cs_linksize,SP ; Speicher freigeben
+ movem.l (SP)+,d2-d6/a2-a4
+ rts
+
+
+*********************************************************************
+** **
+** C R U N C H R O W - eine Zeile CmpByteRun1 crunchen **
+** **
+** Parameter : A0.L : Zeiger auf Source-Adresse in Plane **
+** A1.L : Zeiger auf Destination-Buffer **
+** D0.W : Anzahl Bytes einer Source-Linie **
+** Resultat : D0.L : Anzahl gecrunchte Bytes **
+** **
+*********************************************************************
+
+CrunchRow: movem.l d2-d3/a2-a3,-(SP)
+ lea (a0,d0.w),a2 ; A2 : Source-Endadresse der Linie
+ moveq #0,d3 ; Byte-Zähler
+
+crunchloop: bsr.s CountEq ; wieviele gleiche Bytes folgen ?
+ cmp.w #3,d0 ; genug gleiche Bytes zum runnen ?
+ blt.s countdump ; nee, lohnt sich nicht -> Dumpen
+
+ addq.l #2,d3 ; Markierbyte & Anzahl
+ move.b (a0),d1 ; Wert
+ adda.w d0,a0 ; Source anpassen
+ subq.w #1,d0 ; muss .w sein und nicht .b !!!!!!!
+ neg.b d0 ; negieren (= "Run"-Code)
+ move.b d0,(a1)+ ; und eintragen
+ move.b d1,(a1)+ ; Wert eintragen
+ bra.s crunchcont ; weitermachen
+
+countdump: movea.l a0,a3 ; Source-Pointer retten
+ moveq #0,d2 ; D2 : Länge des Dump-Blocks
+1$: addq.b #1,d2
+ bmi.s 2$ ; höchstens 127 Bytes pro Block
+ addq.l #1,a0
+ cmpa.l a2,a0 ; Ende der Linie erreicht ?
+ bge.s 3$ ; ja -> abbrechen
+ bsr.s CountEq
+ cmp.w #3,d0 ; Ende des Dump-Blocks ?
+ blt.s 1$ ; noch nicht
+ bra.s 3$ ; Ende
+2$: moveq #127,d2
+3$: movea.l a3,a0 ; Source-Pointer restaurieren
+
+ add.l d2,d3 ; zur Gesamtanzahl dazuzählen
+ addq.l #1,d3 ; Markierbyte nicht vergessen
+ subq.w #1,d2 ; aus 1..128 mach 0..127
+ move.b d2,(a1)+ ; Markierbyte eintragen
+4$: move.b (a0)+,(a1)+ ; Datenbytes eintragen
+ dbf d2,4$
+
+
+crunchcont: cmpa.l a2,a0 ; Ende der Linie erreicht ?
+ blt.s crunchloop ; noch nicht!
+
+ move.l d3,d0 ; Return: Anzahl Destination-Bytes
+ movem.l (SP)+,d2-d3/a2-a3
+ rts
+
+ *** Anzahl gleicher Zeichen ab (a0) zählen und nach D0
+
+CountEq: move.l a0,-(SP)
+ moveq #1,d0 ; D0 : Anzahl gleiche Bytes
+1$: move.b (a0)+,d1 ; erstes Byte
+2$: cmp.b (a0)+,d1 ; Byte gleich wie letztes Byte ?
+ bne.s 3$ ; nein -> abbrechen
+ cmp.w #128,d0
+ bge.s 3$ ; höchstens 128 gleiche
+ addq.w #1,d0 ; Anzahl erhöhen
+ cmpa.l a2,a0 ; Ende der Linie erreicht ?
+ blt.s 2$ ; noch nicht -> weiterzählen
+3$: move.l (SP)+,a0
+ rts
+
+ END