| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- ;
- ; Command & Conquer Red Alert(tm)
- ; Copyright 2025 Electronic Arts Inc.
- ;
- ; This program is free software: you can redistribute it and/or modify
- ; it under the terms of the GNU General Public License as published by
- ; the Free Software Foundation, either version 3 of the License, or
- ; (at your option) any later version.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;
- ;***************************************************************************
- ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
- ;***************************************************************************
- ;* *
- ;* Project Name : Westwood 32 bit Library *
- ;* *
- ;* File Name : DRAWLINE.ASM *
- ;* *
- ;* Programmer : Phil W. Gorrow *
- ;* *
- ;* Start Date : June 16, 1994 *
- ;* *
- ;* Last Update : August 30, 1994 [IML] *
- ;* *
- ;*-------------------------------------------------------------------------*
- ;* Functions: *
- ;* VVC::Scale -- Scales a virtual viewport to another virtual viewport *
- ;* Normal_Draw -- jump loc for drawing scaled line of normal pixel *
- ;* __DRAW_LINE -- Assembly routine to draw a line *
- ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *
- IDEAL
- P386
- MODEL USE32 FLAT
- INCLUDE ".\drawbuff.inc"
- INCLUDE ".\gbuffer.inc"
- CODESEG
- ;***************************************************************************
- ;* VVC::DRAW_LINE -- Scales a virtual viewport to another virtual viewport *
- ;* *
- ;* INPUT: WORD sx_pixel - the starting x pixel position *
- ;* WORD sy_pixel - the starting y pixel position *
- ;* WORD dx_pixel - the destination x pixel position *
- ;* WORD dy_pixel - the destination y pixel position *
- ;* WORD color - the color of the line to draw *
- ;* *
- ;* Bounds Checking: Compares sx_pixel, sy_pixel, dx_pixel and dy_pixel *
- ;* with the graphic viewport it has been assigned to. *
- ;* *
- ;* HISTORY: *
- ;* 06/16/1994 PWG : Created. *
- ;* 08/30/1994 IML : Fixed clipping bug. *
- ;*=========================================================================*
- PROC Buffer_Draw_Line C NEAR
- USES eax,ebx,ecx,edx,esi,edi
- ;*==================================================================
- ;* Define the arguements that the function takes.
- ;*==================================================================
- ARG this_object:DWORD ; associated graphic view port
- ARG x1_pixel:DWORD ; the start x pixel position
- ARG y1_pixel:DWORD ; the start y pixel position
- ARG x2_pixel:DWORD ; the dest x pixel position
- ARG y2_pixel:DWORD ; the dest y pixel position
- ARG color:DWORD ; the color we are drawing
- ;*==================================================================
- ;* Define the local variables that we will use on the stack
- ;*==================================================================
- LOCAL clip_min_x:DWORD
- LOCAL clip_max_x:DWORD
- LOCAL clip_min_y:DWORD
- LOCAL clip_max_y:DWORD
- LOCAL clip_var:DWORD
- LOCAL accum:DWORD
- LOCAL bpr:DWORD
- ;*==================================================================
- ;* Take care of find the clip minimum and maximums
- ;*==================================================================
- mov ebx,[this_object]
- xor eax,eax
- mov [clip_min_x],eax
- mov [clip_min_y],eax
- mov eax,[(GraphicViewPort ebx).GVPWidth]
- mov [clip_max_x],eax
- add eax,[(GraphicViewPort ebx).GVPXAdd]
- add eax,[(GraphicViewPort ebx).GVPPitch]
- mov [bpr],eax
- mov eax,[(GraphicViewPort ebx).GVPHeight]
- mov [clip_max_y],eax
- ;*==================================================================
- ;* Adjust max pixels as they are tested inclusively.
- ;*==================================================================
- dec [clip_max_x]
- dec [clip_max_y]
- ;*==================================================================
- ;* Set the registers with the data for drawing the line
- ;*==================================================================
- mov eax,[x1_pixel] ; eax = start x pixel position
- mov ebx,[y1_pixel] ; ebx = start y pixel position
- mov ecx,[x2_pixel] ; ecx = dest x pixel position
- mov edx,[y2_pixel] ; edx = dest y pixel position
- ;*==================================================================
- ;* This is the section that "pushes" the line into bounds.
- ;* I have marked the section with PORTABLE start and end to signify
- ;* how much of this routine is 100% portable between graphics modes.
- ;* It was just as easy to have variables as it would be for constants
- ;* so the global vars ClipMaxX,ClipMinY,ClipMaxX,ClipMinY are used
- ;* to clip the line (default is the screen)
- ;* PORTABLE start
- ;*==================================================================
- cmp eax,[clip_min_x]
- jl short ??clip_it
- cmp eax,[clip_max_x]
- jg short ??clip_it
- cmp ebx,[clip_min_y]
- jl short ??clip_it
- cmp ebx,[clip_max_y]
- jg short ??clip_it
- cmp ecx,[clip_min_x]
- jl short ??clip_it
- cmp ecx,[clip_max_x]
- jg short ??clip_it
- cmp edx,[clip_min_y]
- jl short ??clip_it
- cmp edx,[clip_max_y]
- jle short ??on_screen
- ;*==================================================================
- ;* Takes care off clipping the line.
- ;*==================================================================
- ??clip_it:
- call NEAR PTR ??set_bits
- xchg eax,ecx
- xchg ebx,edx
- mov edi,esi
- call NEAR PTR ??set_bits
- mov [clip_var],edi
- or [clip_var],esi
- jz short ??on_screen
- test edi,esi
- jne short ??off_screen
- shl esi,2
- call [DWORD PTR cs:??clip_tbl+esi]
- jc ??clip_it
- xchg eax,ecx
- xchg ebx,edx
- shl edi,2
- call [DWORD PTR cs:??clip_tbl+edi]
- jmp ??clip_it
- ??on_screen:
- jmp ??draw_it
- ??off_screen:
- jmp ??out
- ;*==================================================================
- ;* Jump table for clipping conditions
- ;*==================================================================
- ??clip_tbl DD ??nada,??a_up,??a_dwn,??nada
- DD ??a_lft,??a_lft,??a_dwn,??nada
- DD ??a_rgt,??a_up,??a_rgt,??nada
- DD ??nada,??nada,??nada,??nada
- ??nada:
- clc
- retn
- ??a_up:
- mov esi,[clip_min_y]
- call NEAR PTR ??clip_vert
- stc
- retn
- ??a_dwn:
- mov esi,[clip_max_y]
- neg esi
- neg ebx
- neg edx
- call NEAR PTR ??clip_vert
- neg ebx
- neg edx
- stc
- retn
- ;*==================================================================
- ;* xa'=xa+[(miny-ya)(xb-xa)/(yb-ya)]
- ;*==================================================================
- ??clip_vert:
- push edx
- push eax
- mov [clip_var],edx ; clip_var = yb
- sub [clip_var],ebx ; clip_var = (yb-ya)
- neg eax ; eax=-xa
- add eax,ecx ; (ebx-xa)
- mov edx,esi ; edx=miny
- sub edx,ebx ; edx=(miny-ya)
- imul edx
- idiv [clip_var]
- pop edx
- add eax,edx
- pop edx
- mov ebx,esi
- retn
- ??a_lft:
- mov esi,[clip_min_x]
- call NEAR PTR ??clip_horiz
- stc
- retn
- ??a_rgt:
- mov esi,[clip_max_x]
- neg eax
- neg ecx
- neg esi
- call NEAR PTR ??clip_horiz
- neg eax
- neg ecx
- stc
- retn
- ;*==================================================================
- ;* ya'=ya+[(minx-xa)(yb-ya)/(xb-xa)]
- ;*==================================================================
- ??clip_horiz:
- push edx
- mov [clip_var],ecx ; clip_var = xb
- sub [clip_var],eax ; clip_var = (xb-xa)
- sub edx,ebx ; edx = (yb-ya)
- neg eax ; eax = -xa
- add eax,esi ; eax = (minx-xa)
- imul edx ; eax = (minx-xa)(yb-ya)
- idiv [clip_var] ; eax = (minx-xa)(yb-ya)/(xb-xa)
- add ebx,eax ; ebx = xa+[(minx-xa)(yb-ya)/(xb-xa)]
- pop edx
- mov eax,esi
- retn
- ;*==================================================================
- ;* Sets the condition bits
- ;*==================================================================
- ??set_bits:
- xor esi,esi
- cmp ebx,[clip_min_y] ; if y >= top its not up
- jge short ??a_not_up
- or esi,1
- ??a_not_up:
- cmp ebx,[clip_max_y] ; if y <= bottom its not down
- jle short ??a_not_down
- or esi,2
- ??a_not_down:
- cmp eax,[clip_min_x] ; if x >= left its not left
- jge short ??a_not_left
- or esi,4
- ??a_not_left:
- cmp eax,[clip_max_x] ; if x <= right its not right
- jle short ??a_not_right
- or esi,8
- ??a_not_right:
- retn
- ;*==================================================================
- ;* Draw the line to the screen.
- ;* PORTABLE end
- ;*==================================================================
- ??draw_it:
- sub edx,ebx ; see if line is being draw down
- jnz short ??not_hline ; if not then its not a hline
- jmp short ??hline ; do special case h line
- ??not_hline:
- jg short ??down ; if so there is no need to rev it
- neg edx ; negate for actual pixel length
- xchg eax,ecx ; swap x's to rev line draw
- sub ebx,edx ; get old edx
- ??down:
- push edx
- push eax
- mov eax,[bpr]
- mul ebx
- mov ebx,eax
- mov eax,[this_object]
- add ebx,[(GraphicViewPort eax).GVPOffset]
- pop eax
- pop edx
- mov esi,1 ; assume a right mover
- sub ecx,eax ; see if line is right
- jnz short ??not_vline ; see if its a vertical line
- jmp ??vline
- ??not_vline:
- jg short ??right ; if so, the difference = length
- ??left:
- neg ecx ; else negate for actual pixel length
- neg esi ; negate counter to move left
- ??right:
- cmp ecx,edx ; is it a horiz or vert line
- jge short ??horiz ; if ecx > edx then |x|>|y| or horiz
- ??vert:
- xchg ecx,edx ; make ecx greater and edx lesser
- mov edi,ecx ; set greater
- mov [accum],ecx ; set accumulator to 1/2 greater
- shr [accum],1
- ;*==================================================================
- ;* at this point ...
- ;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater;
- ;* esi=adder; accum=accumulator
- ;* in a vertical loop the adder is conditional and the inc constant
- ;*==================================================================
- ??vert_loop:
- add ebx,eax
- mov eax,[color]
- ??v_midloop:
- mov [ebx],al
- dec ecx
- jl ??out
- add ebx,[bpr]
- sub [accum],edx ; sub the lesser
- jge ??v_midloop ; any line could be new
- add [accum],edi ; add greater for new accum
- add ebx,esi ; next pixel over
- jmp ??v_midloop
- ??horiz:
- mov edi,ecx ; set greater
- mov [accum],ecx ; set accumulator to 1/2 greater
- shr [accum],1
- ;*==================================================================
- ;* at this point ...
- ;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater;
- ;* esi=adder; accum=accumulator
- ;* in a vertical loop the adder is conditional and the inc constant
- ;*==================================================================
- ??horiz_loop:
- add ebx,eax
- mov eax,[color]
- ??h_midloop:
- mov [ebx],al
- dec ecx ; dec counter
- jl ??out ; end of line
- add ebx,esi
- sub [accum],edx ; sub the lesser
- jge ??h_midloop
- add [accum],edi ; add greater for new accum
- add ebx,[bpr] ; goto next line
- jmp ??h_midloop
- ;*==================================================================
- ;* Special case routine for horizontal line draws
- ;*==================================================================
- ??hline:
- cmp eax,ecx ; make eax < ecx
- jl short ??hl_ac
- xchg eax,ecx
- ??hl_ac:
- sub ecx,eax ; get len
- inc ecx
- push edx
- push eax
- mov eax,[bpr]
- mul ebx
- mov ebx,eax
- mov eax,[this_object]
- add ebx,[(GraphicViewPort eax).GVPOffset]
- pop eax
- pop edx
- add ebx,eax
- mov edi,ebx
- cmp ecx,15
- jg ??big_line
- mov al,[byte color]
- rep stosb ; write as many words as possible
- jmp short ??out ; get outt
- ??big_line:
- mov al,[byte color]
- mov ah,al
- mov ebx,eax
- shl eax,16
- mov ax,bx
- test edi,3
- jz ??aligned
- mov [edi],al
- inc edi
- dec ecx
- test edi,3
- jz ??aligned
- mov [edi],al
- inc edi
- dec ecx
- test edi,3
- jz ??aligned
- mov [edi],al
- inc edi
- dec ecx
- ??aligned:
- mov ebx,ecx
- shr ecx,2
- rep stosd
- mov ecx,ebx
- and ecx,3
- rep stosb
- jmp ??out
- ;*==================================================================
- ;* a special case routine for vertical line draws
- ;*==================================================================
- ??vline:
- mov ecx,edx ; get length of line to draw
- inc ecx
- add ebx,eax
- mov eax,[color]
- ??vl_loop:
- mov [ebx],al ; store bit
- add ebx,[bpr]
- dec ecx
- jnz ??vl_loop
- ??out:
- ret
- ENDP Buffer_Draw_Line
- END
|