]> 4ch.mooo.com Git - 16.git/blob - 16/xlib/xpbitmap.asm
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / xlib / xpbitmap.asm
1 ;-----------------------------------------------------------------------\r
2 ; MODULE XPBITMAP\r
3 ;\r
4 ; Planar Bitmap functions - System Ram <-> Video Ram\r
5 ;\r
6 ; Compile with Tasm.\r
7 ; C callable.\r
8 ;\r
9 ;\r
10 ; ****** XLIB - Mode X graphics library                ****************\r
11 ; ******                                               ****************\r
12 ; ****** Written By Themie Gouthas                     ****************\r
13 ;\r
14 ; egg@dstos3.dsto.gov.au\r
15 ; teg@bart.dsto.gov.au\r
16 ;-----------------------------------------------------------------------\r
17 \r
18 \r
19 COMMENT $\r
20 \r
21   This module implements a set of functions to operate on planar bitmaps.\r
22   Planar bitmaps as used by these functions have the following structure:\r
23 \r
24   BYTE 0                 The bitmap width in bytes (4 pixel groups) range 1..255\r
25   BYTE 1                 The bitmap height in rows range 1..255\r
26   BYTE 2..n1             The plane 0 pixels width*height bytes\r
27   BYTE n1..n2            The plane 1 pixels width*height bytes\r
28   BYTE n2..n3            The plane 2 pixels width*height bytes\r
29   BYTE n3..n4            The plane 3 pixels width*height bytes\r
30 \r
31   These functions provide the fastest possible bitmap blts from system ram to\r
32   to video and further, the single bitmap is applicable to all pixel\r
33   allignments. The masked functions do not need separate masks since all non\r
34   zero pixels are considered to be masking pixels, hence if a pixel is 0 the\r
35   corresponding screen destination pixel is left unchanged.\r
36 \r
37 \r
38 $\r
39 \r
40 include xlib.inc\r
41 include xpbitmap.inc\r
42 LOCALS\r
43         .code\r
44 \r
45 ;----------------------------------------------------------------------\r
46 ; x_flip_masked_pbm - mask write a planar bitmap from system ram to video ram\r
47 ; all zero source bitmap bytes indicate destination byte to be left unchanged\r
48 ; If "Orientation" is set then the bitmap is flipped from left to right as\r
49 ; it is drawn\r
50 ;\r
51 ; Source Bitmap structure:\r
52 ;\r
53 ;  Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1)..,\r
54 ;  Bitmap data (plane 2)..,Bitmap data (plane 3)..\r
55 ;\r
56 ;  note width is in bytes ie lots of 4 pixels\r
57 ;\r
58 ;  x_flip_masked_pbm(X,Y,ScrnOffs,char far * Bitmap, Orientation)\r
59 ;\r
60 ;\r
61 ; LIMITATIONS: No clipping is supported\r
62 ;              Only supports bitmaps with widths which are a multiple of\r
63 ;              4 pixels\r
64 ;\r
65 ; Written by Themie Gouthas\r
66 ;----------------------------------------------------------------------\r
67 _x_flip_masked_pbm  proc\r
68         ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word\r
69         LOCAL Plane:byte,BMHeight:byte,LineInc:word=LocalStk\r
70         push  bp\r
71         mov   bp,sp\r
72         sub   sp,LocalStk                 ; Create space for local variables\r
73         push  si\r
74         push  di\r
75         push  ds\r
76         cld\r
77         mov   ax,SCREEN_SEG\r
78         mov   es,ax\r
79         mov   ax,[Y]                      ; Calculate dest screen row\r
80         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen\r
81         mul   bx                          ;  width then adding screen offset\r
82         mov   di,[ScrnOffs]               ;  store result in DI\r
83         add   di,ax\r
84         mov   cx,[X]                      ; Load X coord into CX and make a\r
85         mov   dx,cx                       ;  copy in DX\r
86         shr   dx,2                        ; Find starting byte in dest row\r
87         add   di,dx                       ;  add to DI giving screen offset of\r
88                                           ;  first pixel's byte\r
89         lds   si,[Bitmap]                 ; DS:SI -> Bitmap data\r
90         lodsw                             ; Al = B.M. width (bytes) AH = B.M.\r
91                                           ;  height\r
92         cmp   Orientation,0\r
93         jz    UnFlippedMasked\r
94 \r
95         mov   [BMHeight],ah               ; Save source bitmap dimensions\r
96         xor   ah,ah                       ; LineInc = bytes to the begin.\r
97         add   bx,ax                       ;  of bitmaps next row on screen\r
98         mov   [LineInc],bx\r
99         mov   bh,al                       ; Use bh as column loop count\r
100         and   cx,0003h                    ; mask X coord giving plane of 1st\r
101                                           ; bitmap pixel(zero CH coincidentally)\r
102         mov   ah,11h                      ; Init. mask for VGA plane selection\r
103         shl   ah,cl                       ; Shift for starting pixel plane\r
104         mov   dx,SC_INDEX                 ; Prepare VGA for cpu to video writes\r
105         mov   al,MAP_MASK\r
106         out   dx,al\r
107         inc   dx\r
108         mov   [Plane],4                   ; Set plane counter to 4\r
109 @@PlaneLoop:\r
110         push  di                          ; Save bitmap's start dest. offset\r
111         mov   bl,[BMHeight]               ; Reset row counter (BL)\r
112         mov   al,ah\r
113         out   dx,al                       ; set vga write plane\r
114 @@RowLoop:\r
115         mov   cl,bh                       ; Reset Column counter cl\r
116 @@ColLoop:\r
117         lodsb                             ; Get next source bitmap byte\r
118         or    al,al                       ; If not zero then write to dest.\r
119         jz    @@NoPixel                   ; otherwise skip to next byte\r
120         mov   es:[di],al\r
121 @@NoPixel:\r
122         dec   di\r
123         loop  @@ColLoop                   ; loop if more columns left\r
124         add   di,[LineInc]                ; Move to next row\r
125         dec   bl                          ; decrement row counter\r
126         jnz   @@RowLoop                   ; Jump if more rows left\r
127         pop   di                          ; Restore bitmaps start dest byte\r
128         ror   ah,1                        ; Shift mask for next plane\r
129         sbb   di,0                        ; If wrapped increment dest address\r
130         dec   [Plane]                     ; Decrement plane counter\r
131         jnz   @@PlaneLoop                 ; Jump if more planes left\r
132 \r
133         pop   ds                          ; restore data segment\r
134         pop   di                          ; restore registers\r
135         pop   si\r
136         mov   sp,bp                       ; dealloc local variables\r
137         pop   bp\r
138         ret\r
139 _x_flip_masked_pbm  endp\r
140 \r
141 \r
142 ;----------------------------------------------------------------------\r
143 ; x_put_masked_pbm - mask write a planar bitmap from system ram to video ram\r
144 ; all zero source bitmap bytes indicate destination byte to be left unchanged\r
145 ;\r
146 ; Source Bitmap structure:\r
147 ;\r
148 ;  Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1)..,\r
149 ;  Bitmap data (plane 2)..,Bitmap data (plane 3)..\r
150 ;\r
151 ;  note width is in bytes ie lots of 4 pixels\r
152 ;\r
153 ;  x_put_masked_pbm(X,Y,ScrnOffs,char far * Bitmap)\r
154 ;\r
155 ;\r
156 ; LIMITATIONS: No clipping is supported\r
157 ;              Only supports bitmaps with widths which are a multiple of\r
158 ;              4 pixels\r
159 ;\r
160 ; Written by Themie Gouthas\r
161 ;----------------------------------------------------------------------\r
162 _x_put_masked_pbm  proc\r
163         ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword\r
164         LOCAL Plane:byte,BMHeight:byte,LineInc:word=LocalStk\r
165         push  bp\r
166         mov   bp,sp\r
167         sub   sp,LocalStk                 ; Create space for local variables\r
168         push  si\r
169         push  di\r
170         push  ds\r
171         cld\r
172         mov   ax,SCREEN_SEG\r
173         mov   es,ax\r
174         mov   ax,[Y]                      ; Calculate dest screen row\r
175         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen\r
176         mul   bx                          ;  width then adding screen offset\r
177         mov   di,[ScrnOffs]               ;  store result in DI\r
178         add   di,ax\r
179         mov   cx,[X]                      ; Load X coord into CX and make a\r
180         mov   dx,cx                       ;  copy in DX\r
181         shr   dx,2                        ; Find starting byte in dest row\r
182         add   di,dx                       ;  add to DI giving screen offset of\r
183                                           ;  first pixel's byte\r
184         lds   si,[Bitmap]                 ; DS:SI -> Bitmap data\r
185         lodsw                             ; Al = B.M. width (bytes) AH = B.M.\r
186                                           ;  height\r
187 UnFlippedMasked:\r
188         mov   [BMHeight],ah               ; Save source bitmap dimensions\r
189         xor   ah,ah                       ; LineInc = bytes to the begin.\r
190         sub   bx,ax                       ;  of bitmaps next row on screen\r
191         mov   [LineInc],bx\r
192         mov   bh,al                       ; Use bh as column loop count\r
193         and   cx,0003h                    ; mask X coord giving plane of 1st\r
194                                           ; bitmap pixel(zero CH coincidentally)\r
195         mov   ah,11h                      ; Init. mask for VGA plane selection\r
196         shl   ah,cl                       ; Shift for starting pixel plane\r
197         mov   dx,SC_INDEX                 ; Prepare VGA for cpu to video writes\r
198         mov   al,MAP_MASK\r
199         out   dx,al\r
200         inc   dx\r
201         mov   [Plane],4                   ; Set plane counter to 4\r
202 @@PlaneLoop:\r
203         push  di                          ; Save bitmap's start dest. offset\r
204         mov   bl,[BMHeight]               ; Reset row counter (BL)\r
205         mov   al,ah\r
206         out   dx,al                       ; set vga write plane\r
207 @@RowLoop:\r
208         mov   cl,bh                       ; Reset Column counter cl\r
209 @@ColLoop:\r
210         lodsb                             ; Get next source bitmap byte\r
211         or    al,al                       ; If not zero then write to dest.\r
212         jz    @@NoPixel                   ; otherwise skip to next byte\r
213         mov   es:[di],al\r
214 @@NoPixel:\r
215         inc   di\r
216         loop  @@ColLoop                   ; loop if more columns left\r
217         add   di,[LineInc]                ; Move to next row\r
218         dec   bl                          ; decrement row counter\r
219         jnz   @@RowLoop                   ; Jump if more rows left\r
220         pop   di                          ; Restore bitmaps start dest byte\r
221         rol   ah,1                        ; Shift mask for next plane\r
222         adc   di,0                        ; If wrapped increment dest address\r
223         dec   [Plane]                     ; Decrement plane counter\r
224         jnz   @@PlaneLoop                 ; Jump if more planes left\r
225 \r
226         pop   ds                          ; restore data segment\r
227         pop   di                          ; restore registers\r
228         pop   si\r
229         mov   sp,bp                       ; dealloc local variables\r
230         pop   bp\r
231         ret\r
232 _x_put_masked_pbm  endp\r
233 \r
234 \r
235 \r
236 ;----------------------------------------------------------------------\r
237 ; x_put_pbm - Write a planar bitmap from system ram to video ram\r
238 ;\r
239 ; Source Bitmap structure:\r
240 ;\r
241 ;  Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1)..,\r
242 ;  Bitmap data (plane 2)..,Bitmap data (plane 3)..\r
243 ;\r
244 ;  note width is in bytes ie lots of 4 pixels\r
245 ;\r
246 ;  x_put_pbm(X,Y,ScrnOffs,char far * Bitmap)\r
247 ;\r
248 ;\r
249 ; LIMITATIONS: No clipping is supported\r
250 ;              Only supports bitmaps with widths which are a multiple of\r
251 ;              4 pixels\r
252 ; FEATURES   : Automatically selects REP MOVSB or REP MOVSW  depending on\r
253 ;              source bitmap width, by modifying opcode ;-).\r
254 ;\r
255 ; Written by Themie Gouthas\r
256 ;----------------------------------------------------------------------\r
257 \r
258 \r
259 _x_put_pbm  proc\r
260         ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword\r
261         LOCAL Plane:byte,BMHeight:byte,LineInc:word=LocalStk\r
262         push  bp\r
263         mov   bp,sp\r
264         sub   sp,LocalStk                 ; Create space for local variables\r
265         push  si\r
266         push  di\r
267         push  ds\r
268         cld\r
269         mov   ax,SCREEN_SEG\r
270         mov   es,ax\r
271         mov   ax,[Y]                      ; Calculate dest screen row\r
272         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen\r
273         mul   bx                          ;  width then adding screen offset\r
274         mov   di,[ScrnOffs]               ;  store result in DI\r
275         add   di,ax\r
276         mov   cx,[X]                      ; Load X coord into CX and make a\r
277         mov   dx,cx                       ;  copy in DX\r
278         shr   dx,2                        ; Find starting byte in dest row\r
279         add   di,dx                       ;  add to DI giving screen offset of\r
280                                           ;  first pixel's byte\r
281         lds   si,[Bitmap]                 ; DS:SI -> Bitmap data\r
282         lodsw                             ; Al = B.M. width (bytes) AH = B.M.\r
283                                           ;  height\r
284 UnFlipped:\r
285         mov   [BMHeight],ah               ; Save source bitmap dimensions\r
286         xor   ah,ah                       ; LineInc = bytes to the begin.\r
287         sub   bx,ax                       ;  of bitmaps next row on screen\r
288         mov   [LineInc],bx\r
289         mov   bh,al\r
290                                           ; Self Modifying, Shame, shame shame..\r
291         and   cx,0003h                    ; mask X coord giving plane of 1st\r
292                                           ; bitmap pixel(zero CH coincidentally)\r
293         mov   ah,11h                      ; Init. mask for VGA plane selection\r
294         shl   ah,cl                       ; Shift for starting pixel plane\r
295         mov   dx,SC_INDEX                 ; Prepare VGA for cpu to video writes\r
296         mov   al,MAP_MASK\r
297         out   dx,al\r
298         inc   dx\r
299         mov   [Plane],4                   ; Set plane counter to 4\r
300 @@PlaneLoop:\r
301         push  di\r
302         mov   bl,[BMHeight]\r
303         mov   al,ah\r
304         out   dx,al\r
305 @@RowLoop:\r
306         mov   cl,bh\r
307         shr   cl,1\r
308         rep   movsw                       ; Copy a complete row for curr plane\r
309         adc   cl,0\r
310         rep   movsb\r
311         add   di,[LineInc]                ; Move to next row\r
312         dec   bl                          ; decrement row counter\r
313         jnz   @@RowLoop                   ; Jump if more rows left\r
314         pop   di                          ; Restore bitmaps start dest byte\r
315         rol   ah,1                        ; Shift mask for next plane\r
316         adc   di,0                        ; If wrapped increment dest address\r
317         dec   [Plane]                     ; Decrement plane counter\r
318         jnz   @@PlaneLoop                 ; Jump if more planes left\r
319 \r
320         pop   ds                          ; restore data segment\r
321         pop   di                          ; restore registers\r
322         pop   si\r
323         mov   sp,bp                       ; dealloc local variables\r
324         pop   bp\r
325         ret\r
326 _x_put_pbm  endp\r
327 \r
328 ;----------------------------------------------------------------------\r
329 ; x_flip_pbm - Write a planar bitmap from system ram to video ram\r
330 ; If "Orientation" is set then the bitmap is flipped from left to right as\r
331 ; it is drawn\r
332 \r
333 ;\r
334 ; Source Bitmap structure:\r
335 ;\r
336 ;  Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1)..,\r
337 ;  Bitmap data (plane 2)..,Bitmap data (plane 3)..\r
338 ;\r
339 ;  note width is in bytes ie lots of 4 pixels\r
340 ;\r
341 ;  x_flip_pbm(X,Y,ScrnOffs,char far * Bitmap, WORD orientation)\r
342 ;\r
343 ;\r
344 ; LIMITATIONS: No clipping is supported\r
345 ;              Only supports bitmaps with widths which are a multiple of\r
346 ;              4 pixels\r
347 ;\r
348 ; NOTES: The flipped put function is slower than the standard put function\r
349 ;\r
350 ; Written by Themie Gouthas\r
351 ;----------------------------------------------------------------------\r
352 _x_flip_pbm  proc\r
353         ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word\r
354         LOCAL Plane:byte,BMHeight:byte,LineInc:word=LocalStk\r
355         push  bp\r
356         mov   bp,sp\r
357         sub   sp,LocalStk                 ; Create space for local variables\r
358         push  si\r
359         push  di\r
360         push  ds\r
361         cld\r
362         mov   ax,SCREEN_SEG\r
363         mov   es,ax\r
364         mov   ax,[Y]                      ; Calculate dest screen row\r
365         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen\r
366         mul   bx                          ;  width then adding screen offset\r
367         mov   di,[ScrnOffs]               ;  store result in DI\r
368         add   di,ax\r
369         mov   cx,[X]                      ; Load X coord into CX and make a\r
370         mov   dx,cx                       ;  copy in DX\r
371         shr   dx,2                        ; Find starting byte in dest row\r
372         add   di,dx                       ;  add to DI giving screen offset of\r
373                                           ;  first pixel's byte\r
374         lds   si,[Bitmap]                 ; DS:SI -> Bitmap data\r
375         lodsw                             ; Al = B.M. width (bytes) AH = B.M.\r
376                                           ;  height\r
377         cmp   Orientation,0\r
378         jz    UnFlipped\r
379 \r
380         mov   [BMHeight],ah               ; Save source bitmap dimensions\r
381         xor   ah,ah                       ; LineInc = bytes to the begin.\r
382         add   bx,ax                       ;  of bitmaps next row on screen\r
383         mov   [LineInc],bx\r
384         mov   bh,al                       ; Use bh as column loop count\r
385         and   cx,0003h                    ; mask X coord giving plane of 1st\r
386                                           ; bitmap pixel(zero CH coincidentally)\r
387         mov   ah,11h                      ; Init. mask for VGA plane selection\r
388         shl   ah,cl                       ; Shift for starting pixel plane\r
389         mov   dx,SC_INDEX                 ; Prepare VGA for cpu to video writes\r
390         mov   al,MAP_MASK\r
391         out   dx,al\r
392         inc   dx\r
393         mov   [Plane],4                   ; Set plane counter to 4\r
394 @@PlaneLoop:\r
395         push  di                          ; Save bitmap's start dest. offset\r
396         mov   bl,[BMHeight]               ; Reset row counter (BL)\r
397         mov   al,ah\r
398         out   dx,al                       ; set vga write plane\r
399 @@RowLoop:\r
400         mov   cl,bh                       ; Reset Column counter cl\r
401 @@ColLoop:\r
402         lodsb\r
403         mov   es:[di],al\r
404         dec   di\r
405         sub   di,2\r
406         loop  @@ColLoop                   ; loop if more columns left\r
407 @@DoneCol:\r
408         add   di,[LineInc]                ; Move to next row\r
409         dec   bl                          ; decrement row counter\r
410         jnz   @@RowLoop                   ; Jump if more rows left\r
411         pop   di                          ; Restore bitmaps start dest byte\r
412         ror   ah,1                        ; Shift mask for next plane\r
413         sbb   di,0                        ; If wrapped increment dest address\r
414         dec   [Plane]                     ; Decrement plane counter\r
415         jnz   @@PlaneLoop                 ; Jump if more planes left\r
416 \r
417         pop   ds                          ; restore data segment\r
418         pop   di                          ; restore registers\r
419         pop   si\r
420         mov   sp,bp                       ; dealloc local variables\r
421         pop   bp\r
422         ret\r
423 _x_flip_pbm  endp\r
424 \r
425 \r
426 ;----------------------------------------------------------------------\r
427 ; x_get_pbm - Read a planar bitmap to system ram from video ram\r
428 ;\r
429 ; Source Bitmap structure:\r
430 ;\r
431 ;  Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1)..,\r
432 ;  Bitmap data (plane 2)..,Bitmap data (plane 3)..\r
433 ;\r
434 ;  note width is in bytes ie lots of 4 pixels\r
435 ;\r
436 ;  x_get_pbm(X,Y,BMwidth,BMheight,ScrnOffs,char far * Bitmap)\r
437 ;\r
438 ;\r
439 ; LIMITATIONS: No clipping is supported\r
440 ;              Only supports bitmaps with widths which are a multiple of\r
441 ;              4 pixels\r
442 ; FEATURES   : Automatically selects REP MOVSB or REP MOVSW  depending on\r
443 ;              source bitmap width, by modifying opcode ;-).\r
444 ;\r
445 ; Written by Themie Gouthas\r
446 ;----------------------------------------------------------------------\r
447 _x_get_pbm  proc\r
448         ARG X:word,Y:word,SrcWidth:byte,SrcHeight:byte,ScrnOffs:word,Bitmap:dword\r
449         LOCAL Plane:byte,LineInc:word=LocalStk\r
450         push  bp\r
451         mov   bp,sp\r
452         sub   sp,LocalStk                 ; Create space for local variables\r
453         push  si\r
454         push  di\r
455         push  ds\r
456         cld\r
457 \r
458         mov   ax,[Y]                      ; Calculate screen row\r
459         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. Y coord by Screen\r
460         mul   bx                          ;  width then adding screen offset\r
461         mov   si,[ScrnOffs]               ;  store result in SI\r
462         add   si,ax\r
463         mov   cx,[X]                      ; Load X coord into CX and make a\r
464         mov   dx,cx                       ;  copy in DX\r
465         shr   dx,2                        ; Find starting byte in screen row\r
466         add   si,dx                       ;  add to SI giving screen offset of\r
467                                           ;  first pixel's byte\r
468         mov   ax,SCREEN_SEG\r
469         mov   ds,ax\r
470         les   di,[Bitmap]                 ; ES:DI -> Bitmap data\r
471         mov   al,[SrcWidth]\r
472         mov   ah,[SrcHeight]\r
473         stosw                             ; Al = B.M. width (bytes) AH = B.M.\r
474                                           ;  height\r
475         xor   ah,ah                       ; LineInc = bytes to the begin.\r
476         sub   bx,ax                       ;  of bitmaps next row on screen\r
477         mov   [LineInc],bx\r
478         mov   bh,al\r
479                                           ; Self Modifying, Shame, shame shame..\r
480         and   cx,0003h                    ; mask X coord giving plane of 1st\r
481                                           ; bitmap pixel(zero CH coincidentally)\r
482         mov   ah,11h                      ; Init. mask for VGA plane selection\r
483         shl   ah,cl                       ; Shift for starting pixel plane\r
484         mov   dx,GC_INDEX                 ; Prepare VGA for cpu to video reads\r
485         mov   al,READ_MAP\r
486         out   dx,al\r
487         inc   dx\r
488         mov   [Plane],4                   ; Set plane counter (BH) to 4\r
489         mov   al,cl\r
490 @@PlaneLoop:\r
491         push  si\r
492         mov   bl,[SrcHeight]\r
493         out   dx,al\r
494 @@RowLoop:\r
495         mov   cl,bh\r
496         shr   cl,1\r
497         rep   movsw                       ; Copy a complete row for curr plane\r
498         adc   cl,0\r
499         rep   movsb\r
500         add   si,[LineInc]                ; Move to next row\r
501         dec   bl                          ; decrement row counter\r
502         jnz   @@RowLoop                   ; Jump if more rows left\r
503         pop   si                          ; Restore bitmaps start dest byte\r
504 \r
505         inc   al                          ; Select next plane to read from\r
506         and   al,3                        ;\r
507 \r
508         rol   ah,1                        ; Shift mask for next plane\r
509         adc   si,0                        ; If wrapped increment dest address\r
510         dec   [Plane]                     ; Decrement plane counter\r
511         jnz   @@PlaneLoop                 ; Jump if more planes left\r
512 \r
513         pop   ds                          ; restore data segment\r
514         pop   di                          ; restore registers\r
515         pop   si\r
516         mov   sp,bp                       ; dealloc local variables\r
517         pop   bp\r
518         ret\r
519 _x_get_pbm  endp\r
520 \r
521 \r
522 \r
523 \r
524         end\r
525 \r
526 \r
527 \r
528         ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word\r
529         LOCAL Plane:byte,BMHeight:byte,LineInc:word,Columns:byte=LocalStk\r
530         push  bp\r
531         mov   bp,sp\r
532         sub   sp,LocalStk                 ; Create space for local variables\r
533         push  si\r
534         push  di\r
535         push  ds\r
536         cld\r
537         mov   ax,SCREEN_SEG\r
538         mov   es,ax\r
539         mov   ax,[Y]                      ; Calculate dest screen row\r
540         mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen\r
541         mul   bx                          ;  width then adding screen offset\r
542         mov   di,[ScrnOffs]               ;  store result in DI\r
543         add   di,ax\r
544         mov   cx,[X]                      ; Load X coord into CX and make a\r
545         mov   dx,cx                       ;  copy in DX\r
546         shr   dx,2                        ; Find starting byte in dest row\r
547         add   di,dx                       ;  add to DI giving screen offset of\r
548                                           ;  first pixel's byte\r
549         lds   si,[Bitmap]                 ; DS:SI -> Bitmap data\r
550         lodsw                             ; Al = B.M. width (bytes) AH = B.M.\r
551                                           ;  height\r
552         cmp   Orientation,0\r
553         jz    UnFlipped\r
554 \r
555         mov   [BMHeight],ah               ; Save source bitmap dimensions\r
556         xor   ah,ah                       ; LineInc = bytes to the begin.\r
557         add   bx,ax                       ;  of bitmaps next row on screen\r
558         mov   [LineInc],bx\r
559         mov   [Columns],al                ; Use bh as column loop count\r
560         and   cx,0003h                    ; mask X coord giving plane of 1st\r
561                                           ; bitmap pixel(zero CH coincidentally)\r
562         mov   ah,11h                      ; Init. mask for VGA plane selection\r
563         shl   ah,cl                       ; Shift for starting pixel plane\r
564         mov   bh,ah\r
565         mov   dx,SC_INDEX                 ; Prepare VGA for cpu to video writes\r
566         mov   al,MAP_MASK\r
567         out   dx,al\r
568         inc   dx\r
569         mov   [Plane],4                   ; Set plane counter to 4\r
570 @@PlaneLoop:\r
571         push  di                          ; Save bitmap's start dest. offset\r
572         mov   bl,[BMHeight]               ; Reset row counter (BL)\r
573         mov   al,bh\r
574         out   dx,al                       ; set vga write plane\r
575 @@RowLoop:\r
576         mov   cl,[Columns]                ; Reset Column counter cl\r
577         shr   cx,1\r
578         jnc   @@ColLoop\r
579         lodsb\r
580         mov   es:[di],al\r
581         dec   di\r
582 @@ColLoop:\r
583         lodsw                             ; Get next source bitmap byte\r
584         xchg  al,ah\r
585         mov   es:[di],ax\r
586         sub   di,2\r
587         loop  @@ColLoop                   ; loop if more columns left\r
588 \r
589         add   di,[LineInc]                ; Move to next row\r
590         dec   bl                          ; decrement row counter\r
591         jnz   @@RowLoop                   ; Jump if more rows left\r
592         pop   di                          ; Restore bitmaps start dest byte\r
593         ror   bh,1                        ; Shift mask for next plane\r
594         sbb   di,0                        ; If wrapped increment dest address\r
595         dec   [Plane]                     ; Decrement plane counter\r
596         jnz   @@PlaneLoop                 ; Jump if more planes left\r
597 \r
598         pop   ds                          ; restore data segment\r
599         pop   di                          ; restore registers\r
600         pop   si\r
601         mov   sp,bp                       ; dealloc local variables\r
602         pop   bp\r
603         ret