;                                    \|/
;                                    O O
;--------------------------------oOO--U--OOo--------------------------------
;|                                                                         |
;|                               Shade Dots.                               |
;|                      By Alain BROBECKER. (as Baah)                      |
;|                                                        25 december 1995 |
;---------------------------------------------------------------------------
;  This source is an example of my latest dot shading and unshading routine.
;The demo consist in many "shadedots" and "unshadedots" moving randomly
;on the screen, thus giving a quite nice pattern.
;  The main features of the shading routines are their speed and also the
;"bounding", ie they leave all pixels with color between max_value+1 and 15
;unaltered. (This allows to have foreground images without redrawing them
;all the time) The rest of the code is optimised for size, not for speed.
;The resulting executable is 788 bytes longs, which is quite ok.
;  This was written on a 1Meg A3000, with 800kb floppy. The assembler used
;is ExtASM 0.50b. If you want to assemble with another prog, or a newer
;version of ExtASM, you' ll have to make changes. Good luck.

;  If you liked this little demo, or the sourcecode, please send me a nice
;postcard. (Cheap and very valuable to me when I receive it) Also, in case
;you use my code in one of your demo, please send it to me. You can get in
;touch with me for any reasons...
;
;          Alain BROBECKER         Dracula / Positivity (STe)
;          rte de Dardagny         Baah / Arm's Tech (Archie)
;           01630 CHALLEX                           Baah (PC)
;              FRANCE

;2000jan29 -- even better random generator. 764 bytes.
;1997jul22 -- added swi "OS_Exit" instead of "ldr pc,[old_pc]". 772 bytes.
;1996may14 -- random number generator has been improved, it' s now faster,
;          smaller and it uses only one register. Code is now 776 bytes.

#name       ShadeDots

;------>  Constants  <-------------------------------------------------------
#set        nb_points = 64          ;Nb of points to process each frame.
#set        nb_iter = 16            ;Nb of iterations per point.
#set        max_value = 13          ;Maximum value for shading effect.

;------>  BSS Labels Offsets  <----------------------------------------------
#set        points_coords = 0


;****************************************************************************
;****************************************************************************
;*****                                                                  *****
;*****                              MACROS                              *****
;*****                                                                  *****
;****************************************************************************
;****************************************************************************

