From: hcp@csx.cciw.ca (H.C. Pulley)
Subject: Re: CGA 160x100x16
Organization: Canada Centre for Inland Waters
Date: Sun, 13 Sep 1992 16:19:27 GMT

In article <1992Sep11.120323.16528@nuscc.nus.sg> isc30108@nusunix3.nus.sg (AMBAT SASI S/O PALISSERY P) writes:
>can some1 please post some code (c/asm/pas)
>describing how to arrive at this simulated "graphics"
>mode with 16 colors 160x100 resolution.
>thanks.
>
>sasi.
><last request posted expired>

Alright, but you asked for it!

Like I said before, it doesn't work properly.

Please don't give me any comments on my assembly style.  This was an 
experimental program only.

If you manage to get it to work properly, please send me the modified source.

This program simply goes into 160x100x16 mode (or tries to anyways) and draws
200 lines changing colors as it goes.

--- CUT HERE ---

; This program goes into text/graphics mode (160*100) in 16 colors
; It draws 200 lines and then exits
; By Harry C. Pulley, IV.  MAR92.

     .MODEL small

     .STACK 200h

     .DATA
Current_pos_x DW 159                    ; to hold current pixel x value
Current_pos_y DW 0                      ; to hold current pixel y value
Last_pos_x DW 0                         ; to hold last pixel x value
Last_pos_y DW 99                        ; to hold last pixel y value
Saved_video_mode DB ?                   ; to hold the old video mode for return to DOS
Set_video_mode DB 5                     ; new video mode=5
Plot_mode DB 0                          ; plot mode: pixel color
signed_rise DW ?                        ; signed rise
signed_run DW ?                         ; signed run
rise_sign DB ?                          ; rise + | -
run_sign DB ?                           ; run + | -
Hold_x DW ?                             ; starting x value
Hold_y DW ?                             ; starting y value

     .CODE
Start:                                  ; start of program
     mov ax,@data                       ; set up ds to point to .DATA segment
     mov ds,ax                          ; use ax since mov ds,@data is illegal

     mov ah,0fh                         ; video function to get video parameters
     int 10h                            ; video interrupt
     mov [Saved_video_mode],al          ; save video mode in variable for later

     sub al,al                          ; set al to zero
     mov dx,3d8h                        ; cga mode control register

     out dx,al                          ; disable display

     mov dx,3d4h

     out dx,al                          ; set CRTC reg 0

     mov al,83
     mov dx,3d5h

     out dx,al                          ; set horizontal total to 83

     mov al,1
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 1

     mov al,80
     mov dx,3d5h

     out dx,al                          ; set horizontal displayed to 80

     mov al,2
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 2

     mov al,81
     mov dx,3d5h

     out dx,al                          ; set horizontal sync to 81

     mov al,3
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 3

     mov al,1
     mov dx,3d5h

     out dx,al                          ; set horizontal sync width 1

     mov al,4
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 4

     mov al,107
     mov dx,3d5h

     out dx,al                          ; set vertical total to 107

     mov al,5
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 5

     sub al,al                          ; al=0
     mov dx,3d5h

     out dx,al                          ; set vertical adjust 0

     mov al,6
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 6

     mov al,107
     mov dx,3d5h

     out dx,al                          ; set vertical displayed 107

     mov al,7
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 7

     mov al,100
     mov dx,3d5h

     out dx,al                          ; set vertical sync 100

     mov al,8
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 8

     mov al,2
     mov dx,3d5h

     out dx,al                          ; set interlace 2

     mov al,9
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 9

     mov al,7
     mov dx,3d5h

     out dx,al                          ; set max scan 7

     mov al,10
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 10

     mov al,6
     mov dx,3d5h

     out dx,al                          ; set cursor start 6

     mov al,11
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 11

     mov al,7
     mov dx,3d5h

     out dx,al                          ; set cursor end 7

     mov al,12
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 12

     sub al,al
     mov dx,3d5h

     out dx,al                          ; set high start addr 0

     mov al,13
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 13

     sub al,al
     mov dx,3d5h

     out dx,al                          ; set low start addr 0

     mov al,14
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 14

     sub al,al
     mov dx,3d5h

     out dx,al                          ; set high end addr 0

     mov al,15
     mov dx,3d4h

     out dx,al                          ; set CRTC reg 15

     sub al,al
     mov dx,3d5h

     out dx,al                          ; set low end addr 0

     mov al,01000001b
     mov dx,3d8h

     out dx,al                          ; set psuedographics mode 160x100x16

     mov ax,0b800h
     mov es,ax                          ; set es to video memory

     cld

     mov ax,00deh                       ; set even bytes to deh character
     mov cx,8000                        ; 8000 words long
     mov di,0                           ; set di to offset of start of video buffer

     rep stosw                          ; fill video memory

     mov al,01001001b
     mov dx,3d8h

     out dx,al                          ; enable display

