;****************************************************************************
;*
;* The SuperVGA Kit - UniVBE Software Development Kit
;*
;* Copyright (C) 1996 SciTech Software
;* All rights reserved.
;*
;* Filename: $Workfile: _linsdk.asm $
;* Version: $Revision: 1.7 $
;*
;* Language: 80386 Assembler
;* Environment: IBM PC 32 bit Protected Mode.
;*
;* Description: Assembly language support routines for the SuperVGA Kit
;* UniVBE Software Development Kit. This module contains the
;* 32 bit linear frame buffer drawing routines.
;*
;* Note that even though this code is 32 bit protected mode,
;* it can be called directly from 16 bit protected mode code
;* using a 16 bit far pointer with the selector set to a USE32
;* code segment (which the code in this segment is). To convert
;* the CS selector to a proper 32 bit selector, call the
;* function _linksdk_enable32() before calling any functions
;* in this segment. You only need to call this routine once
;* for the entire execution of the program (but you may call it
;* more than once - it will simply return if the selector is
;* already 32 bit).
;*
;* $Date: 22 Jun 1996 17:01:22 $ $Author: KendallB $
;*
;****************************************************************************
IDEAL
include "model.mac" ; Memory model macros
include "vbeaf.inc" ; VBE/AF Accelerator Functions
include "svga.inc" ; SuperVGA Kit structures
if pmode
header _linsdk
CRTC EQU 3D4h ; Port of CRTC registers
begdataseg _linsdk
DC EQU __SV_devCtx ; Macro to access global structure
$EXTRN __SV_devCtx,SV_devCtx_s
$EXTRN __SV_pagesize,ULONG
$EXTRN __SV_bankShift,UINT
$EXTRN __SV_setBankRM,DPTR
$EXTRN __SV_setBankPtr,DPTR
enddataseg _linsdk
begcodeseg32 _linsdk
; Define the _linksdk_enable32 function to convert the CS selector to 32 bit.
define_enable32 _linsdk
; Macro to load the linear framebuffer video memory selector into the ES
; register for 16 bit Windows code.
MACRO load_es_videoSel
ife flatmodel
mov es,[(WORD DC.videoMem)+2]; ES := linear framebuffer selector
endif
ENDM
;----------------------------------------------------------------------------
; PixelAddr256 Determine buffer address of pixel in _linsdk 256 color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: EBX - byte offset in buffer
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr256 near
push edx
clrhi16 ax ; EAX := y
clrhi16 bx ; EBX := x
mul [DC.bytesperline] ; EAX := y * bytesperline
add ebx,eax ; EBX := y * BytesPerLine + x
add ebx,[DC.originOffset]
pop edx
ret
ENDP PixelAddr256
;----------------------------------------------------------------------------
; PixelAddr32k Determine buffer address of pixel in _linsdk 32k color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: EBX - byte offset in buffer
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr32k near
push edx
clrhi16 ax ; EAX := y
clrhi16 bx ; EBX := x
mul [DC.bytesperline] ; EAX := y * bytesperline
shl ebx,1
add ebx,eax ; EBX := y * BytesPerLinef + x * 2
add ebx,[DC.originOffset]
pop edx
ret
ENDP PixelAddr32k
;----------------------------------------------------------------------------
; PixelAddr16m Determine buffer address of pixel in _linsdk 16m color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: EBX - byte offset in buffer
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr16m near
push edx
clrhi16 ax ; EAX := y
clrhi16 bx ; EBX := x
mul [DC.bytesperline] ; EAX := y * bytesperline
add eax,ebx
shl ebx,1
add ebx,eax ; EBX := y * BytesPerLine + x * 3
add ebx,[DC.originOffset]
pop edx
ret
ENDP PixelAddr16m
;----------------------------------------------------------------------------
; PixelAddr4G Determine buffer address of pixel in _linsdk 32k color modes
;----------------------------------------------------------------------------
;
; Entry: _AX - y-coordinate
; _BX - x-coordinate
;
; Exit: EBX - byte offset in buffer
;
; Registers: None.
;
;----------------------------------------------------------------------------
PROC PixelAddr4G near
push edx
clrhi16 ax ; EAX := y
clrhi16 bx ; EBX := x
mul [DC.bytesperline] ; EAX := y * bytesperline
shl ebx,2
add ebx,eax ; EBX := y * BytesPerLine + x * 2
add ebx,[DC.originOffset]
pop edx
ret
ENDP PixelAddr4G
;----------------------------------------------------------------------------
; clearLinear - Clears the linear framebuffer page
;----------------------------------------------------------------------------
; Entry: EAX - Value to clear buffer with
;
; Registers: All.
;----------------------------------------------------------------------------
PROC clearLinear
load_es_videoSel
push eax
mov _ax,[DC.maxy]
clrhi16 ax ; EAX := maxy
inc eax
mul [DC.bytesperline] ; EAX := number of bytes to fill
mov ecx,eax ; ECX := bytes in last bank to fill
mov edi,[DC.originOffset] ; EDI -> start of video memory
cld ; Moves go up in memory
pop eax
shr ecx,2 ; ECX := number of double USHORTs to set
rep stosd
ret
ENDP clearLinear
;----------------------------------------------------------------------------
; void clear256Lin(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart32 __SV_clear256Lin
ARG color:ULONG
enter_c 0
xor eax,eax
mov al,[BYTE color]
mov ebx,eax
shl ebx,8
or eax,ebx
mov ebx,eax
shl ebx,16
or eax,ebx ; EAX = 32 bit color value
call clearLinear
leave_c_nolocal
ret32
procend __SV_clear256Lin
;----------------------------------------------------------------------------
; void clear32kLin(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart32 __SV_clear32kLin
ARG color:ULONG
enter_c 0
xor eax,eax
mov ax,[WORD color]
mov ebx,eax
shl ebx,16
or eax,ebx ; EAX = 32 bit color value
call clearLinear
leave_c_nolocal
ret32
procend __SV_clear32kLin
;----------------------------------------------------------------------------
; void clear16mLin(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart32 __SV_clear16mLin
ARG color:ULONG
enter_c 0
mov eax,[color]
or eax,eax
jnz @@SlowClear
call clearLinear ; Clear the video memory page to black
jmp @@Exit
@@SlowClear:
load_es_videoSel
mov ebx,[DC.originOffset] ; ES:EBX -> start of video memory
mov _di,[DC.maxx]
clrhi16 di
inc edi ; EDI := number of pixels to draw
mov _si,[DC.maxy]
clrhi16 si
inc esi ; ESI := number of lines to process
mov ax,[WORD color] ; AX := pixel color
mov dh,[BYTE color+2] ; DH := top byte of pixel color
mov ebp,edi
shl ebp,1
add ebp,edi ; EBP := bytes per physical scanline
sub ebp,[DC.bytesperline]
neg ebp ; EBP := scanline adjust factor
@@NextScanLine:
mov ecx,edi
@@LoopSolid:
mov [BYTE _ES ebx],al ; Set pixel value in buffer
mov [BYTE _ES ebx+1],ah
mov [BYTE _ES ebx+2],dh
add ebx,3 ; Increment to next pixel
loop @@LoopSolid ; Loop across line
@@AfterPlot:
add ebx,ebp
dec esi
jnz @@NextScanLine
@@Exit: leave_c_nolocal
ret32
procend __SV_clear16mLin
;----------------------------------------------------------------------------
; void clear4GLin(long color)
;----------------------------------------------------------------------------
; Routine to clear the screen. Assumes pages begin on bank boundaries
; for simplicity of coding.
;----------------------------------------------------------------------------
procstart32 __SV_clear4GLin
ARG color:ULONG
enter_c 0
mov eax,[color]
call clearLinear
leave_c_nolocal
ret32
procend __SV_clear4GLin
;----------------------------------------------------------------------------
; void putPixel256Lin(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart32 __SV_putPixel256Lin
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
load_es_videoSel
mov _ax,[y]
mov _bx,[x]
clrhi16 ax ; EAX := y * BytesPerLine
clrhi16 bx ; EBX := x
mul [DC.bytesperline]
add ebx,[DC.originOffset]
add ebx,eax ; EBX := y * BytesPerLine + x
mov al,[BYTE color]
mov [_ES ebx],al ; Replace the pixel
leave_c_nolocal
ret32
procend __SV_putPixel256Lin
;----------------------------------------------------------------------------
; void putPixel32kLin(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart32 __SV_putPixel32kLin
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
load_es_videoSel
mov _ax,[y]
mov _bx,[x]
clrhi16 ax ; EAX := y * BytesPerLine
clrhi16 bx ; EBX := x
mul [DC.bytesperline]
shl ebx,1
add ebx,[DC.originOffset]
add ebx,eax ; EBX := y * BytesPerLine + x
mov ax,[WORD color]
mov [_ES ebx],ax ; Replace the pixel
leave_c_nolocal
ret32
procend __SV_putPixel32kLin
;----------------------------------------------------------------------------
; void putPixel16mLin(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart32 __SV_putPixel16mLin
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
load_es_videoSel
mov _ax,[y]
mov _bx,[x]
clrhi16 ax ; EAX := y * BytesPerLine
clrhi16 bx ; EBX := x
mul [DC.bytesperline]
add eax,ebx
shl ebx,1
add eax,ebx
add eax,[DC.originOffset]
mov ebx,eax ; EBX := y * BytesPerLine + x * 3
mov eax,[color]
mov [_ES ebx],al ; Replace the first byte
mov [_ES ebx+1],ah
shr eax,16
mov [_ES ebx+2],al
@@Exit: leave_c_nolocal
ret32
procend __SV_putPixel16mLin
;----------------------------------------------------------------------------
; void putPixel4GLin(int x,int y,long color)
;----------------------------------------------------------------------------
; Routine sets the value of a pixel in native VGA graphics modes.
;
; Entry: x - X coordinate of pixel to draw
; y - Y coordinate of pixel to draw
; color - Color of pixel to draw
;
;----------------------------------------------------------------------------
procstart32 __SV_putPixel4GLin
ARG x:UINT, y:UINT, color:ULONG
enter_c 0
load_es_videoSel
mov _ax,[y]
mov _bx,[x]
clrhi16 ax ; EAX := y * BytesPerLine
clrhi16 bx ; EBX := x
mul [DC.bytesperline]
shl ebx,2
add ebx,[DC.originOffset]
add ebx,eax ; EBX := y * BytesPerLine + x
mov eax,[color]
mov [_ES ebx],eax ; Replace the pixel
leave_c_nolocal
ret32
procend __SV_putPixel4GLin
;----------------------------------------------------------------------------
; void _SV_line256Lin(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart32 __SV_line256Lin
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL LoSlope:USHORT, VertInc:ULONG, EIncr:ULONG, \
NEIncr:ULONG = LocalSize
enter_c LocalSize
mov esi,[DC.bytesperline] ; ESI = Increment for video buffer
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg esi ; negative increment for buffer
; select appropriate routine for slope of line
@@Y2Greater:
clrhi16 ax ; EAX := dx
clrhi16 bx ; EBX := dy
mov [VertInc],esi ; save increment
mov [LoSlope],1
cmp ebx,eax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [LoSlope],0
xchg ebx,eax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl ebx,1 ; _BX := 2 * dy
mov [EIncr],ebx ; EIncr := 2 * dy
sub ebx,eax ; d = 2 * dy - dx
mov edi,ebx ; EDI := initial decision variable
sub ebx,eax
mov [NEIncr],ebx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push eax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr256 ; EBX -> buffer
load_es_videoSel
pop ecx ; Restore dx
inc ecx ; CX := # pixels to draw
test [LoSlope],1
jz @@HiSlopeLine ; This is a high slope line
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; ES:EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov al,[BYTE color] ; AL := pixel value to fill
@@LoopLo:
mov [_ES ebx],al ; Set pixel value in buffer
inc ebx ; Increment x coordinate
or edi,edi ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add edi,[NEIncr] ; d := d + NEIncr
add ebx,[VertInc] ; increment y
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; ES:EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov al,[BYTE color] ; AL := pixel value to fill
@@LoopHi:
mov [_ES ebx],al ; Set pixel value in buffer
add ebx,[VertInc] ; increment y
or edi,edi ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add edi,[NEIncr] ; d := d + NEIncr
inc ebx ; Increment x
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
leave_c
ret32
procend __SV_line256Lin
;----------------------------------------------------------------------------
; void _SV_line32kLin(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart32 __SV_line32kLin
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL LoSlope:ULONG, VertInc:ULONG, EIncr:ULONG, \
NEIncr:ULONG = LocalSize
enter_c LocalSize
cld
mov esi,[DC.bytesperline] ; ESI = Increment for video buffer
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg esi ; negative increment for buffer
; select appropriate routine for slope of line
@@Y2Greater:
clrhi16 ax ; EAX := dx
clrhi16 bx ; EBX := dy
mov [VertInc],esi ; save increment
mov [LoSlope],1
cmp ebx,eax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [LoSlope],0
xchg ebx,eax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl ebx,1 ; EBX := 2 * dy
mov [EIncr],ebx ; EIncr := 2 * dy
sub ebx,eax ; d = 2 * dy - dx
mov edi,ebx ; EDI := initial decision variable
sub ebx,eax
mov [NEIncr],ebx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push eax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr32k ; EBX -> buffer
load_es_videoSel
pop ecx ; Restore dx
inc ecx ; ECX := # pixels to draw
test [LoSlope],1
jz @@HiSlopeLine ; This is a high slope line
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov ax,[USHORT color] ; AX := pixel value to fill
@@LoopLo:
mov [_ES ebx],ax ; Set pixel value in buffer
inc ebx ; Increment x coordinate
inc ebx
or edi,edi ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add edi,[NEIncr] ; d := d + NEIncr
add ebx,[VertInc] ; increment y
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov ax,[USHORT color] ; AL := pixel value to fill
@@LoopHi:
mov [_ES ebx],ax ; Set pixel value in buffer
add ebx,[VertInc] ; increment y
or edi,edi ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add edi,[NEIncr] ; d := d + NEIncr
inc ebx
inc ebx ; Increment x
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
leave_c
ret32
procend __SV_line32kLin
;----------------------------------------------------------------------------
; void _SV_line16mLin(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart32 __SV_line16mLin
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL LoSlope:ULONG, VertInc:ULONG, EIncr:ULONG, \
NEIncr:ULONG = LocalSize
enter_c LocalSize
cld
mov esi,[DC.bytesperline] ; ESI = Increment for video buffer
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg esi ; negative increment for buffer
; select appropriate routine for slope of line
@@Y2Greater:
clrhi16 ax ; EAX := dx
clrhi16 bx ; EBX := dy
mov [VertInc],esi ; save increment
mov [LoSlope],1
cmp ebx,eax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [LoSlope],0
xchg ebx,eax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl ebx,1 ; _BX := 2 * dy
mov [EIncr],ebx ; EIncr := 2 * dy
sub ebx,eax ; d = 2 * dy - dx
mov edi,ebx ; EDI := initial decision variable
sub ebx,eax
mov [NEIncr],ebx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push eax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr16m ; EBX -> buffer
load_es_videoSel
pop ecx ; Restore dx
inc ecx ; ECX := # pixels to draw
test [LoSlope],1
jz @@HiSlopeLine ; This is a high slope line
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov ax,[USHORT color] ; AX := pixel value to fill
mov dh,[BYTE color+2] ; DH := top byte of pixel value
@@LoopLo:
mov [_ES ebx],al ; Set pixel value in buffer
mov [_ES ebx+1],ah ; Set pixel value in buffer
mov [_ES ebx+2],dh
inc ebx
inc ebx
inc ebx ; Increment x coordinate
@@DonePixelLo:
or edi,edi ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add edi,[NEIncr] ; d := d + NEIncr
add ebx,[VertInc] ; increment y
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov ax,[USHORT color] ; AL := pixel value to fill
mov dh,[BYTE color+2] ; DH := current bank number
@@LoopHi:
mov [_ES ebx],al ; Set pixel value in buffer
mov [_ES ebx+1],ah ; Set pixel value in buffer
mov [_ES ebx+2],dh
@@DonePixelHi:
add ebx,[VertInc] ; increment y
or edi,edi ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add edi,[NEIncr] ; d := d + NEIncr
inc ebx
inc ebx
inc ebx ; Increment x coordinate
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
leave_c
ret32
procend __SV_line16mLin
;----------------------------------------------------------------------------
; void _SV_line4GLin(int x1,int y1,int x2,int y2, long color)
;----------------------------------------------------------------------------
; Routine draws a line in native VGA graphics modes.
;
; Differentiates between horizontal, vertical and sloping lines. Horizontal
; and vertical lines are special cases and can be drawn extremely quickly.
; The sloping lines are drawn using the Midpoint line algorithm.
;
; Entry: x1 - X1 coordinate of line to draw
; y1 - Y1 coordinate of line to draw
; x2 - X2 coordinate of line to draw
; y2 - Y2 coordinate of line to draw
; color - color to draw the line in
;
;----------------------------------------------------------------------------
procstart32 __SV_line4GLin
ARG x1:UINT, y1:UINT, x2:UINT, y2:UINT, color:ULONG
LOCAL LoSlope:ULONG, VertInc:ULONG, EIncr:ULONG, \
NEIncr:ULONG = LocalSize
enter_c LocalSize
push eax
cld
mov esi,[DC.bytesperline] ; ESI = Increment for video buffer
mov _ax,[x2]
sub _ax,[x1] ; _AX := X2 - X1
; Force X1 < X2
jns @@X2Greater ; Jump if X2 > X1
neg _ax ; _AX := X1 - X2
mov _bx,[x2] ; Exchange X1 and X2
xchg _bx,[x1]
mov [x2],_bx
mov _bx,[y2] ; Exchange Y1 and Y2
xchg _bx,[y1]
mov [y2],_bx
; calcluate dy = ABS(Y2-Y1)
@@X2Greater:
mov _bx,[y2]
sub _bx,[y1] ; _BX := Y2 - Y1
jns @@Y2Greater ; Jump if slope is positive
neg _bx ; _BX := Y1 - Y2
neg esi ; negative increment for buffer
; select appropriate routine for slope of line
@@Y2Greater:
clrhi16 ax ; EAX := dx
clrhi16 bx ; EBX := dy
mov [VertInc],esi ; save increment
mov [LoSlope],1
cmp ebx,eax
jle @@LoSlope ; Jump if dy <= dx (Slope <= 1)
mov [LoSlope],0
xchg ebx,eax ; exchange dy and dx
; calculate initial decision variable and increments
@@LoSlope:
shl ebx,1 ; _BX := 2 * dy
mov [EIncr],ebx ; EIncr := 2 * dy
sub ebx,eax ; d = 2 * dy - dx
mov edi,ebx ; EDI := initial decision variable
sub ebx,eax
mov [NEIncr],ebx ; NEIncr := 2 * (dy - dx)
; calculate first pixel address
push eax ; preserve dx
mov _ax,[y1]
mov _bx,[x1]
call PixelAddr4G ; EBX -> buffer
load_es_videoSel
pop ecx ; Restore dx
inc ecx ; ECX := # pixels to draw
test [LoSlope],1
jz @@HiSlopeLine ; This is a high slope line
;****************************************************************************
;
; Routine for dy <= dx (slope <= 1)
; ES:EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@LoSlopeLine:
mov eax,[color] ; EAX := pixel value to fill
@@LoopLo:
mov [_ES ebx],eax ; Set pixel value in buffer
inc ebx
inc ebx
inc ebx
inc ebx ; Increment x coordinate
or edi,edi ; Test sign of d
jns @@LoPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@LoPosDi:
add edi,[NEIncr] ; d := d + NEIncr
add ebx,[VertInc] ; increment y
loop @@LoopLo ; Loop for remaining pixels
jmp @@Exit ; We are all done
;****************************************************************************
;
; Routine for dy > dx (slope > 1)
; EBX -> video buffer
; ECX = # pixels to draw
; EDI = decision variable
; EIncr - East pixel increment
; NEIncr - North East pixel increment
;
;****************************************************************************
@@HiSlopeLine:
mov eax,[color] ; EAX := pixel value to fill
@@LoopHi:
mov [_ES ebx],eax ; Set pixel value in buffer
add ebx,[VertInc] ; increment y
or edi,edi ; Test sign of d
jns @@HiPosDi ; Jump if d >= 0
add edi,[EIncr] ; d := d + EIncr
loop @@LoopHi ; Loop for remaining pixels
jmp @@Exit ; We are all done
@@HiPosDi:
add edi,[NEIncr] ; d := d + NEIncr
inc ebx
inc ebx
inc ebx
inc ebx ; Increment x coordinate
loop @@LoopHi ; Loop for remaining pixels
@@Exit:
pop eax
leave_c
ret32
procend __SV_line4GLin
;----------------------------------------------------------------------------
; void _SV_setActivePageLin(int which)
;----------------------------------------------------------------------------
; Routine to set the video page for active output.
;
; Entry: page - Page number of page to use
;
;----------------------------------------------------------------------------
procstart32 __SV_setActivePageLin
ARG which:UINT
enter_c 0
; Calculate 18 bit address of page in video memory. Note that it is in this
; routine that we add the offset to the linear framebuffer into the
; DC.originOffset variable, to remove the need to load it at runtime.
mov _ax,[which] ; _AX := page number
clrhi16 ax ; EAX := page number
mul [__SV_pagesize] ; EDX:EAX := result
if flatmodel
add eax,[DC.videoMem]
endif
mov [DC.originOffset],eax ; Save video buffer offset
leave_c_nolocal
ret32
procend __SV_setActivePageLin
endcodeseg32 _linsdk
endif
END