4 RECTANGLE STRUCT 2,NONUNIQUE
\r
11 ; DrawMe is used to not bother with sprites that you know
\r
12 ; are contained totally within another, allowing animated
\r
13 ; eyes, etc to be stored in separate sprites. These will be
\r
14 ; drawn to the local buffer but skipped when copying to the
\r
15 ; screen, so if they are not TOTALLY contained, they will
\r
16 ; just get clipped away.
\r
17 DrawMe BYTE 1 ; default, yes draw me.
\r
18 ; (Storage from this point on ... NEVER provide anything but
\r
19 ; default for these values!)
\r
22 next_line_virt WORD 0
\r
23 next_line_buf WORD 0
\r
26 SPRITE STRUCT 2, NONUNIQUE
\r
27 RECTANGLE <> ; Contains rectangle info
\r
31 rect5 SPRITE <<40 ,60 , 2,8, C_TRANSPARENT, 0 , 0>>
\r
32 rect4 SPRITE <<80 ,30 , 2,8, C_TRANSPARENT, offset rect5, 0>>
\r
33 rect3 SPRITE <<120,60 , 2,8, C_TRANSPARENT, offset rect4, 0>>
\r
34 rect2 SPRITE <<55 ,100, 2,8, C_TRANSPARENT, offset rect3, 0>>
\r
35 rect1 SPRITE <<105,100, 2,8, C_TRANSPARENT, offset rect2, 0>>
\r
37 rect6 SPRITE <<36 ,56 , 4,16, C_BLUE, offset rect1, 1>>
\r
38 rect7 SPRITE <<76 ,26 , 4,16, C_BLUE, offset rect6, 1>>
\r
39 rect8 SPRITE <<116,56 , 4,16, C_BLUE, offset rect7, 1>>
\r
40 rect9 SPRITE <<51 ,96 , 4,16, C_BLUE, offset rect8, 1>>
\r
41 rect10 SPRITE <<101,96 , 4,16, C_BLUE, offset rect9, 1>>
\r
43 ;; Simply adding in these 5 rectangles (~20000 pixels for both
\r
44 ;; drawing and erasing) really slows things down! That's why
\r
45 ;; it's important to optimize the sprite drawing routines!
\r
46 rect11 SPRITE <<35 ,55 ,14,36, C_GREEN, offset rect10, 1>>
\r
47 rect12 SPRITE <<75 ,25 ,14,36, C_GREEN, offset rect11, 1>>
\r
48 rect13 SPRITE <<115,55 ,14,36, C_GREEN, offset rect12, 1>>
\r
49 rect14 SPRITE <<50 ,95 ,14,36, C_GREEN, offset rect13, 1>>
\r
50 rect15 SPRITE <<100,95 ,14,36, C_GREEN, offset rect14, 1>>
\r
52 FIRST_SPRITE EQU rect10
\r
55 AnimateSprites PROC near
\r
57 ; Blank out the draw page, by copying from the blank page
\r
58 ; to the draw page all rectangles which had changed. The
\r
59 ; blank page must always be entirely blank if this is going
\r
61 mov di,cs:DrawPage.UpperLeftAddress
\r
62 add di,cs:DrawPage.ScrollOffset
\r
63 mov si,cs:BlankPage.UpperLeftAddress
\r
64 add si,cs:BlankPage.ScrollOffset
\r
65 mov bp,cs:BlankPage.Rectangles
\r
68 ; Now draw the sprites. Uses a temporary buffer to ensure
\r
69 ; minimal drawing to the screen, but that's not really necessary,
\r
70 ; if memory is at a minimum. It's just faster...
\r
71 mov bp,offset FIRST_SPRITE
\r
72 mov cs:DrawPage.Rectangles,bp
\r
74 mov di,cs:DrawPage.UpperLeftAddress
\r
75 add di,cs:DrawPage.ScrollOffset
\r
76 mov bh,cs:DrawPage.AlignmentMask
\r
77 mov bp,offset FIRST_SPRITE
\r
78 jmp smart_rects ; "call"
\r
86 smart_rects PROC near
\r
87 add di,cs:DrawPage.Address
\r
94 mov cs:smart_dest,di
\r
96 ; === Beginning of loop through rectangles! ===
\r
98 cmp cs:[bp].RECTANGLE.DrawMe,1
\r
100 ; Draw this rectangle from the buffer to screen memory.
\r
101 ; Calculate the output address.
\r
102 mov si,cs:[bp].RECTANGLE.address_buf
\r
103 mov di,cs:[bp].RECTANGLE.address_virt
\r
104 add di,cs:smart_dest
\r
106 ; Loop over 4 planes
\r
108 sp_plane_loop: mov al,bh
\r
115 mov ch,cs:[bp].RECTANGLE.Ht
\r
118 ; Loop over width of rectangle (Wid4 is actually width/4)
\r
119 mov cl,cs:[bp].RECTANGLE.Wid4
\r
122 ; Read a byte from the buffer
\r
123 ; Is it transparent (no-modify)? If so, just jump over the draw
\r
124 mov al,byte ptr ds:[si]
\r
125 cmp al,C_TRANSPARENT
\r
127 ; Otherwise, draw it on the spreen, and mark it transparent
\r
128 ; so that it won't be drawn again.
\r
129 mov byte ptr es:[di],al
\r
130 mov byte ptr ds:[si],C_TRANSPARENT
\r
132 ; Skip to next 4-byte group (next column that can be drawn in
\r
133 ; Mode X) Also increment spreen draw address, but only by 1
\r
134 ; because ModeX is 4 pixels per byte
\r
142 ; End of row. Skip space to get to left edge of next row down
\r
143 ; Skip SI = (SCREEN_WIDTH - #bytesdrawn)
\r
144 ; Only draw up to height of rectangle
\r
145 add si,cs:[bp].RECTANGLE.next_line_buf
\r
146 add di,cs:[bp].RECTANGLE.next_line_virt
\r
159 ; Follow chain to next rectangle
\r
160 sp_next: mov bp,cs:[bp].RECTANGLE.Next
\r
167 ; BP -> first rectangle. Follows BP->next, stops when BP = 0
\r
169 do_fill_buffer PROC near
\r
170 mov es,cs:segBuffer
\r
176 mov bx,cs:[bp].RECTANGLE.Y
\r
177 shl bx,1 ; BX = word index y
\r
178 mov di,cs:MultBufWidth[bx] ; DI = SW * y
\r
179 mov cx,cs:[bp].RECTANGLE.X ; CX = x
\r
180 add di,cx ; DI = (SW * y) + x
\r
181 mov cs:[bp].RECTANGLE.address_buf,di ; (DI used later)
\r
183 mov ax,cs:MultVirtWidth[bx] ; AX = (VW/4) * y
\r
184 shr cx,2 ; CX = (x / 4)
\r
185 add ax,cx ; AX = (VW * y + x)/4
\r
186 mov cs:[bp].RECTANGLE.address_virt,ax
\r
188 mov dx,(VIRTUAL_WIDTH / 4)
\r
189 sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (VW - w) / 4
\r
190 mov cs:[bp].RECTANGLE.next_line_virt,dx
\r
192 mov dx,(SCREEN_WIDTH / 4)
\r
193 sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (SW - w) / 4
\r
194 shl dx,2 ; DX = SW - w
\r
195 mov cs:[bp].RECTANGLE.next_line_buf,dx
\r
197 mov ah,cs:[bp].RECTANGLE.Color
\r
198 mov al,cs:[bp].RECTANGLE.Color
\r
200 mov ch,cs:[bp].RECTANGLE.Ht
\r
201 fill_row_loop: mov cl,cs:[bp].RECTANGLE.Wid4
\r
202 fill_col_loop: mov es:[di],ax
\r
211 mov bp,cs:[bp].RECTANGLE.Next
\r
215 do_fill_buffer ENDP
\r
218 CopyRectangles PROC near
\r
223 ; Calculate the difference between the source and destination
\r
224 ; pages. Since in a movsb loop the two would remain a constant
\r
225 ; distance apart, we can just calculate a displacement and then
\r
226 ; not have to worry about SI; instead use DI and DI+BX, thanks
\r
227 ; to the thoughtful x86 ALU!
\r
232 mov ax,ALL_COPY_BITS
\r
238 mov si,di ;store destination
\r
240 ; === Beginning of loop through rectangles! ===
\r
241 cr_nextrect: cmp cs:[bp].RECTANGLE.DrawMe,1
\r
243 ; Draw this rectangle from the buffer to screen memory.
\r
244 ; Calculate the output address.
\r
245 mov di,cs:[bp].RECTANGLE.address_virt
\r
246 mov dx,cs:[bp].RECTANGLE.next_line_virt
\r
250 mov ch,cs:[bp].RECTANGLE.Ht
\r
253 ; Loop over width of rectangle (Wid4 is actually width/4)
\r
254 mov cl,cs:[bp].RECTANGLE.Wid4
\r
255 cr_col_loop: mov al,ds:[di + bx]
\r
259 mov al,ds:[di + bx]
\r
262 ; End of row. Skip space to get to left edge of next row down
\r
263 ; Only draw up to height of rectangle
\r
268 ; Follow chain to next rectangle
\r
269 cr_next: mov bp,cs:[bp].RECTANGLE.Next
\r
275 mov ax,ALL_DRAW_BITS
\r
278 CopyRectangles ENDP
\r