Mainloop:

     Call Plot_line

     dec [Current_pos_x]

     inc [Current_pos_y]

     inc [Last_pos_x]

     dec [Last_pos_y]                   ; adjust point values

     cmp [Last_pos_x],100
     jge OutofLoop

     inc [Plot_mode]
     and [Plot_mode],0fh                ; get Plot_mode%16

;    mov ax,10h
;    int 16h                            ; wait for key

     jmp Mainloop                       ; get next character/mouse action

OutofLoop:
     mov ah,0                           ; set video mode
     mov al,[Saved_video_mode]          ; restore video mode
     int 10h                            ; video interrupt

     mov ah,4ch                         ; DOS terminate program function
     int 21h                            ; DOS interrupt

; Procedure to plot a pixel using direct memory writes
; Input: Plot_mode, Current_pos_x, Current_pos_y
; Registers destroyed: ax,bx,cx,dx
; Output: none

Plot_pixel     PROC

     mov ax,[Current_pos_y]             ; set ax to current # of lines
     mov dx,80                          ; mul by 160
     mul dx                             ; get current pixel count in lines
     add ax,[Current_pos_x]             ; add x pos to count
     mov dx,ax
     and dx,1                           ; get odd bit of count
     and ax,0fffeh                      ; get even count
     inc ax                             ; make count odd bye

     mov bx,ax                          ; quotient is byte count in bx

     mov cl,2
     sal dl,cl                          ; multiply dl by 4 for correct shift
     add dl,4                           ; add 4 to dl to compensate for endianess
     mov cl,dl                          ; cl is the shift count, which is the bit count

     mov dl,[Plot_mode]                 ; make dl pixel color
     mov dh,0f0h                        ; prepare to erase

     ror dl,cl                          ; rotate the bit to the correct position in dl
     ror dh,cl                          ; rotate erasure window to correct pos

     and BYTE PTR es:[bx],dh            ; clear pixel

     or BYTE PTR es:[bx],dl             ; draw pixel
     ret

Plot_pixel     ENDP

; Procedure to plot a line from Last_pos_? to Current_pos_? using Plot_pixel
; Input: Last_pos_x,Last_pos_y,Current_pos_x,Current_pos_y
; Registers destroyed: ax,bx,cx,dx
; Output: none

Plot_line      PROC

     mov cx,[Current_pos_y]
     mov dx,[Current_pos_x]             ; put current pos in registers cx,dx

     mov ax,cx
     sub ax,[Last_pos_y]
     mov [signed_rise],ax               ; get signed rise

     mov ax,dx
     sub ax,[Last_pos_x]
     mov [signed_run],ax                ; get signed run

     mov ax,[Last_pos_y]
     push ax
     mov ax,[Last_pos_x]
     push ax                            ; preserve last x,y

     cmp cx,[Last_pos_y]                ; we want a positive rise
     jl Last_y_bigger
     mov [rise_sign],1                  ; remember rise sign +
     jmp Do_run

Last_y_bigger:
     xchg cx,[Last_pos_y]               ; swap current y and last y
     mov [rise_sign],-1                 ; remember rise sign -

Do_run:
     sub cx,[Last_pos_y]                ; get +rise

     cmp dx,[Last_pos_x]                ; want a pos rise
     jl Last_x_bigger
     mov [run_sign],1                   ; remember run sign +
     jmp Do_line

