home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
SKY.ZIP
/
TESTSKY.ASM
< prev
next >
Wrap
Assembly Source File
|
1996-02-14
|
7KB
|
228 lines
;----------------------------------------------------------------------
; ProjectSky - Project a 256x256 map to the sky
;
; Turbo Pascal near-callable as
; ProjectSky(Map:Pointer;Buffer:Pointer;X,Y,Height:longint);
;
; X,Y are the coords of the viewpoint (16.16 fixed point)
; Height is the distance from the sky to the viewpoint (16.16)
;
; This routine has been timed at ~4.8 cycles/pixel for the inner loop
; rendering to an offscreen buffer on a 486 with 256K cache.
;
; WARNING: this code is somewhat kludgy.
;
; In particular, I have done some nasty things to gain an extra
; register (sp) for the main unrolled loop, and at the same time
; modified the stack segment register as a general segment register.
; This is VERY NAUGHTY and I don't recommend doing it :). The instruction
; ordering is also a bit counter-intuitive in the inner loop to avoid
; register contentions and AGIs on both the Pentium and the 486.
;
; The code is also somewhat more spaghetti-ish than it need be, since
; this is cut down from a more general routine that allows pitching of
; the viewpoint as well as other things.
;
; One obvious improvement is to have two inner loops: one for close bits
; which dithers the sky map, the other for distant bits which interpolates
; between values, thus avoiding some of the aliasing you get close to the
; horizon. If anyone does this and wants to send me a copy, I'd be
; grateful :)
;
; Mark Mackey (mdm1004@cus.cam.ac.uk)
;
; This code is Copyright (C) 1996 Mark Mackey. Use, modification,
; and redistribution of this code is freely permitted, provided that
; the original author is acknowledged.
;----------------------------------------------------------------------
.model small,pascal
.386
BORDER equ 0 ; Size of screen border
BUFFERWIDTH equ 256 ; Width of screen buffer
; General view parameters
d equ 1 ; 2^d is the focal length
StartLine equ 100 ; Starting line value
EndLine equ 4 ; End line value
; Total number of lines drawn is
; StartLine-Endline. The horizon is
; at 0 but it's generally worth clipping
; the sky a few lines above the horizon
; since you get nasty aliasing in the
; last few lines. Change StartLine to
; 97 and Endline to 1 to see what I
; mean :).
;Sky
xscale equ 6 ; scaling factors: change these to taste.
zscale equ 1 ; Note that these values are logarithmic,
; ie increasing them by 1 doubles the
; scale.
Mapz equ -4
Mapx equ -8 ; local variables.
STACK_FRAME_SIZE equ 8
.DATA
Saved_ss dw (?) ; Used to hold ss and sp during inner loop.
Saved_sp dw (?)
.CODE
MyShl MACRO reg,int ; General purpose shl by a constant. Handles negatives.
IF (int) EQ 0
ELSE ;ignore shifts by zero
IF (int) LT 0
MySar reg,-int
ELSE
IF (int) EQ 1
add reg,reg ; Faster than shl xx,1
ELSE
shl reg,int
ENDIF
ENDIF
ENDIF
ENDM
MySar MACRO reg,int ; General purpose sar by a constant. Handles negatives.
IF (int) EQ 0
ELSE ; Ignore shifts by zero
IF (int) LT 0
MyShl reg,-int
ELSE
sar reg,int ; Arithmetic shift.
ENDIF
ENDIF
ENDM
PUBLIC ProjectSky
ProjectSky proc near Pascal Map:FAR PTR,Buffer:FAR PTR,X:DWORD,Y:DWORD,Height:DWORD
; Kills all registers except ds,ss,sp,bp
sub sp,STACK_FRAME_SIZE
push ds
cld
mov ax,_DATA
mov gs,ax
les di,[Buffer]
add di,BORDER
xor ecx,ecx
mov cx,StartLine ; Counter=value of first line
align 16
@@startloop:
mov ebx,ecx
shl ebx,8 ;ebx holds counter in 24.8
xor edx,edx
mov eax,[height]
shld edx,eax,8+d
MyShl eax,8+d
div ebx
;eax holds height*d/ebx 16.16
; save as Mapz
mov dword ptr [bp+Mapz],eax
MyShl eax,7-xscale-d
neg eax
add eax,[x]
mov [bp+Mapx],eax ;mapx=(-128*mapz) shr xscale (scaling) div d + x in 16.16
; This is the starting x value for the map
mov eax,[bp+Mapz]
MyShl eax,zscale ;mapz=mapz*2^zscale (scaling)
mov ebx,[y]
add eax,ebx ;eax = mapz + y in 16.16
shr eax,8 ;ah holds map y value for this line.
mov ebx,[bp+Mapx]
sar ebx,16 ; Whole value of mapx in bx
mov al,bl ; mapx mod 256 placed in al
; => ax holds map starting point (integer)
lds si,[Map]
add si,ax
mov eax,[bp+mapx] ; ax holds fractional part of mapx
; => si.ax holds complete map starting
; point in 16.16 fixed point
mov ebx,[bp+mapz]
shr ebx,xscale+d ;ebx = delta = mapz shr (xscale+d) (scaling)
mov edx,ebx
shr edx,16 ;delta in dx.bx in 16:16 fixed point
; delta is the value we step across the
; sky map with.
push cx ; save counter
cli ;Prevent interrupts since stack is
;clobbered below
push bp
mov gs:[Saved_sp],sp ;save stack pointer: can't use stack
mov gs:[Saved_ss],ss ;until restored!
mov sp,es
mov ss,sp ; ss points to buffer. We do this to
; avoid segment overrides in the inner
; loop, which really slow the Pentium
; down.
mov bp,di ; ss:bp points to current location in buffer
mov di,si
mov sp,ax ; di.sp = si.ax = map starting point
add sp,bx ;initialise odd start value: add delta
adc di,dx
and cx,0001 ;Swap odd/even dither depending on
; lsb of cx
jnz @odd
@even:
add ax,8000h ; add 0.5 for dithering on even bytes
adc si,0
jmp @ditherOK
@odd:
add sp,8000h ; add 0.5 for dithering on odd bytes
adc di,0
@ditherOK:
add bx,bx ;double delta
adc dx,dx
add ax,bx ;setup due to rearranged instructions in
adc si,dx ; main loop
add sp,bx ;
offs=0
rept (BUFFERWIDTH-BORDER*2)/2 ; 2 pixels/loop. Pentium pipeline use below:
mov cl,ds:[si] ;V0
adc di,dx ;U1
add ax,bx ;V1
mov ch,ds:[di] ;U3 (AGI on di)
adc si,dx ;U4
add sp,bx ;V4
mov ss:[bp+offs],cx ;U5
offs=offs+2
endm
mov di,bp
mov ss,gs:[Saved_ss] ; restore stack
mov sp,gs:[Saved_sp]
pop bp
sti
add di,BUFFERWIDTH ; set up for next row
pop cx
dec cx
cmp cx,EndLine ; Have we finished?
jge @@startloop
@End:
pop ds
ret ; Done!
ProjectSky endp
end