  NOLIST

*---------------------------------------------------------------------------
*   Program     WriteBitMap
*   Author      Eduard Pech, The New Power Generation
*   Compiler    NCode 1.2
*   Version     $0.99\alpha.00a$ not yet functional [npg]
*   Date        14-Jun-92
*   Version     $0.99\alpha.00b$ fully functional   [npg]
*   Date        15-Jun-92
*   Version     $0.99\alpha.00c$                    [npg]
*   Date        16-Jun-92
*   Version     $0.99\alpha.01a$                    [npg]
*   Date        16-Jun-92
*   Version     $0.99\alpha.01b$                    [npg]
*   Date        22-Jun-92
*   Version     $0.99\beta.00a$                     [npg]
*   Date        15-Jul-92
*   History     $0.99\alpha.00a$
*               Me idiot. Listen (and don't repeat):
*               (1) I used _scratch_ registers as parameters. Of course
*                   they've been modified with the third instruction...
*               (2) I wrote: "WriteByteLen EQU *-WriteByteLen" instead
*                   of "WriteByteLen EQU *-WriteByteTxt". Of course DOS
*                   tried to write out 4 GB onto my 105 MB Quantum...
*               This "errors" have been discovered on 15-Jun-92. They
*               have been removed. (It only took about 20 hours of real
*               time!?!) But then I also discovered a "real" error:
*               (3) In conjuntion with the "EndOfImage" function the
*                   flags have not been set/tested correctly. I will be
*                   working on this right now (can't take very long, I
*                   hope).
*               $0.99\alpha.00b$
*               Eliminated all errors from the last version. Rewrote the
*               "EndOfImage" function. Discovered that in any case the
*               maximum screen size is being used to determine the size
*               of the output. I'll try to fix this by passing the actual
*               width and height of the picture/brush. Well, but I tried.
*               The problem is, I think, that I can't get the "real" size
*               of the image from the module IFF Support.
*               $0.99\alpha.00c$
*               Discovered how IFF Support stores information about the
*               image. So I was able to add a "modulo" functionality:
*               Images not using the whole screen width should be treated
*               correctly. But I have no possibility to check this out.
*               And I suspect IFF Support of not expanding such an image
*               to the full screen width (filling the screen up with 0
*               bytes), so the whole probably won't work (but at least
*               I tried, and it's not my fault). Started commenting the
*               source code. Finished comments at 0:58, 16-Jun-92.
*               $0.99\alpha.01a$
*               This versions now contains _dangerous_ code. I included
*               an error handler that notices any error in writing to
*               the output file, but does stack manipulation which is
*               _very_ specialized for this program. So, don't try to
*               change it unless you _really_ know what you do. The
*               procedure now returns TRUE if no error occured, else
*               FALSE. Beside this, _LVO's were introduced with this
*               version.
*               $0.99\alpha.01b$
*               Inserted the command "eor.b #$FF,d0" in "MirrorByte" to
*               get a reversed bitmap output. This is, because a cleared
*               bit will be displayed white and v.~v. with "xsetroot".
*               $0.99\beta.00a$
*               After several hard weeks of trial and error I finally
*               found the "erroneous" piece of code. Instead of adding
*               only one byte to the bitmap pointer in A2, I always added
*               eight bytes at a time, probably "thinking" in pixels as
*               I coded this part. So now no more borders will be created
*               for pictures that are not a multiple of sixteen pixels
*               wide. Introduced EQUR directives.
*---------------------------------------------------------------------------

  XDEF    WriteBitMap

_LVOFWrite        EQU -330
_LVOOpenLibrary   EQU -552
_LVOCloseLibrary  EQU -414

TRUE  EQU -1
FALSE EQU 0

BitPlane    EQUR  A4  ; register contents must not be changed
File        EQUR  A5  ; register contents must not be changed
ImageWidth  EQUR  D6  ; register contents may change
ImageHeight EQUR  D7  ; register contents may change

HexTabPtr   EQUR  A3
LFCounter   EQUR  D5
PointerToX  EQUR  D6
PointerToY  EQUR  D7

; D0-D4/A0-A1 are scratch registers

WriteBitMap                   ; initialization part of WriteBitMap
  subq.w  #1,ImageWidth       ; normalize Image.width
  lsr.w   #3,ImageWidth
  addq.w  #1,ImageWidth
  lsl.w   #3,ImageWidth
  move.w  ImageWidth,width    ; ((Image.width + 1) DIV 8 + 1) * 8
  move.w  ImageHeight,height  ; Image.height
  and.w   #$000F,ImageWidth
  lsr.b   #3,ImageWidth
  ext.l   ImageWidth
  move.l  ImageWidth,modulo   ; Image.width MOD 16
  bra.s   WBMMain             ; branch into main part

GetFirstByte                  ; get the first byte of bitplane
  moveq   #0,PointerToX       ; PointerToX := 0
  moveq   #0,PointerToY       ; PointerToY := 0
GetNextByte                   ; get the next byte of bitplane
  move.b  (BitPlane)+,d0      ; D0 == byte := (BitPlane)+
  addq.w  #8,PointerToX       ; PointerToX := PointerToX + 8 (pixels)
  cmp.w   width,PointerToX    ; IF PointerToX >= Image.width
  bcs.s   GNBRet
  moveq   #0,PointerToX       ; THEN PointerToX := 0
  addq.w  #1,PointerToY       ;      INC (PointerToY,1)
  add.l   modulo,BitPlane     ;      BitPlane := BitPlane + Image.width MOD 16
GNBRet
  rts                         ; back to future...

MirrorByte                    ; mirrors the byte in D0, changes D0-D2
  moveq   #7,d2               ; loop counter (=> 8 loops)
MBLoop                        ; REPEAT
  lsr.b   #1,d0               ;   shift out right bit
  roxl.b  #1,d1               ;   shift in from right
  dbra    d2,MBLoop           ; UNTIL loop counter == 0
  move.b  d1,d0               ; return mirrored byte in D0
  eor.b   #$FF,d0             ; invert it, too
  rts                         ; back to back...

WBMMain                       ; main part of WriteBitMap
  movem.l d1-d7/a0-a6,-(SP)   ; save used registers _except_ D0
  move.l  (4).w,a6            ; get Exec.Base
  lea     dosname,a1
  moveq   #37,d0
  jsr     _LVOOpenLibrary(a6) ; Exec.OpenLibrary (dos.library,37)
  move.l  d0,a6               ; no errors due to usage in Oberon already
  lea     HexTab,HexTabPtr    ; HexTabPtr := POINTER TO HexTab
  bsr.s   GetFirstByte        ; get the first byte of bitplane
  bsr.s   MirrorByte          ; transform it, mirror the bits
  bsr.s   WriteByte           ; output this new byte
  moveq   #1,LFCounter        ; LFCounter := 1
WBMLoop
  bsr.s   EndOfImage          ; WHILE ~EndOfImage
  bne.s   WBMDone
  bsr.s   WriteComma          ; DO output a comma
  addq.b  #1,LFCounter        ;    increase LF counter
  cmp.b   #12,LFCounter       ;    IF LF counter > 12
  bls.s   WBMMark
  bsr.s   WriteLn             ;    THEN output a LF
  moveq   #1,LFCounter        ;         set LF counter to 1
WBMMark
  bsr.s   GetNextByte         ;    get the next byte of bitplane
  bsr.s   MirrorByte          ;    mirror its bits
  bsr.s   WriteByte           ;    output the byte
  bra.s   WBMLoop             ; END (* WHILE *)
WBMDone
  move.l  #TRUE,-(SP)         ; everything was alright here (will go to D0)
WBMRet
  move.l  a6,a1
  move.l  (4).w,a6            ; get Exec.Base
  jsr     _LVOCloseLibrary(a6) ; Exec.CloseLibrary (dos.library)
  movem.l (SP)+,d0-d7/a0-a6   ; restore used registers _and_ RETURN result
  rts                         ; back up...

EndOfImage                    ; checks for end of image
  cmp.w   height,PointerToY   ; IF PointerToY >= Image.height
  bcs.s   EOIFalse
EOITrue
  moveq   #TRUE,d0            ; THEN RETURN TRUE
  bra.s   EOIRet
EOIFalse
  moveq   #FALSE,d0           ; ELSE RETURN FALSE
EOIRet
  rts                         ; back to life...

DoOutput                      ; output handler
  move.l  File,d1             ; Dos.FileHandlePtr
  moveq   #1,d4               ; number of blocks
  jsr     _LVOFWrite(a6)      ; Dos.FWrite
  cmp.l   #1,d0               ; IF blocks_written # blocks_sent == 1
  beq.s   DORet
  move.l  #FALSE,(SP)         ; THEN overwrite return address with FALSE
  bra.s   WBMRet              ;      terminate WriteBitMap procedure
DORet
  rts                         ; back to reality...

WriteLn                       ; output a LF
  move.l  #WriteLnTxt,d2      ; POINTER TO Block
  move.l  #WriteLnLen,d3      ; SYSTEM.SIZE (Block)
  bra.s   DoOutput            ; branch into output handler

WriteComma                    ; output a comma
  move.l  #WriteCommaTxt,d2   ; POINTER TO Block
  move.l  #WriteCommaLen,d3   ; SYSTEM.SIZE (Block)
  bra.s   DoOutput            ; branch into output handler

WriteByte                     ; output a byte
  ror.l   #4,d0               ; save last 4 bits
  and.w   #$000f,d0           ; transform first nibble to hexadecimal
  move.b  0(HexTabPtr,d0.w),WriteByteTxt+3 ; cipher and store it
  rol.l   #4,d0               ; get back the lower nibble
  and.w   #$000f,d0           ; do the same transformation and
  move.b  0(HexTabPtr,d0.w),WriteByteTxt+4 ; store it, too
  move.l  #WriteByteTxt,d2    ; POINTER TO Block
  move.l  #WriteByteLen,d3    ; SYSTEM.SIZE (Block)
  bra.s   DoOutput            ; branch into output handler

  SECTION Daten,DATA          ; data section
dosname                       ; name of dos.library
  DC.B  "dos.library",0
WriteLnTxt                    ; text for LF's
  DC.B  10,"  "
WriteLnLen    EQU *-WriteLnTxt
WriteCommaTxt                 ; text for commas to be written
  DC.B  ","
WriteCommaLen EQU *-WriteCommaTxt
WriteByteTxt                  ; text for hexadecimal byte output
  DC.B  " 0x00"
WriteByteLen  EQU *-WriteByteTxt
HexTab                        ; table of hexadecimal ciphers
  DC.B  "0123456789abcdef"

  SECTION Puffer,BSS          ; buffer section
width                         ; Image.width
  DS.W  1
height                        ; Image.height
  DS.W  1
modulo                        ; Image.width MOD 16
  DS.L  1

  END