Last_x_bigger:
     xchg dx,[Last_pos_x]               ; swap current x and last x
     mov [run_sign],-1                  ; remember run sign -

Do_line:
     sub dx,[Last_pos_x]                ; want pos run

     pop ax
     mov [Last_pos_x],ax
     pop ax
     mov [Last_pos_y],ax                ; restore last x,y

     mov ax,cx
     add ax,dx
     cmp ax,0                           ; if cx==dx==0 no draw needed
     jne Continue
     ret

Continue:
     mov ax,[Current_pos_y]
     push ax
     mov ax,[Current_pos_x]
     push ax                            ; preserve current position x & y

     cmp cx,dx                          ; compare rise to run
     jg Skip
     jmp Run_bigger                     ; ignore = case, doesn't matter y | x if equal

Skip:
     cmp [rise_sign],1
     je Start_last                      ; determine starting point, last or current
     jmp Start_next
Start_last:
     mov ax,[Last_pos_y]
     mov [Current_pos_y],ax             ; set last y to start
     mov ax,[Last_pos_x]
     mov [Current_pos_x],ax             ; set last x to start
Start_next:
     mov ax,[Current_pos_y]
     mov [Hold_y],ax                    ; keep start y

Rise_loop:
     mov ax,[Current_pos_y]
     sub ax,[Hold_y]                    ; ax=delta y
     mov bx,[signed_run]
     imul bx                            ; mul y*run
     mov bx,[signed_rise]
     idiv bx                            ; div (y*run)/rise

     add ax,[Current_pos_x]             ; add ((y*run)/rise)+b

     xchg ax,[Current_pos_x]            ; save x

     push ax                            ; preserve ax for Current_pos_x
     push cx                            ; preserve cx for Loop counter

     call Plot_pixel

     pop cx                             ; restore cx
     pop ax                             ; restore ax

     mov [Current_pos_x],ax             ; restore x

     inc [Current_pos_y]                ; go to next y pos

     loop Rise_loop                     ; do next y pos

     jmp Restore                        ; exit procedure

Run_bigger:

     mov cx,dx                          ; put run into counter

     cmp [run_sign],1
     je Start_lst                       ; determine starting point, last or current
     jmp Start_nxt
Start_lst:
     mov ax,[Last_pos_y]
     mov [Current_pos_y],ax             ; set last y to start
     mov ax,[Last_pos_x]
     mov [Current_pos_x],ax             ; set last x to start
Start_nxt:
     mov ax,[Current_pos_x]
     mov [Hold_x],ax                    ; keep starting x value

Run_loop:
     mov ax,[Current_pos_x]
     sub ax,[Hold_x]                    ; ax=delta x
     mov bx,[signed_rise]
     imul bx                            ; mul x*rise
     mov bx,[signed_run]
     idiv bx                            ; div (x*rise)/run

     add ax,[Current_pos_y]             ; add ((x*rise)/run)+b

     xchg ax,[Current_pos_y]            ; save y

     push ax                            ; preserve ax for Current_pos_y
     push cx                            ; preserve cx for Loop counter

     call Plot_pixel

     pop cx                             ; restore cx
     pop ax                             ; restore ax

     mov [Current_pos_y],ax             ; restore y

     inc [Current_pos_x]                ; go to next x pos

     loop Run_loop                      ; do next x pos

     jmp Restore

Restore:
     pop ax
     mov [Current_pos_x],ax             ; restore x
     pop ax
     mov [Current_pos_y],ax             ; restore y

     ret

Plot_single:
     call Plot_pixel

     ret
Plot_line      ENDP

     END Start

--- CUT HERE ---

Harry

-- 
          hcp@csx.cciw.ca           | This message    | It takes all kinds,
    hcpiv@grumpy.cis.uoguelph.ca    | released to the | and to each his own.
------------------------------------| PUBLIC DOMAIN.  | This thought in mind,
 Stay away from the DOS side, Luke! |                 | I walk alone.
Newsgroups: comp.sys.ibm.pc.hardware