1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
|
PAGE ,132 ;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;AN000;
;; DOS - GRAPHICS Command
;; (c) Copyright 1988 Microsoft
;; ;AN000;
;; File Name: GRCOMMON.ASM ;AN000;
;; ---------- ;AN000;
;; ;AN000;
;; Description: ;AN000;
;; ------------ ;AN000;
;; ;AN000;
;; This file contains the modules common to the Print Screen ;AN000;
;; process of GRAPHICS.COM. ;AN000;
;; This file is included by both set of Print modules. ;AN000;
;; ;AN000;
;; This file MUST BE COMPILED WITH EACH SET OF MODULES since, ;AN000;
;; one set is relocated in memory at installation time; all ;AN000;
;; references to the common procedures must be resolved from ;AN000;
;; within each set of print modules. ;AN000;
;; ;AN000;
;; The set of common modules is relocated in memory along with ;AN000;
;; the selected set of print modules. ;AN000;
;; ;AN000;
;; Documentation Reference: ;AN000;
;; ------------------------ ;AN000;
;; OASIS High Level Design ;AN000;
;; OASIS GRAPHICS I1 Overview ;AN000;
;; ;AN000;
;; Procedures Contained in This File: ;AN000;
;; ---------------------------------- ;AN000;
;; READ_DOT ;AN000;
;; LOC_MODE_PRT_INFO ;AN000;
;; STORE_BOX ;AN000;
;; PRINT_BUFFER ;AN000;
;; GET_SCREEN_INFO ;AN000;
;; SETUP_PRT ;AN000;
;; RESTORE_PRT ;AN000;
;; NEW_PRT_LINE ;AN000;
;; PRINT_BYTE ;AN000;
;; DET_CUR_SCAN_LNE_LENGTH ;AN000;
;; ;AN000;
;; Include Files Required: ;AN000;
;; ----------------------- ;AN000;
;; none ;AN000;
;; ;AN000;
;; External Procedure References: ;AN000;
;; ------------------------------ ;AN000;
;; FROM FILE GRCTRL.ASM: ;AN000;
;; PRT_SCR - Main module for printing the screen. ;AN000;
;; FROM FILE GRBWPRT.ASM: ;AN000;
;; PRT_BW_APA - Main module for printing on BW printer. ;AN000;
;; FROM FILE GRCOLPRT.ASM: ;AN000;
;; PRINT_COLOR - Main module for printing on COLOR printer. ;AN000;
;; ;AN000;
;; Linkage Instructions: ;AN000;
;; -------------------- ;AN000;
;; ;AN000;
;; This file is included by both GRBWPRT.ASM and GRCOLPRT.ASM and is ;AN000;
;; compiled with each of them. However, only one copy is made resident. ;AN000;
;; ;AN000;
;; Change History: ;AN000;
;; --------------- ;AN000;
;; ;AN000;
;; ;AN000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;AN000;
;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; LOC_MODE_PRT_INFO: LOCATE DISPLAYMODE PRINTER INFO. FOR THE CURRENT ;AN000;
; MODE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: BP = Offset of the shared data area ;AN000;
; CUR_MODE = Current video mode ;AN000;
; ;AN000;
; OUTPUT: CUR_MODE_PTR = Absolute Offset of the ;AN000;
; current DISPLAYMODE INFO record. ;AN000;
; ;AN000;
; ERROR_CODE = DISPLAYMODE_INFO_NOT_FOUND if not found. ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRINT_BW_APA ;AN000;
; ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: DISPLAYMODE_PTR is pointing to the first DISPLAYMODE ;AN000;
; INFO record within the Shared Data Area. ;AN000;
; ;AN000;
; This (chained) list of DISPLAYMODE records is scanned until the record ;AN000;
; for the current mode is found. ;AN000;
; ;AN000;
; Note: All pointers in the DISPLAYMODE records are relative to the beginning ;AN000;
; of the shared data area. Therefore, we must add the offset of the ;AN000;
; shared data area (in BP) in order to access the data these pointers ;AN000;
; are referencing. ;AN000;
; ;AN000;
; The CUR_MODE_PTR is relative to the segment and references the ;AN000;
; DISPLAYMODE record for the video mode currently set at print screen ;AN000;
; time. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; FOUND := FALSE ;AN000;
; DO UNTIL FOUND OR END_OF_LIST ;AN000;
; Get a display mode information record ;AN000;
; IF record.DISP_MODE = CUR_MODE ;AN000;
; THEN FOUND := TRUE ;AN000;
; ELSE ;AN000;
; CUR_MODE_PTR := record.NEXT_DISP_MODE ;AN000;
; ;AN000;
; ;AN000;
;AN000;
LOC_MODE_PRT_INFO PROC NEAR ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH SI ;AN000;
;AN000;
MOV BX,DS:[BP].DISPLAYMODE_PTR ; [BX] := Current DISPLAYMODE ;AN000;
ADD BX,BP ; record ;AN000;
MOV DL,CUR_MODE ; DL := Current mode ;AN000;
;AN000;
SCAN_1_DISPLAYMODE_RECORD: ;AN000;
MOV SI,[BX].DISP_MODE_LIST_PTR ; [SI] : First mode covered ;AN000;
ADD SI,BP ; by this DISPLAYMODE record ;AN000;
MOV CL,[BX].NUM_DISP_MODE ; Scan each mode in the list ;AN000;
XOR CH,CH ;AN000;
SCAN_LIST_OF_MODES: ;AN000;
CMP CS:[SI],DL ; FOUND ? ;AN000;
JE FOUND ;AN000;
INC SI ; NO, get next mode in ;AN000;
LOOP SCAN_LIST_OF_MODES ; DISPLAYMODE record ;AN000;
;AN000;
CMP [BX].NEXT_DISP_MODE,-1 ; END OF DISPLAYMODE LIST ? ;AN000;
JE NOT_FOUND ; Yes, this mode not supported ;AN000;
NEXT_RECORD: ; No, ;AN000;
MOV BX,[BX].NEXT_DISP_MODE ; [BX] := Next record ;AN000;
ADD BX,BP ; ;AN000;
JMP SHORT SCAN_1_DISPLAYMODE_RECORD ;AN000;
;AN000;
FOUND: ; Found: ;AN000;
MOV CUR_MODE_PTR,BX ; Update pointer to current ;AN000;
JMP SHORT LOC_MODE_PRT_INFO_END ; DISPLAYMODE record. ;AN000;
;AN000;
NOT_FOUND: ; Not found: ;AN000;
MOV ERROR_CODE,DISPLAYMODE_INFO_NOT_FOUND ; Return error condition ;AN000;
;AN000;
LOC_MODE_PRT_INFO_END: ;AN000;
POP SI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
LOC_MODE_PRT_INFO ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; STORE_BOX : STORE ONE BOX IN THE PRINT BUFFER. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: SI = OFFSET OF THE BOX TO BE PRINTED ;AN000;
; BOX_W = BOX WIDTH IN BITS ;AN000;
; BOX_H = BOX HEIGHT IN BITS ;AN000;
; ;AN000;
; OUTPUT: PRT_BUF = THE PRINT BUFFER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: The print buffer is first shifted left in order to make ;AN000;
; room for the new box (Note: the MSB's are lost; they are assumed to ;AN000;
; have been printed), then the box is inserted in the low-order bits of ;AN000;
; the printer buffer. ;AN000;
; ;AN000;
PAGE ;AN000;
; EXAMPLE ;AN000;
; ------- ;AN000;
; BEFORE: AFTER: ;AN000;
; ;AN000;
; BOX: 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; 0 0 0 ;AN000;
; b1 b2 b3 ;AN000;
; b4 b5 b6 ;AN000;
; ;AN000;
; PRT_BUF: byte1 byte2 byte3 PRT_BUF: byte1 byte2 byte3 ;AN000;
; 0 1 0 1 1 1 ;AN000;
; 1 0 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 1 1 1 ;AN000;
; 1 1 1 b1 b2 b3 ;AN000;
; LSB --> 1 1 1 b4 b5 b6 ;AN000;
; ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; FOR each byte of the buffer (BOX_W) ;AN000;
; BEGIN ;AN000;
; Make room for the box to be inserted ;AN000;
; Insert the box ;AN000;
; END ;AN000;
; ;AN000;
STORE_BOX PROC NEAR ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DI ;AN000;
;AN000;
MOV DI,OFFSET PRT_BUF ; DI := Offset of the Print buffer ;AN000;
XOR BX,BX ; BX := Byte index number ;AN000;
;AN000;
MOV CL,BOX_H ; CL := Number of BITS to be shifted ;AN000;
; FOR each column (byte) of the box to be stored in the buffer: ;AN000;
STORE_1_BYTE: ;AN000;
SHL BYTE PTR [BX][DI],CL ; Make room for the bits to be inserted ;AN000;
MOV CH,[BX][SI] ; CH := column of the box to be inserted;AN000;
OR [BX][DI],CH ; Insert the box column in the buffer ;AN000;
INC BL ; Get next column (byte) of the box ;AN000;
CMP BL,BOX_W ; All columns (bytes) of box stored ? ;AN000;
JL STORE_1_BYTE ; No, store next one. ;AN000;
;AN000;
STORE_BOX_END: ;AN000;
POP DI ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
STORE_BOX ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; PRINT_BUFFER : PRINT THE BUFFER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: PRT_BUF = BYTES TO BE PRINTED ;AN000;
; BOW_W = BOX WIDTH ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Prints BOX_W bytes. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; DO for each column in one pattern ;AN000;
; BEGIN ;AN000;
; Print one byte from the buffer ;AN000;
; END ;AN000;
; ;AN000;
PRINT_BUFFER PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,OFFSET PRT_BUF ;AN000;
XOR CX,CX ;AN000;
MOV CL,BOX_W ;AN000;
PRINT_1_BUF_COLUMN: ;AN000;
MOV AL,[BX] ; Print one byte ;AN000;
CALL PRINT_BYTE ;AN000;
JC PRINT_BUFFER_END; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP PRINT_1_BUF_COLUMN ;AN000;
PRINT_BUFFER_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
PRINT_BUFFER ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; GET_SCREEN_INFO : GET INFORMATION ABOUT HOW TO READ THE SCREEN. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: SCREEN_HEIGHT = Number of pixel rows on the screen ;AN000;
; SCREEN_WIDTH = Number of pixel columns on screen ;AN000;
; CUR_MODE_PTR = Offset of the current DISPLAYMODE info rec. ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; SCAN_LINE_MAX_LENGTH = Maximum length of Screen scan line. ;AN000;
; NB_SCAN_LINES = Number of SCAN LINES on the screen ;AN000;
; CUR_ROW,CUR_COLUMN = Coordinates of the first pixel to be ;AN000;
; read on the screen ;AN000;
; NB_BOXES_PER_PRT_BUF = Number of boxes fitting in the Print ;AN000;
; buffer ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: ;AN000;
; ;AN000;
; 1) Determine where to start reading the screen. ;AN000;
; For non-rotated printing, it should start with the top-left ;AN000;
; corner pixel. ;AN000;
; For rotated printing, it should start with the low-left corner ;AN000;
; pixel. ;AN000;
; ;AN000;
; 2) Determine the length of a scan line. ;AN000;
; For non-rotated printing, it is the WIDTH of the screen. ;AN000;
; For rotated printing, it is the HEIGHT of the screen. ;AN000;
; ;AN000;
; 3) Determine the number of scan lines on the screen. ;AN000;
; For non-rotated printing, it is the HEIGHT of the screen divided ;AN000;
; by the number of boxes fitting in the print buffer. ;AN000;
; For rotated printing, it is the WIDTH of the screen divided by ;AN000;
; the number of boxes fitting in the print buffer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; CUR_COLUMN := 0 ;AN000;
; IF printing is sideways ;AN000;
; THEN ;AN000;
; CUR_ROW := SCREEN_HEIGHT - 1 ; Low-left pixel ;AN000;
; SCAN_LINE_MAX_LENGTH := SCREEN_HEIGHT ;AN000;
; NB_SCAN_LINES := SCREEN_WIDTH / NB_BOXES_PER_PRT_BUF ;AN000;
; ELSE ;AN000;
; CUR_ROW := 0 ; Top-left pixel ;AN000;
; SCAN_LINE_MAX_LENGTH := SCREEN_WIDTH ;AN000;
; NB_SCAN_LINES := SCREEN_HEIGHT / NB_BOXES_PER_PRT_BUF ;AN000;
; ;AN000;
; ;AN000;
GET_SCREEN_INFO PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ; Used for DIV ;AN000;
PUSH DX ; Used for DIV ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Offset DISPLAYMODE info record ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Calculate how many printer boxes fit in the print buffer: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AX,8 ; Num := 8 bits / Box heigth ;AN000;
MOV DL,[BX].BOX_HEIGHT ;AN000;
DIV DL ;AN000;
MOV NB_BOXES_PER_PRT_BUF,AL ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Determine where to start reading the screen: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV CUR_COLUMN,0 ; Reading always start from left of scr ;AN000;
.IF <[BX].PRINT_OPTIONS EQ ROTATE> ;AN000;
.THEN ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Printing is sideways; screen must be read starting in low-left corner. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AX,SCREEN_HEIGHT ;AN000;
MOV SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen height ;AN000;
DEC AX ;AN000;
MOV CUR_ROW,AX ; First row := screen height - 1 ;AN000;
;AN000;
;-------Calculate the number of scan lines: ;AN000;
MOV AX,SCREEN_WIDTH ; DX AX = Screen width ;AN000;
CWD ; ;AN000;
XOR BX,BX ; BX = Number of boxes per print buf ;AN000;
MOV BL,NB_BOXES_PER_PRT_BUF ; ;AN000;
DIV BX ; Screen width / number boxes per buff ;AN000;
MOV NB_SCAN_LINES,AX ; Number of scan lines := result ;AN000;
.ELSE ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Printing is not sideways; screen must be read starting in top-left corner ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AX,SCREEN_WIDTH ;AN000;
MOV SCAN_LINE_MAX_LENGTH,AX ; Scan line length := screen width ;AN000;
MOV CUR_ROW,0 ; First row := 0 ;AN000;
;AN000;
;-------Calculate the number of scan lines: ;AN000;
MOV AX,SCREEN_HEIGHT ; DX AX = Screen height ;AN000;
CWD ; ;AN000;
XOR BX,BX ; BX = Number of boxes per print buff ;AN000;
MOV BL,NB_BOXES_PER_PRT_BUF ; ;AN000;
DIV BX ; Screen height/number boxes per buff. ;AN000;
MOV NB_SCAN_LINES,AX ; Number of scan lines := result ;AN000;
.ENDIF ;AN000;
POP DX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
GET_SCREEN_INFO ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; DET_CUR_SCAN_LNE_LENGTH : Determine where is the last non-blank "scan line ;AN000;
; column" on the current scan line. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_ROW, ;AN000;
; CUR_COLUMN = Coordinates of the top pixel of the current ;AN000;
; scan line. ;AN000;
; XLT_TAB = Color translation table ;AN000;
; ;AN000;
; OUTPUT: CUR_SCAN_LNE_LENGTH = Number of "columns" of pixels from the ;AN000;
; beginning of the scan line up to ;AN000;
; the last non-blank pixel. ;AN000;
; ;AN000;
; DATA SCREEN_WIDTH, ;AN000;
; REFERENCED: SCREEN_HEIGHT = Dimensions of the screen in pels ;AN000;
; SCAN_LINE_MAX_LENGTH= Maximum length of the scan line ;AN000;
; ROTATE_SW = ON if printing is sideways ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Determine where is the last non-blank "column" by reading ;AN000;
; the scan line backwards, one column at a time. ;AN000;
; ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; ; Obtain coordinates for the top pixel of the last column on the current ;AN000;
; ; scan line: ;AN000;
; IF printing is sideways ;AN000;
; THEN ;AN000;
; CUR_ROW := 0 ;AN000;
; ELSE ;AN000;
; CUR_COLUMN := SCREEN_WIDTH - 1 ;AN000;
; ;AN000;
; CUR_SCAN_LNE_LENGTH := SCAN_LINE_MAX_LENGTH ;AN000;
; ; Read a column of pixels on the scan line until a non-blank is found: ;AN000;
; For each column on the screen ;AN000;
; CALL FILL_BUFF ;AN000;
; ; Check if PRT_BUF is empty ;AN000;
; IF buffer is empty ;AN000;
; THEN DEC CUR_SCAN_LNE_LENGTH ;AN000;
; ; Get next column ;AN000;
; IF printing sideways THEN DEC CUR_ROW ;AN000;
; ELSE DEC CUR_COLUMN ;AN000;
; ELSE quit the loop ;AN000;
; ;AN000;
DET_CUR_SCAN_LNE_LENGTH PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH SI ;AN000;
PUSH DI ;AN000;
PUSH CUR_COLUMN ;AN000;
PUSH CUR_ROW ;AN000;
;AN000;
MOV BX,OFFSET XLT_TAB ; BX := Offset of XLT_TAB ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Obtain coordinates of the top pixel for the last column of the current ;AN000;
; scan line: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; then, ;AN000;
MOV CUR_ROW,0 ; CUR_ROW := 0 ;AN000;
.ELSE ; else, ;AN000;
MOV CX,SCREEN_WIDTH ; CUR_COLUMN := SCREEN_WIDTH - 1 ;AN000;
DEC CX ; ;AN000;
MOV CUR_COLUMN,CX ; ;AN000;
.ENDIF ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; Read the scan line backwards "column" by "column" until a non-blank is found: ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV CX,SCAN_LINE_MAX_LENGTH ; CX := current length ;AN000;
; ;AN000;
;-------For each "column" ;AN000;
CHECK_1_COLUMN: ;AN000;
MOV SI,CUR_ROW ; Save coordinates of the column ;AN000;
MOV DI,CUR_COLUMN ; in SI, DI ;AN000;
XOR DL,DL ; DL := Number of pixels verified in ;AN000;
; one "column" ;AN000;
; ;AN000;
;-------For each pixel within that "column" ;AN000;
CHECK_1_PIXEL: ;AN000;
CALL READ_DOT ; AL := Index into translation table ;AN000;
XLAT XLT_TAB ; AL := Band mask or Intensity ;AN000;
;AN000;
;-------Check if pixel will map to an empty box: ;AN000;
.IF <DS:[BP].PRINTER_TYPE EQ BLACK_WHITE> ; If BLACK AND WHITE printer ;AN000;
.THEN ; then, check for intensity of white ;AN000;
CMP AL,WHITE_INT ; If curent pixel not blank ;AN000;
JNE DET_LENGTH_END ; THEN, LEAVE THE LOOP ;AN000;
.ELSE ; else, COLOR printer ;AN000;
OR AL,AL ; IF Band mask not blank ;AN000;
JNZ DET_LENGTH_END ; THEN, LEAVE THE LOOP ;AN000;
.ENDIF ;AN000;
;AN000;
;-------All pixels so far on this "column" are blank, get next pixel: ;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; ;AN000;
INC CUR_COLUMN ; then, increment column number ;AN000;
.ELSE ; ;AN000;
INC CUR_ROW ; else, increment row number ;AN000;
.ENDIF ; ;AN000;
INC DL ; One more pixel checked ;AN000;
CMP DL,NB_BOXES_PER_PRT_BUF ; All pixels for that column done ? ;AN000;
JL CHECK_1_PIXEL ; No, check next one. ;AN000;
;AN000;
;-------Nothing to print for this column, get next column ;AN000;
.IF <ROTATE_SW EQ ON> ; If printing sideways ;AN000;
.THEN ; then, ;AN000;
MOV CUR_COLUMN,DI ; Restore column number ;AN000;
INC CUR_ROW ; Get next row ;AN000;
.ELSE ; else, ;AN000;
MOV CUR_ROW,SI ; Restore row number ;AN000;
DEC CUR_COLUMN ; Get next column ;AN000;
.ENDIF ; ;AN000;
LOOP CHECK_1_COLUMN ; CX (length) := CX - 1 ;AN000;
;AN000;
DET_LENGTH_END: ;AN000;
MOV CUR_SCAN_LNE_LENGTH,CX ; Get current length ;AN000;
;AN000;
POP CUR_ROW ;AN000;
POP CUR_COLUMN ;AN000;
POP DI ;AN000;
POP SI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
DET_CUR_SCAN_LNE_LENGTH ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; SETUP_PRT : SET UP THE PRINTER FOR PRINTING IN GRAPHIC MODE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the SETUP escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_SETUP_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; SI := CUR_MODE_PTR.SETUP_ESC_PTR ;AN000;
; ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
SETUP_PRT PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
XOR CX,CX ; CX := Number of bytes to print ;AN000;
MOV CL,[BX].NUM_SETUP_ESC ; ;AN000;
.IF <CL G 0> ; If there is at least one ;AN000;
.THEN ; byte to be printed: ;AN000;
MOV BX,[BX].SETUP_ESC_PTR ; BX := Offset sequence to send ;AN000;
ADD BX,BP ;AN000;
;AN000;
SEND_1_SETUP_BYTE: ;AN000;
MOV AL,[BX] ; AL := byte to print ;AN000;
CALL PRINT_BYTE ; Send it to the printer ;AN000;
JC SETUP_PRT_END ; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP SEND_1_SETUP_BYTE ;AN000;
.ENDIF ;AN000;
SETUP_PRT_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
SETUP_PRT ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; RESTORE_PRT : RESTORE THE PRINTER TO ITS INITIAL STATUS ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_COLOR ;AN000;
; PRT_BW_APA ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the RESTORE escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_RESTORE_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; SI := CUR_MODE_PTR.RESTORE_ESC_PTR ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
RESTORE_PRT PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
XOR CX,CX ; CX := Number of bytes to print ;AN000;
MOV CL,[BX].NUM_RESTORE_ESC ;AN000;
.IF <CL G 0> ; If there is at least one ;AN000;
.THEN ; byte to be printed: ;AN000;
MOV BX,[BX].RESTORE_ESC_PTR ; BX := Offset sequence to send ;AN000;
ADD BX,BP ;AN000;
;AN000;
SEND_1_RESTORE_BYTE: ;AN000;
MOV AL,[BX] ; AL := byte to print ;AN000;
CALL PRINT_BYTE ; Send it to the printer ;AN000;
JC RESTORE_PRT_END ; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP SEND_1_RESTORE_BYTE ;AN000;
.ENDIF ;AN000;
RESTORE_PRT_END: ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
RESTORE_PRT ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; NEW_PRT_LINE : INITIALIZE THE PRINTER FOR A GRAPHIC LINE ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE_PTR = Offset of the DISPLAYMODE information ;AN000;
; record for the current mode ;AN000;
; CUR_SCAN_LNE_LENGTH = Number of bytes to send to the printer. ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ;AN000;
; CALLED BY: PRINT_BAND ;AN000;
; PRT_BW_APA ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Extract the GRAPHICS escape sequence from the DISPLAYMODE ;AN000;
; information record; Send this escape sequence to the printer. ;AN000;
; Then, send the number of bytes that will follow. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Number of bytes to print := CUR_MODE_PTR.NUM_GRAPHICS_ESC ;AN000;
; ;AN000;
; Get the escape sequence: ;AN000;
; Set up the 2 bytes containing the number of bytes to send in this sequence. ;AN000;
; SI := CUR_MODE_PTR.GRAPHICS_ESC_PTR ;AN000;
; ;AN000;
; FOR each byte to be printed ;AN000;
; PRINT_BYTE [SI] ; Send the byte to the printer ;AN000;
; INC SI ; Get the next byte ;AN000;
; ;AN000;
; Send the byte count ;AN000;
; ;AN000;
;AN000;
NEW_PRT_LINE PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH BX ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
PUSH DI ;AN000;
;AN000;
MOV BX,CUR_MODE_PTR ; BX := Displaymode info record. ;AN000;
;AN000;
;-------------------------------------------------------------------------------;AN000;
; Set up the 2 bytes containing the number of bytes to send in the GRAPHICS seq.;AN000;
; NOTE: number of bytes to send is "CUR_SCAN_LNE_LENGTH * BOX_W" ;AN000;
;-------------------------------------------------------------------------------;AN000;
MOV AL,BOX_W ; cur_scan_lne_length * ;AN000;
CBW ; printer box width = nb bytes to send;AN000;
MUL CUR_SCAN_LNE_LENGTH ; (result in DX AX) ;AN000;
; ;AN000;
;-------AX := Number of bytes to print ;AN000;
MOV DI,[BX].LOW_BYT_COUNT_PTR; DI := Offset of LOW byte of ;AN000;
ADD DI,BP ; byte count ;AN000;
MOV [DI],AL ; Store low byte ;AN000;
MOV DI,[BX].HGH_BYT_COUNT_PTR; DI := Offset of HIGH byte of ;AN000;
ADD DI,BP ; byte count ;AN000;
MOV [DI],AH ; Store high byte ;AN000;
;AN000;
;-------------------------------------------------------------------------------;AN000;
; Send the GRAPHICS escape sequence to the printer: ;AN000;
;-------------------------------------------------------------------------------;AN000;
XOR CX,CX ; CX := Length of the escape seq;AN000;
MOV CL,[BX].NUM_GRAPHICS_ESC ;AN000;
MOV BX,[BX].GRAPHICS_ESC_PTR ; BX := Offset sequence to send ;AN000;
ADD BX,BP ;AN000;
;AN000;
SEND_1_GRAPHICS_BYTE: ;AN000;
MOV AL,[BX] ; AL := byte to print ;AN000;
CALL PRINT_BYTE ; Send it to the printer ;AN000;
JC NEW_PRT_LINE_ENDP ; If printer error, quit the loop ;AN000;
INC BX ; Get next byte ;AN000;
LOOP SEND_1_GRAPHICS_BYTE ;AN000;
;AN000;
NEW_PRT_LINE_ENDP: ;AN000;
POP DI ;AN000;
POP DX ;AN000;
POP CX ;AN000;
POP BX ;AN000;
POP AX ;AN000;
RET ;AN000;
NEW_PRT_LINE ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; PRINT_BYTE : SEND A BYTE TO THE PRINTER AT LPT1 ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: AL = Byte to be printed ;AN000;
; ;AN000;
; OUTPUT: PRINTER ;AN000;
; ERROR_CODE = PRINTER_ERROR if an error is detected. ;AN000;
; Carry flag is set in case of error. ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
PRINT_BYTE PROC NEAR ;AN000;
PUSH AX ;AN000;
PUSH DX ;AN000;
;AN000;
MOV DX,0000 ; PRINTER NUMBER ;AN000;
MOV AH,00 ; REQUEST PRINT ;AN000;
INT 17H ; CALL BIOS : SEND THE CHARACTER ;AN000;
;AN000;
AND AH,00101001B ; Test error code returned in AH for ;AN000;
; "Out of paper", "I/O error" and "Time-out". ;AN000;
JNZ PRINT_BYTE_ERROR; Set the error code if error ;AN000;
JMP SHORT PRINT_BYTE_END ; else, return normally ;AN000;
PRINT_BYTE_ERROR: ;AN000;
MOV ERROR_CODE,PRINTER_ERROR ;AN000;
STC ; Set the carry flag to indicate ERROR ;AN000;
PRINT_BYTE_END: ;AN000;
POP DX ;AN000;
POP AX ;AN000;
RET ;AN000;
PRINT_BYTE ENDP ;AN000;
PAGE ;AN000;
;===============================================================================;AN000;
; ;AN000;
; READ_DOT: READ A PIXEL - RETURN A COLOR TRANSLATION TABLE INDEX ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; INPUT: CUR_MODE = Current video mode. ;AN000;
; CUR_ROW, ;AN000;
; CUR_COLUMN = Coordinates of the pixel to be read. ;AN000;
; CUR_PAGE = Active page number ;AN000;
; ;AN000;
; OUTPUT: AL = Index into COLOR TRANSLATION TABLE. ;AN000;
; ;AN000;
; DEPENDENCIES : COLOR TRANSLATION TABLE entries must be bytes ;AN000;
; ;AN000;
; ;AN000;
;-------------------------------------------------------------------------------;AN000;
; ;AN000;
; DESCRIPTION: Use VIDEO BIOS INTERRUPT 10H "READ DOT CALL". ;AN000;
; ;AN000;
; Depending on the video hardware, the dot returned by BIOS has ;AN000;
; different meanings. ;AN000;
; With an EGA it is an index into the Palette registers, ;AN000;
; With a CGA it is a number from 0 to 3, mapping to a specific color ;AN000;
; depending on the background color and the color palette currently ;AN000;
; selected. ;AN000;
; ;AN000;
; The Color Translation table has been set up to hold the correct color ;AN000;
; mapping for any "dot" in any mode. Therefore, the dot number returned ;AN000;
; by INT 10H can be used with any mode as a direct index within that ;AN000;
; table. ;AN000;
; ;AN000;
; With APA Monochrome mode 0FH there are 4 different dots: white, ;AN000;
; blinking white, high-intensity white, and black. ;AN000;
; ;AN000;
; For mode 0FH, the dot returned by interrupt 10 "read dot" call is a byte ;AN000;
; where only bits 0 and 2 are significant. These 2 bits must be appended ;AN000;
; together in order to obtain a binary number (from 0 to 3) that will be used ;AN000;
; as an index in the Color Translation table. ;AN000;
; ;AN000;
; For mode 11H, the dot is either 0 (for background color) or 7 (for the ;AN000;
; foreground color) only the LSB is returned. That is, we return either ;AN000;
; 0 or 1. ;AN000;
; ;AN000;
; LOGIC: ;AN000;
; ;AN000;
; Call VIDEO BIOS "READ DOT" ;AN000;
; IF CUR_MODE = 0FH ;AN000;
; THEN ;AN000;
; Append bits 1 and 3. ;AN000;
; IF CUR_MODE = 11H ;AN000;
; THEN ;AN000;
; Wipe out bits 1 and 2. ;AN000;
; ;AN000;
READ_DOT PROC NEAR ;AN000;
PUSH BX ; Save registers ;AN000;
PUSH CX ;AN000;
PUSH DX ;AN000;
;AN000;
MOV BH,CUR_PAGE ;AN000;
MOV DX,CUR_ROW ;AN000;
MOV CX,CUR_COLUMN ;AN000;
MOV AH,READ_DOT_CALL ;AN000;
INT 10H ; Call BIOS: AL <-- Dot read ;AN000;
;AN000;
CMP CUR_MODE,0FH ; Is it Mode 0fH ? ;AN000;
JNE MODE_11H? ; No, look for mode 11h. ;AN000;
;-------Mode 0Fh is the current mode: ;AN000;
;-------Convert bits 2 and 0 into a 2 bit number: ;AN000;
MOV BL,AL ; BL := AL = "Pixel read" ;AN000;
AND BL,00000100B ; Wipe off all bits but bit 2 in BL ;AN000;
AND AL,00000001B ; Wipe off all bits but bit 0 in AL ;AN000;
SHR BL,1 ; Move bit 2 to bit 1 in BL ;AN000;
OR AL,BL ; Append bit 1 and bit 0 ;AN000;
JMP SHORT READ_DOT_END ; Quit. ;AN000;
;AN000;
MODE_11H?: ;AN000;
CMP CUR_MODE,11H ; Is it Mode 0fH ? ;AN000;
JNE READ_DOT_END ; No, quit ;AN000;
;AN000;
;-------Mode 11H is the current mode: ;AN000;
AND AL,00000001B ; Keep only the Least significant bit ;AN000;
;AN000;
READ_DOT_END: ;AN000;
POP DX ; Restore registers ;AN000;
POP CX ;AN000;
POP BX ;AN000;
RET ;AN000;
READ_DOT ENDP ;AN000;
|