From 36c824864c02f0a3f62c8a1d365d1670835c8c96 Mon Sep 17 00:00:00 2001 From: "Christian A. Weber" Date: Tue, 12 May 1992 22:26:12 +0000 Subject: Initial revision --- Source/SaveClip.S | 490 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 Source/SaveClip.S (limited to 'Source/SaveClip.S') 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 -- cgit v1.2.3