]> 4ch.mooo.com Git - 16.git/blob - 16/xlib/xclippbm.asm
code miraculously works on real hardware
[16.git] / 16 / xlib / xclippbm.asm
1 ;-----------------------------------------------------------------------\r
2 ; MODULE XCLIPPBM\r
3 ;\r
4 ; This module was written by Matthew MacKenzie\r
5 ; matm@eng.umd.edu\r
6 ;\r
7 ; Clipped transfer of planar bitmaps from system memory to video memory.\r
8 ;\r
9 ; Compile with TASM.\r
10 ; C near-callable.\r
11 ;\r
12 ; ****** XLIB - Mode X graphics library                ****************\r
13 ; ******                                               ****************\r
14 ; ****** Written By Themie Gouthas                     ****************\r
15 ;\r
16 ; egg@dstos3.dsto.gov.au\r
17 ; teg@bart.dsto.gov.au\r
18 ;-----------------------------------------------------------------------\r
19 \r
20 include xlib.inc\r
21 include xclippbm.inc\r
22 \r
23 \r
24         .data\r
25 \r
26         align 2\r
27 \r
28 ; global clipping variables\r
29 _TopBound       dw      (?)\r
30 _BottomBound    dw      (?)\r
31 _LeftBound      dw      (?)\r
32 _RightBound     dw      (?)\r
33 \r
34 ; VGA plane masks\r
35 ColumnMask      db      011h,022h,044h,088h\r
36 \r
37 ; bit delay timers\r
38 LeftDelay       db      0, 1, 2, 4\r
39 RightDelay      db      0, 4, 2, 1\r
40 \r
41 \r
42 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
43 ; _x_clip_pbm\r
44 ;\r
45 ; C near-callable as:\r
46 ;\r
47 ; void x_clip_pbm (int X, int Y, int ScreenOffs, char far * Bitmap);\r
48 ;\r
49 ; Bitmap is a planar bitmap, in the regular Xlib format.\r
50 ;\r
51 ; ax, bx, cx, and dx go south.\r
52 \r
53         .code\r
54 \r
55         public _x_clip_pbm\r
56         align   2\r
57 _x_clip_pbm proc\r
58 ARG     X:word, Y:word, ScreenOffs:word, Bitmap:dword\r
59 LOCAL   left_counter, right_counter,column,clipped_height,clipped_width,screen_pos,bitmap_pos,bitmap_size,VGA_mask,width_copy,height_temp,screen_width:word=LocalStk\r
60 ; Tasm 1.0 does not allow the \ line continuation\r
61 ;LOCAL   left_counter:word, right_counter:word, \\r
62 ;               column:word, clipped_height:word, clipped_width:word, \\r
63 ;               screen_pos:word, bitmap_pos:word, bitmap_size:word, \\r
64 ;               VGA_mask:word, width_copy, height_temp:word, \\r
65 ;               screen_width:word=LocalStk\r
66 \r
67         push bp\r
68         mov bp, sp\r
69         sub sp, LocalStk\r
70         push si\r
71         push di\r
72         push ds\r
73 \r
74 ; sociopathic cases: are the clipping bounds out of order?\r
75         mov ax, _TopBound\r
76         cmp ax, _BottomBound\r
77         jg @@GetOut\r
78         mov ax, _LeftBound\r
79         cmp ax, _RightBound\r
80         jle @@ReasonableAndProper\r
81 @@GetOut:                               ; return a 1 -- no image drawn\r
82         pop ds\r
83         pop di\r
84         pop si\r
85         mov ax, 1\r
86         mov sp, bp\r
87         pop bp\r
88         ret\r
89 \r
90 @@ReasonableAndProper:\r
91 \r
92 ; we need to use both the tables in ds and the height and width of the bitmap\r
93         les si, Bitmap\r
94 \r
95 ; vertical position\r
96         xor cx, cx\r
97         mov cl, byte ptr es:[si + 1] ; height of bitmap\r
98         xor ax, ax\r
99         mov al, byte ptr es:[si] ; width of bitmap\r
100         mul cx\r
101         mov bitmap_size, ax\r
102         mov ax, Y\r
103         cmp ax, _BottomBound ; top edge below clipping box?\r
104         jg @@GetOut\r
105 \r
106         mov bx, cx\r
107         add bx, ax\r
108         dec bx              ; bottom edge = Y + height - 1\r
109         cmp bx, _TopBound\r
110         jl @@GetOut\r
111         sub bx, _BottomBound ; bottom margin = bottom edge - BottomBound\r
112         jle @@NoBottomBound\r
113         sub cx, bx          ; clip bottom margin from height\r
114 @@NoBottomBound:\r
115         mov bx, _TopBound\r
116         sub bx, ax          ; top margin = TopBound - Y\r
117         jle @@NoTopBound\r
118         add ax, bx          ; top edge = Y + top margin\r
119         sub cx, bx          ; clip top margin from height\r
120         jmp @@KeepMargin\r
121 @@NoTopBound:\r
122         xor bx, bx\r
123 @@KeepMargin:\r
124         mov clipped_height, cx\r
125 \r
126         mul _ScrnLogicalByteWidth\r
127         mov di, ax\r
128         add di, ScreenOffs  ; row of upper-left corner of blit\r
129 \r
130         mov cl, byte ptr es:[si] ; width of bitmap (ch is still 0 from height)\r
131         mov ax, cx\r
132         mul bx\r
133         add si, ax\r
134         add si, 2           ; starting position in bitmap\r
135 \r
136 ; horizontal position\r
137         mov width_copy, cx\r
138         mov dx, X\r
139         cmp dx, _RightBound\r
140         jg @@GetOut\r
141         mov dx, 0           ; unclipped value for right delay\r
142 \r
143         mov ax, cx\r
144         shl ax, 2           ; width in pixels\r
145         add ax, X\r
146         dec ax              ; right edge = X + width in pixels - 1\r
147         cmp ax, _LeftBound\r
148         jl @@GetOut\r
149         sub ax, _RightBound  ; right margin = right edge - RightBound\r
150         jle @@NoRightBound\r
151         mov bx, ax\r
152         and bx, 3\r
153         mov dl, RightDelay[bx]\r
154         shr ax, 2\r
155         sub cx, ax          ; subtract clipped bytes from width\r
156 @@NoRightBound:\r
157         mov right_counter, dx\r
158         mov dx, 0           ; unclipped value for left delay\r
159         mov ax, _LeftBound\r
160         sub ax, X           ; left margin = LeftBound - X\r
161         jle @@NoLeftBound\r
162         mov bx, ax\r
163         and bx, 3\r
164         mov dl, LeftDelay[bx]\r
165         add ax, 3\r
166         shr ax, 2           ; left margin/4, rounded up\r
167         sub cx, ax          ; subtract clipped bytes from width\r
168         add si, ax          ; move starting position in bitmap past margin\r
169         add di, ax          ; move starting position on screen past margin\r
170 @@NoLeftBound:\r
171         mov left_counter, dx\r
172         mov clipped_width, cx\r
173 \r
174         mov ax, X           ; add x coordinate to screen position\r
175         mov bx, ax\r
176         sar ax, 2\r
177         add di, ax\r
178 \r
179         mov dx, SC_INDEX\r
180         mov al, MAP_MASK\r
181         out dx, al\r
182         inc dx\r
183 \r
184         and bx, 3           ; initial mask\r
185         xor ax, ax\r
186         mov al, ColumnMask[bx]\r
187         mov VGA_mask, ax\r
188         out dx, al          ; initial mask\r
189 \r
190         mov column, 4\r
191         mov bitmap_pos, si\r
192         mov screen_pos, di\r
193         mov ax, _ScrnLogicalByteWidth\r
194         mov screen_width, ax ; since we move ds\r
195 \r
196 ; we've used all our tables, so we can change ds to point to the bitmap,\r
197 ; and es to point to the screen\r
198         mov ds, word ptr [Bitmap + 2]\r
199         mov ax, SCREEN_SEG\r
200         mov es, ax\r
201 \r
202         cld                 ; strings go forward\r
203         mov bx, width_copy\r
204         sub bx, clipped_width ; bytes to advance one line in bitmap\r
205 \r
206 ; let's actually draw something for a change\r
207 @@WritePlane:\r
208         mov ax, clipped_height\r
209         mov height_temp, ax\r
210         mov dx, screen_width\r
211         sub dx, clipped_width ; bytes to advance one line across screen\r
212 \r
213 @@WriteLine:\r
214         mov cx, clipped_width\r
215         shr cx, 1\r
216         rep movsw           ; in they went, two by two...\r
217         adc cx, 0\r
218         rep movsb           ; catch stray last byte, if it's there\r
219         add si, bx          ; advance one bitmap line\r
220         add di, dx          ; advance one screen line\r
221 \r
222         dec height_temp\r
223         jnz @@WriteLine\r
224 \r
225         dec column\r
226         jz @@OuttaHere      ; only four columns per customer, please\r
227         mov dx, SC_INDEX + 1\r
228         rol byte ptr VGA_mask, 1\r
229         adc screen_pos, 0   ; add to location if we've wrapped to plane 0\r
230         mov al, byte ptr VGA_mask\r
231         out dx, al          ; set VGA for next column\r
232 \r
233         shr right_counter, 1\r
234         jnc @@NoRightCounter\r
235         dec clipped_width   ; cut off right edge for later planes\r
236         inc bx\r
237 @@NoRightCounter:\r
238         shr left_counter, 1\r
239         jnc @@NoLeftCounter\r
240         inc clipped_width   ; add to left edge for later planes\r
241         dec bx\r
242         dec bitmap_pos\r
243         dec screen_pos\r
244 @@NoLeftCounter:\r
245         mov si, bitmap_pos\r
246         add si, bitmap_size\r
247         mov bitmap_pos, si\r
248         mov di, screen_pos\r
249         jmp @@WritePlane\r
250 \r
251 @@OuttaHere:                    ; return a 0 -- something was inside the boundary\r
252         pop ds\r
253         pop di\r
254         pop si\r
255         mov ax, 0\r
256         mov sp, bp\r
257         pop bp\r
258         ret\r
259 _x_clip_pbm endp\r
260 \r
261 \r
262 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
263 ; _x_clip_masked_pbm\r
264 ;\r
265 ; C near-callable as:\r
266 ;\r
267 ; void x_clip_masked_pbm (int X, int Y, int ScreenOffs, char far * Bitmap);\r
268 ;\r
269 ; Bitmap is a planar bitmap, in the regular Xlib format.\r
270 ; The width of the bitmap cannot be greater than 90 bytes, however.\r
271 ; Ain't that just criminal?\r
272 ;\r
273 ; ax, bx, cx, and dx go south.\r
274 \r
275 \r
276 ; one branch per pixel is more than enough -- we'll unroll the line-writing\r
277 ; loop all the way to try to get a little speed (at the expense, as usual,\r
278 ; of a chunk of memory)\r
279 \r
280 MaskedPoint macro offset\r
281         mov al, [si + offset]\r
282         or al, al\r
283         jz $+6\r
284         mov es:[di + offset], al\r
285         endm\r
286 \r
287 MaskedPointSize     equ     11\r
288 \r
289         public _x_clip_masked_pbm\r
290         align   2\r
291 _x_clip_masked_pbm proc\r
292 ARG     X:word, Y:word, ScreenOffs:word, Bitmap:dword\r
293 ; Tasm 1.0 does not allow the \ line continuation\r
294 LOCAL   left_counter,right_counter,column:word,clipped_height,screen_pos,bitmap_pos,bitmap_size,VGA_mask,width_copy,height_temp,screen_width:word=LocalStk\r
295 ;LOCAL   left_counter:word, right_counter:word, \\r
296 ;               column:word, clipped_height:word, \\r
297 ;               screen_pos:word, bitmap_pos:word, bitmap_size:word, \\r
298 ;               VGA_mask:word, width_copy, height_temp:word, \\r
299 ;               screen_width:word=LocalStk\r
300         push bp\r
301         mov bp, sp\r
302         sub sp, LocalStk\r
303         push si\r
304         push di\r
305         push ds\r
306 \r
307 ; sociopathic cases: are the clipping bounds out of order?\r
308         mov ax, _TopBound\r
309         cmp ax, _BottomBound\r
310         jg @@GetOut\r
311         mov ax, _LeftBound\r
312         cmp ax, _RightBound\r
313         jle @@ReasonableAndProper\r
314 @@GetOut:                               ; return a 1 -- no image drawn\r
315         pop ds\r
316         pop di\r
317         pop si\r
318         mov ax, 1\r
319         mov sp, bp\r
320         pop bp\r
321         ret\r
322 \r
323 @@ReasonableAndProper:\r
324 \r
325 ; we need to use both the tables in ds and the height and width of the bitmap\r
326         les si, Bitmap\r
327 \r
328 ; vertical position\r
329         xor cx, cx\r
330         mov cl, byte ptr es:[si + 1] ; height of bitmap\r
331         xor ax, ax\r
332         mov al, byte ptr es:[si] ; width of bitmap\r
333         mul cx\r
334         mov bitmap_size, ax\r
335         mov ax, Y\r
336         cmp ax, _BottomBound ; top edge below clipping box?\r
337         jg @@GetOut\r
338 \r
339         mov bx, cx\r
340         add bx, ax\r
341         dec bx              ; bottom edge = Y + height - 1\r
342         cmp bx, _TopBound\r
343         jl @@GetOut\r
344         sub bx, _BottomBound ; bottom margin = bottom edge - BottomBound\r
345         jle @@NoBottomBound\r
346         sub cx, bx          ; clip bottom margin from height\r
347 @@NoBottomBound:\r
348         mov bx, _TopBound\r
349         sub bx, ax          ; top margin = TopBound - Y\r
350         jle @@NoTopBound\r
351         add ax, bx          ; top edge = Y + top margin\r
352         sub cx, bx          ; clip top margin from height\r
353         jmp @@KeepMargin\r
354 @@NoTopBound:\r
355         xor bx, bx\r
356 @@KeepMargin:\r
357         mov clipped_height, cx\r
358 \r
359         mul _ScrnLogicalByteWidth\r
360         mov di, ax\r
361         add di, ScreenOffs  ; row of upper-left corner of blit\r
362 \r
363         mov cl, byte ptr es:[si] ; width of bitmap (ch is still 0 from height)\r
364         mov ax, cx\r
365         mul bx\r
366         add si, ax\r
367         add si, 2           ; starting position in bitmap\r
368 \r
369 ; horizontal position\r
370         mov width_copy, cx\r
371         mov dx, X\r
372         cmp dx, _RightBound\r
373         jg @@GetOut\r
374         mov dx, 0           ; unclipped value for right delay\r
375 \r
376         mov ax, cx\r
377         shl ax, 2           ; width in pixels\r
378         add ax, X\r
379         dec ax              ; right edge = X + width in pixels - 1\r
380         cmp ax, _LeftBound\r
381         jl @@GetOut\r
382         sub ax, _RightBound ; right margin = right edge - RightBound\r
383         jle @@NoRightBound\r
384         mov bx, ax\r
385         and bx, 3\r
386         mov dl, RightDelay[bx]\r
387         shr ax, 2\r
388         sub cx, ax          ; subtract clipped bytes from width\r
389 @@NoRightBound:\r
390         mov right_counter, dx\r
391         mov dx, 0           ; unclipped value for left delay\r
392         mov ax, _LeftBound\r
393         sub ax, X           ; left margin = LeftBound - X\r
394         jle @@NoLeftBound\r
395         mov bx, ax\r
396         and bx, 3\r
397         mov dl, LeftDelay[bx]\r
398         add ax, 3\r
399         shr ax, 2           ; left margin/4, rounded up\r
400         sub cx, ax          ; subtract clipped bytes from width\r
401         add si, ax          ; move starting position in bitmap past margin\r
402         add di, ax          ; move starting position on screen past margin\r
403 @@NoLeftBound:\r
404         mov left_counter, dx\r
405         mov ax, cx\r
406         imul ax, (-1 * MaskedPointSize)\r
407         add ax, offset @@LineDone + 2\r
408         mov cx, ax          ; jump offset for plotting\r
409 \r
410         mov ax, X           ; add x coordinate to screen position\r
411         mov bx, ax\r
412         shr ax, 2\r
413         add di, ax\r
414 \r
415         mov dx, SC_INDEX\r
416         mov al, MAP_MASK\r
417         out dx, al\r
418         inc dx\r
419 \r
420         and bx, 3           ; initial mask\r
421         xor ax, ax\r
422         mov al, ColumnMask[bx]\r
423         mov VGA_mask, ax\r
424         out dx, al\r
425 \r
426         mov column, 4\r
427         mov bitmap_pos, si\r
428         mov screen_pos, di\r
429         mov ax, _ScrnLogicalByteWidth\r
430         mov screen_width, ax ; since we move ds\r
431 \r
432 ; we've used all our tables, so we can change ds to point to the bitmap,\r
433 ; and es to point to the screen\r
434         mov ds, word ptr [Bitmap + 2]\r
435         mov ax, SCREEN_SEG\r
436         mov es, ax\r
437 \r
438         mov bx, width_copy\r
439 \r
440 ; let's actually draw something for a change\r
441         mov ax, clipped_height\r
442         mov height_temp, ax\r
443         mov dx, screen_width\r
444         jmp cx\r
445 \r
446 ; 90 bottles of beer on the wall...\r
447         PointLoop = 89\r
448         rept 89\r
449                 MaskedPoint PointLoop\r
450                 PointLoop = PointLoop - 1\r
451         endm\r
452 ; one bottle of beer...\r
453 \r
454 ; final point needs a different branch offset, so we don't use MaskedPoint\r
455         mov al, [si]\r
456         or al, al\r
457         jz @@LineDone\r
458         mov es:[di], al\r
459 \r
460 @@LineDone:\r
461         add si, bx          ; advance one bitmap line\r
462         add di, dx          ; advance one screen line\r
463         dec height_temp\r
464         jz @@PlaneDone\r
465         jmp cx\r
466 \r
467 @@PlaneDone:\r
468         dec column\r
469         jz @@OuttaHere      ; only four columns per customer, please\r
470         mov dx, SC_INDEX + 1\r
471         rol byte ptr VGA_mask, 1\r
472         adc screen_pos, 0   ; move to new column if we've wrapped to plane 0\r
473         mov al, byte ptr VGA_mask\r
474         out dx, al          ; set VGA for next column\r
475 \r
476         shr right_counter, 1\r
477         jnc @@NoRightCounter\r
478         add cx, MaskedPointSize ; cut off right edge for later planes\r
479 @@NoRightCounter:\r
480         shr left_counter, 1\r
481         jnc @@NoLeftCounter\r
482         sub cx, MaskedPointSize ; add to left edge for later planes\r
483         dec bitmap_pos\r
484         dec screen_pos\r
485 @@NoLeftCounter:\r
486         mov si, bitmap_pos\r
487         add si, bitmap_size\r
488         mov bitmap_pos, si\r
489         mov di, screen_pos\r
490 \r
491         mov ax, clipped_height\r
492         mov height_temp, ax\r
493         mov dx, screen_width\r
494         jmp cx\r
495 \r
496 @@OuttaHere:                    ; return a 0 -- something was inside the boundary\r
497         pop ds\r
498         pop di\r
499         pop si\r
500         mov ax, 0\r
501         mov sp, bp\r
502         pop bp\r
503         ret\r
504 _x_clip_masked_pbm endp\r
505 \r
506         end\r
507 \r