]> 4ch.mooo.com Git - 16.git/blob - 16/scrasm/SPRITE.INC
9c3f2e48143b9678d089031df369a305f23d030e
[16.git] / 16 / scrasm / SPRITE.INC
1 ; SPRITE routines\r
2 MAX_SPRITE      EQU     100\r
3 \r
4 RECTANGLE STRUCT 2,NONUNIQUE\r
5                 X       WORD    0\r
6                 Y       WORD    0\r
7                 Wid4    BYTE    0\r
8                 Ht      BYTE    0\r
9                 Color   BYTE    0\r
10                 Next    WORD    0\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
20                 address_virt    WORD    0\r
21                 address_buf     WORD    0\r
22                 next_line_virt  WORD    0\r
23                 next_line_buf   WORD    0\r
24 RECTANGLE ENDS\r
25 \r
26 SPRITE  STRUCT 2, NONUNIQUE\r
27         RECTANGLE       <>      ; Contains rectangle info\r
28 SPRITE  ENDS\r
29 \r
30 EVEN\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
36 \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
42 \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
51 \r
52 FIRST_SPRITE    EQU     rect10\r
53 \r
54 EVEN\r
55 AnimateSprites  PROC    near\r
56                 ret\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
60         ; to work!\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
66                 call    CopyRectangles\r
67 \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
73                 call    do_fill_buffer\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
79 AnimateSprites  ENDP\r
80 \r
81 smart_dest      DW      0\r
82 out_di          DW      0\r
83 out_si          DW      0\r
84 \r
85 EVEN\r
86 smart_rects     PROC    near\r
87                 add     di,cs:DrawPage.Address\r
88                 mov     ds,cs:segBuffer\r
89                 mov     es,cs:segVideo\r
90                 mov     dx,3c4h\r
91                 mov     al,02h\r
92                 out     dx,al\r
93                 inc     dx\r
94                 mov     cs:smart_dest,di\r
95 \r
96         ; === Beginning of loop through rectangles! ===\r
97 sp_nextrect:\r
98                 cmp     cs:[bp].RECTANGLE.DrawMe,1\r
99                 jne     sp_next\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
105 \r
106         ; Loop over 4 planes\r
107                 mov     bl,4\r
108 sp_plane_loop:  mov     al,bh\r
109                 out     dx,al\r
110 \r
111                 mov     cs:out_di,di\r
112                 mov     cs:out_si,si\r
113 \r
114         ; Loop over height\r
115                 mov     ch,cs:[bp].RECTANGLE.Ht\r
116 sp_row_loop:\r
117 \r
118         ; Loop over width of rectangle (Wid4 is actually width/4)\r
119                 mov     cl,cs:[bp].RECTANGLE.Wid4\r
120 sp_col_loop:\r
121 \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
126                 je      sp_next_pixel\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
131 \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
135 sp_next_pixel:\r
136                 add     si,4\r
137                 inc     di\r
138 \r
139                 dec     cl\r
140                 jnz     sp_col_loop\r
141 \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
147                 dec     ch\r
148                 jnz     sp_row_loop\r
149 \r
150                 mov     di,cs:out_di\r
151                 mov     si,cs:out_si\r
152                 inc     si\r
153                 rol     bh,1\r
154                 adc     di,0\r
155 \r
156                 dec     bl\r
157                 jnz     sp_plane_loop\r
158 \r
159         ; Follow chain to next rectangle\r
160 sp_next:        mov     bp,cs:[bp].RECTANGLE.Next\r
161                 cmp     bp,0\r
162                 jne     sp_nextrect\r
163         ; All done\r
164 sp_end:         ret\r
165 smart_rects     ENDP\r
166 \r
167 ; BP -> first rectangle.  Follows BP->next, stops when BP = 0\r
168 EVEN\r
169 do_fill_buffer  PROC    near\r
170                 mov     es,cs:segBuffer\r
171 \r
172                 cmp     bp,0\r
173                 je      fill_end\r
174 fill_loop:\r
175 \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
182 \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
187 \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
191 \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
196 \r
197                 mov     ah,cs:[bp].RECTANGLE.Color\r
198                 mov     al,cs:[bp].RECTANGLE.Color\r
199 \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
203                 mov     es:[di+2],ax\r
204                 add     di,4\r
205                 dec     cl\r
206                 jnz     fill_col_loop\r
207                 add     di,dx\r
208                 dec     ch\r
209                 jnz     fill_row_loop\r
210 \r
211                 mov     bp,cs:[bp].RECTANGLE.Next\r
212                 cmp     bp,0\r
213                 jne     fill_loop\r
214 fill_end:       ret\r
215 do_fill_buffer  ENDP\r
216 \r
217 EVEN\r
218 CopyRectangles  PROC    near\r
219                 mov     ax,cs:segVideo\r
220                 mov     ds,ax\r
221                 mov     es,ax\r
222 \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
228                 mov     bx,di\r
229                 sub     bx,si\r
230 \r
231                 mov     dx,GC_INDEX\r
232                 mov     ax,ALL_COPY_BITS\r
233                 out     dx,ax\r
234 \r
235                 mov     dx,SC_INDEX\r
236                 mov     ax,0F02h\r
237                 out     dx,ax\r
238                 mov     si,di   ;store destination\r
239 \r
240         ; === Beginning of loop through rectangles! ===\r
241 cr_nextrect:    cmp     cs:[bp].RECTANGLE.DrawMe,1\r
242                 jne     cr_next\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
247                 add     di,si\r
248 \r
249         ; Loop over height\r
250                 mov     ch,cs:[bp].RECTANGLE.Ht\r
251 cr_row_loop:\r
252 \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
256                 stosb\r
257                 dec     cl\r
258                 jnz     cr_col_loop\r
259                 mov     al,ds:[di + bx]\r
260                 mov     es:[di],al\r
261 \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
264                 add     di,dx\r
265                 dec     ch\r
266                 jnz     cr_row_loop\r
267 \r
268         ; Follow chain to next rectangle\r
269 cr_next:        mov     bp,cs:[bp].RECTANGLE.Next\r
270                 cmp     bp,0\r
271                 jne     cr_nextrect\r
272         ; All done\r
273 cr_end:\r
274                 mov     dx,GC_INDEX\r
275                 mov     ax,ALL_DRAW_BITS\r
276                 out     dx,ax\r
277                 ret\r
278 CopyRectangles  ENDP\r
279 \r
280 \1a