gbufToLCD.z80 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. GraphToLCD_:
  2. ld hl,(BufPtr)
  3. ld de,(GrayBufPtr)
  4. BufferToLCD_:
  5. ;Input:
  6. ; HL points to the buffer to copy to the LCD
  7. ; DE points to a secondary buffer to use in grayscale
  8. ; (graymask) has the gray mask
  9. ; (graymask+1) is the method
  10. ; expects the LCD to be in X-increment mode
  11. ; (If you don't know what this means, you probably don't have to worry!)
  12. ;Outputs:
  13. ; HL is incremented by 12
  14. ; DE is incremented by 12
  15. ;Destroys:
  16. ; AF,BC,IX
  17. ; This might change in the future, but A and C are the gray mask, B is 0,
  18. ; and IX points to the routine that mixes the pixels from two layers
  19. di
  20. ld a,(graymask+1)
  21. or a
  22. ld ix,gray2
  23. jr z,+_
  24. ld ix,gray3
  25. dec a
  26. jr z,+_
  27. gbuftoLCD_4:
  28. ld ix,gray4
  29. sub 15
  30. jr c,+_
  31. dec a
  32. jp z,mask_buffer_to_LCD
  33. ld ix,LCD_buf_OR
  34. _:
  35. ; Expect that the LCD increment mode is already set to increment down
  36. ;
  37. ; We shouldn't need a delay here!
  38. ; in a,(16) \ rla \ jr c,$-3
  39. ; Set the LCD pointer to the top row
  40. ld a,$80
  41. out (16),a
  42. ;We have to wait for the LCD anyways, so may as well do something useful.
  43. ;Get the gray mask and put it in C
  44. ld a,(graymask)
  45. ld c,a
  46. ;Wait for the LCD to be ready for new data
  47. in a,(16) \ rla \ jr c,$-3
  48. ; Set the LCD pointer to the left-most column of 8 pixels
  49. ld a,$20
  50. col:
  51. ;Set the column
  52. out (10h),a
  53. ;Save the column number
  54. push af
  55. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  56. ld b,64
  57. _:
  58. ;Now wait for the LCD to be ready
  59. in a,(16) \ rla \ jr c,$-3
  60. ;IX points to our mask routine. It rotates the mask and computes the next byte.
  61. call call_ix_01 ;rotate the mask
  62. bit InvertLCDFlag,(iy+userflags)
  63. jr z,$+3
  64. cpl
  65. out (17),a
  66. ;We are drawing in columns, so we need to advance HL by 12
  67. ld a,12
  68. add a,l
  69. ld l,a
  70. jr nc,$+3
  71. inc h
  72. ;And advance DE by 12
  73. ld a,12
  74. add a,e
  75. ld e,a
  76. jr nc,$+3
  77. inc d
  78. djnz -_
  79. ;Rotate the mask an extra time. We want to keep it out of phase.
  80. dec ix
  81. call call_ix_01 ;rotate the mask
  82. inc ix
  83. ;Now point to HL to the start of the next column.
  84. ;If we subtract 768, it is where it started, so we'd need to increment 1 more.
  85. ;Basically, HL-(3*256)+1
  86. dec h
  87. dec h
  88. dec h
  89. inc hl
  90. ;Same with DE
  91. dec d
  92. dec d
  93. dec d
  94. inc de
  95. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  96. ;12 columns, so no more looping. Otherwise, draw the next column.
  97. pop af
  98. inc a
  99. cp $2C
  100. jp nz,col
  101. ;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
  102. ;want to avoid a static image if possible!
  103. call call_ix_01 ;rotate the mask one last time
  104. ld a,c
  105. ld (graymask),a
  106. ret
  107. gray2:
  108. ;This just grabs from the main buffer
  109. ld a,(hl)
  110. ret
  111. nop
  112. gray3:
  113. ;Toggles the mask between %10101010 and %01010101.
  114. rlc c
  115. ; Now we use C to select pixels from either (DE), or (HL).
  116. ; If a bit in C is 0, the corresponding bit in the output is from (HL),
  117. ; else it is from (DE). There is an explaination of this at the end.
  118. ld a,(de)
  119. xor (hl)
  120. and c
  121. xor (hl)
  122. ret
  123. gray4:
  124. ld a,c ;\
  125. cp $C0 ; | Rotate the graymask
  126. rra ; | Can be efficiently done by rotating left while
  127. ld c,a ;/ shifting in the XOR of the top two bits.
  128. ; Now we use C to select pixels from either (DE), or (HL).
  129. ; If a bit in C is 0, the corresponding bit in the output is from (HL),
  130. ; else it is from (DE). There is an explaination of this at the end.
  131. ld a,(de)
  132. xor (hl)
  133. and c
  134. xor (hl)
  135. ret
  136. LCD_buf_OR:
  137. ld a,(de)
  138. or (hl)
  139. ret
  140. mask_buffer_to_LCD:
  141. ;This will AND the secondary buf on to the tilemap_buf, then OR the primary buf
  142. ;on to that.
  143. ld ix,(tilemap_buf)
  144. ; Expect that the LCD increment mode is already set to increment down
  145. ;
  146. ; We shouldn't need a delay here!
  147. ; in a,(16) \ rla \ jr c,$-3
  148. ; Set the LCD pointer to the top row
  149. ld a,$80
  150. out (16),a
  151. ;Wait for the LCD to be ready for new data
  152. in a,(16) \ rla \ jr c,$-3
  153. ; Set the LCD pointer to the left-most column of 8 pixels
  154. ld a,$20
  155. maskcol:
  156. ;Set the column
  157. out (10h),a
  158. ;Save the column number
  159. push af
  160. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  161. ld bc,$400C
  162. _:
  163. push bc
  164. ld a,(de)
  165. and (ix)
  166. xor (hl)
  167. bit InvertLCDFlag,(iy+userflags)
  168. jr z,$+3
  169. cpl
  170. push af
  171. ld b,0
  172. add hl,bc
  173. ex de,hl
  174. add hl,bc
  175. ex de,hl
  176. add ix,bc
  177. ;Now wait for the LCD to be ready
  178. in a,(16) \ rla \ jr c,$-3
  179. pop af
  180. out (17),a
  181. pop bc
  182. djnz -_
  183. ;Now point to HL to the start of the next column.
  184. ;If we subtract 768, it is where it started, so we'd need to increment 1 more.
  185. ;Basically, HL-(3*256)+1
  186. dec h
  187. dec h
  188. dec h
  189. inc hl
  190. ;Same with DE
  191. dec d
  192. dec d
  193. dec d
  194. inc de
  195. ;Same with IX
  196. dec ixh
  197. dec ixh
  198. dec ixh
  199. inc ix
  200. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  201. ;12 columns, so no more looping. Otherwise, draw the next column.
  202. pop af
  203. inc a
  204. cp $2C
  205. jp nz,maskcol
  206. ret
  207. ; How C can select from two different buffers
  208. ;
  209. ;
  210. ;We'll use this magical formula:
  211. ; ((x^y)&m)^y
  212. ;
  213. ;When m is 0:
  214. ; ((x^y)&m)^y
  215. ; = ((x^y)&0)^y
  216. ; = (0)^y
  217. ; = y
  218. ;
  219. ;When m is 1:
  220. ; ((x^y)&m)^y
  221. ; = ((x^y)&1)^y
  222. ; = (x^y)^y
  223. ; = x^(y^y) ;We can do this when all operations are XOR
  224. ; = x
  225. ;
  226. ;So a 0 in the mask will choose the pixel from (HL) (primary buffer),
  227. ;and a 1 will choose a pixel from (DE) (gray/back/secondary buffer).