;------>  Shade_Mode9  <-----------------------------------------------------
;At first, we calculate the adress of the longword which contains the pixel
;and also the shift we must use to place the pixel in the upper quartet of
;a register. Once the long is loaded, we compare max_value<<28 and the
;register with the applied shift. (Note that the other quartets in the
;register are not always null, and we must take this in account) If pixel
;value is lower than the max, then we shade it in the original long and
;save the modified long back in video memory.
;          m0=videoram adress.
;          m1=%111<<2
;          m2=1<<28
;          m3=max_value<<28
;          m4=x
;          m5=y
;          m6-m8 are temporary registers. (We can choose m6=m4 and m7=m5)
macro shade_mode9 m0:r,m1:r,m2:r,m3:r,m4:r,m5:r,m6:r,m7:r,m8:r
{ add       m7,m5,m5,lsl #2         ;Make m7 points on good line.
  add       m7,m0,m7,lsl #5
  mov       m8,m4,lsr #3            ;m8=int(x/8).
  bic       m6,m1,m4,lsl #2         ;m6=4*(not(x) mod8)=shift.
  ldr       m8,[m7,m8,lsl #2]!      ;m7=long adress | m8=long.
  cmp       m3,m8,lsl m6            ;Flags=max_value<<28-pixie<<28.
  addHI     m8,m8,m2,lsr m6         ;Shade if max_value higher than pixie,
  strHI     m8,[m7]                 ;  and save the long back.
}

;------>  UnShade_Mode9  <---------------------------------------------------
;The basic idea is the same as for the shading, except that we don' t want
;to change color of pixel if it' s 0 or higher than max_value. In order to
;have both conditions tested at same time, I substract 1 to the pixel value
;with wrapping. (mod16) Then if (pixel-1 mod16) is lower than max_value,
;we unshade it and save the long back.
;          m0=videoram adress.
;          m1=%111<<2
;          m2=1<<28
;          m3=x
;          m4=y
;          m5-m8 are temporary registers. (We can choose m5=m3 and m6=m4)
macro unshade_mode9 m0:r,m1:r,m2:r,m3:r,m4:r,m5:r,m6:r,m7:r,m8:r
{ add       m6,m4,m4,lsl #2         ;Make m6 points on good line.
  add       m6,m0,m6,lsl #5
  mov       m7,m3,lsr #3            ;m7=int(x/8).
  bic       m5,m1,m3,lsl #2         ;m5=4*(not(x) mod8)=shift.
  ldr       m7,[m6,m7,lsl #2]!      ;m6=long adress | m7=long.
  rsb       m8,m2,m7,lsl m5         ;m8=(pixie-1 mod16)<<28.
  cmp       m8,#max_value<<28       ;Flags=m8-max_value<<28.
  subCC     m7,m7,m2,lsr m5         ;Shade if m8 lower than max_value<<28,
  strCC     m7,[m6]                 ;  and save the long back.
}


;------>  Random32  <--------------------------------------------------------
;This macro takes one random number, and by using subtile (hum) operations
;changes it in a new one.
macro random32 m0:r
{ rsbS m0,m0,m0,ror#11
}

;Second version was using only one register.
;macro random32 m0:r
;{ eorS      m0,m0,m0,rrx
; adc       m0,m0,m0,ror #7
;}

;Previous random generator was the following one. I give it as a reminder.
;macro random32 m0:r,m1:r
;{ add       m0,m1,m0,ror #3
; mov       m0,m0,ror m1
; eor       m1,m0,m1,ror #7
;}



;****************************************************************************
;****************************************************************************
;*****                                                                  *****
;*****                               CODE                               *****
;*****                                                                  *****
;****************************************************************************
;****************************************************************************

;------>  Start Of Proggy  <-------------------------------------------------
.proggy_start
  swi       256+22                  ;Set screen mode.
  swi       256+9
  swi       OS_RemoveCursors        ;They are so ugly!
  adr       r0,videoram_adress      ;Get videoram adress.
  mov       r1,r0
  swi       OS_ReadVduVariables
  adr       r0,colors               ;Change colors.
  mov       r1,#16*6
  swi       OS_WriteN

  adr       r0,bss+points_coords    ;Set all points to the same position.
  mov       r1,#256                 ;Initial position.
  mov       r2,#200
  mov       r3,#2*nb_points         ;Copy it 2*nb_points times.
._init_one_point
  stmia     r0!,{r1-r2}             ;Initialise one point.
  subS      r3,r3,#1
  bNE       _init_one_point

  ldr       r0,videoram_adress      ;Copy the 'baah.' logo.
  add       r0,r0,#7+(11*160)       ;Recenter the first logo.
  mov       r1,#8                   ;Copy 8 rows of logos.
._logos_one_row
  mov       r2,#5                   ;Copy 5 columns of logos.
._logos_one_column
  mov       r3,r0                   ;r3=destination adress.
  adr       r4,logo                 ;r4=source adress.
  mov       r5,#9                   ;9 lines.
._logo_one_line
  mov       r6,#18                  ;18 bytes per line.
._logo_one_byte
  ldrB      r7,[r4],#1              ;Copy one byte.
  strB      r7,[r3],#1
  subS      r6,r6,#1
  bNE       _logo_one_byte
  add       r3,r3,#160-18           ;Next logo line.
  subS      r5,r5,#1
  bNE       _logo_one_line
  add       r0,r0,#32               ;Next logo. (Column)
  subS      r2,r2,#1
  bNE       _logos_one_column
  add       r0,r0,#160*31           ;Next logo. (Row)
  subS      r1,r1,#1
  bNE       _logos_one_row


;------>  Random Walk  <-----------------------------------------------------
;We process nb_points points, and for each of them, we perform nb_iter
;random movements. At each of thoses, we shade the according pixel.
;Then we do the same for unshading.
.random_walk
  ldr       r0,videoram_adress      ;r0=videoram adress.
  adr       r1,directions           ;r1=table of directions.
  ldr       r2,[r1,#-4]             ;Load random germ.
  adr       r3,bss+points_coords
  mov       r4,#nb_points           ;Nb of points to shade.
  mov       r5,#&7<<2               ;Used to calculate pixel shift.
  mov       r6,#1<<28               ;Used to decrement pixel in lword.
  mov       r7,#max_value<<28       ;Used in pixel shading.
.shade_one_point
  ldmia     r3,{r8-r9}              ;r8=x_pos | r9=y_pos.
  mov       r14,#nb_iter
.shade_one_iter
  shade_mode9 r0,r5,r6,r7,r8,r9,r10,r11,r12 ;Shade the pixel.
  and       r10,r2,#%111            ;r10=random_nb mod8.
  add       r10,r1,r10,lsl #3       ;r10 points on good direction.
  ldmia     r10,{r10-r11}           ;r10=incx | r11=incy.
  addS      r8,r8,r10               ;pos_x+=incx.
  addMI     r8,r8,#1                ;Clipping.
  cmp       r8,#320
  subPL     r8,r8,#1
  addS      r9,r9,r11               ;pos_y+=incy.
  addMI     r9,r9,#1                ;Clipping.
  cmp       r9,#256
  subPL     r9,r9,#1
  random32  r2                      ;Next random number.
  subS      r14,r14,#1              ;One iteration processed.
  bNE       shade_one_iter
  stmia     r3!,{r8-r9}             ;Save new coords.
  subS      r4,r4,#1                ;One point processed.
  bNE       shade_one_point

  mov       r4,#nb_points           ;Nb of points to unshade.
.unshade_one_point
  ldmia     r3,{r7-r8}              ;r7=x_pos | r8=y_pos.
  mov       r14,#nb_iter
.unshade_one_iter
  unshade_mode9 r0,r5,r6,r7,r8,r9,r10,r11,r12 ;UnShade the pixel.
  and       r9,r2,#%111             ;r9=random_nb mod8.
  add       r9,r1,r9,lsl #3         ;r9 points on good direction.
  ldmia     r9,{r9-r10}             ;r9=incx | r10=incy.
  addS      r7,r7,r9                ;pos_x+=incx.
  addMI     r7,r7,#1                ;Clipping.
  cmp       r7,#320
  subPL     r7,r7,#1
  addS      r8,r8,r10               ;pos_y+=incy.
  addMI     r8,r8,#1                ;Clipping.
  cmp       r8,#256
  subPL     r8,r8,#1
  random32  r2                      ;Next random number.
  subS      r14,r14,#1              ;One iteration processed.
  bNE       unshade_one_iter
  stmia     r3!,{r7-r8}             ;Save new coords.
  subS      r4,r4,#1                ;One point processed.
  bNE       unshade_one_point

  str       r2,[r1,#-4]             ;Save the random germ for next time.

  swi       OS_ReadEscapeState      ;Escape key pressed?
  bCC       random_walk             ;No, then loop.
  swi       OS_Exit


;****************************************************************************
;****************************************************************************
;*****                                                                  *****
;*****                            MAIN DATAS                            *****
;*****                                                                  *****
;****************************************************************************
;****************************************************************************

.videoram_adress dcd 148,-1         ;Will contain videoram adress.

.colors
  dcb       19,&0,16,&00,&00,&00, 19,&1,16,&22,&00,&00
  dcb       19,&2,16,&44,&00,&00, 19,&3,16,&66,&00,&00
  dcb       19,&4,16,&88,&00,&00, 19,&5,16,&aa,&22,&00
  dcb       19,&6,16,&bb,&44,&00, 19,&7,16,&cc,&66,&00
  dcb       19,&8,16,&dd,&88,&00, 19,&9,16,&ee,&aa,&00
  dcb       19,&a,16,&ff,&bb,&22, 19,&b,16,&ff,&cc,&44
  dcb       19,&c,16,&ff,&dd,&66, 19,&d,16,&ff,&ee,&88
  dcb       19,&e,16,&66,&66,&dd, 19,&f,16,&00,&00,&00

;The random germ must be just before the directions.
;The 8 directions are the increments for the 8 surrounding pixels.
.random_germ dcd &eb1a2c37
.directions  dcd -1,-1,0,-1,1,-1,1,0,1,1,0,1,-1,1,-1,0

.logo                   ;Hard to trust, but here' s the logo.
  dcb       &F0,&0F,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&F0,&0F,&00,&00
  dcb       &00,&00,&EF,&FE,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&EF,&FE
  dcb       &00,&00,&00,&00,&EF,&FE,&FF,&0F,&00,&FF,&FF,&FF,&00,&FF,&FF,&FF
  dcb       &EF,&FE,&FF,&0F,&00,&00,&EF,&FE,&EE,&FE,&F0,&EE,&EE,&EE,&FF,&EE
  dcb       &EE,&EE,&EF,&FE,&EE,&FE,&00,&00,&EF,&EE,&FF,&EE,&EF,&FE,&FF,&EE
  dcb       &EF,&FE,&FF,&EE,&EF,&EE,&FF,&EE,&0F,&00,&EF,&FE,&F0,&EE,&EF,&FE
  dcb       &F0,&EE,&EF,&FE,&F0,&EE,&EF,&FE,&F0,&EE,&FF,&0F,&EF,&FE,&FF,&EE
  dcb       &EF,&FE,&EF,&EE,&EF,&FE,&EF,&EE,&EF,&FE,&EF,&FE,&EF,&FE,&F0,&EE
  dcb       &EE,&FE,&F0,&EE,&FE,&EE,&FF,&EE,&FE,&EE,&EF,&FE,&EF,&EE,&EF,&FE
  dcb       &00,&FF,&FF,&0F,&00,&FF,&0F,&FF,&00,&FF,&0F,&FF,&F0,&0F,&F0,&FF
  dcb       &F0,&0F
ALIGN

;----------------------->  THIS MUST BE AT VERY END  <-----------------------
.bss
