;**********************************
;*** ***
;*** A Fast 3D LandScape ***
;*** by TTT ***
;*** ***
;*** ttaipale@phoenix.oulu.fi ***
;**********************************
;Copyright (C) TTT, All rights reserved.
;
;The routine to set ModeX by Draeden/VLA
;
;NOTE: The land data can be anything. This land is a FractInt
; plasma-cloud converted to ASCII.
;
;*** Land data now generated at runtime, by Tenie Remmel
; This saves a HUGE amount of space.
DOSSEG
.MODEL small
.STACK 200h
.386
;***************
;*** EQUATES ***
;***************
ClipT equ 0
ClipB equ 239
ClipL equ 0
ClipR equ 319
MidX equ 160
MidY equ 160
GridX equ 1 ;Size of the grid
GridY equ 50
GridZ equ 50
GyAdd equ GridY*2*2
GridPoints equ GridX*GridY*GridZ
DIST equ 15 ;Distance between points
SVAL_2 equ 6 ;2nd shift value
;*************************
;*** Data for the land ***
;*************************
Land segment use16 'BSS'
db 64000 dup(0)
Land ends
PointData segment use16
dd GridPoints*3 dup(0)
PointData ends
PointData2 segment use16
dw GridPoints*3 dup(0)
PointData2 ends
.CODE
;******************
;INCLUDES
;******************
INCLUDE modex.inc
ALIGN 2
INCLUDE scos.dd ;Sine and cosine tables: value * 16384
ALIGN 2
YTable label word
INCLUDE ytab80.dw
ALIGN 2
YTab label word
INCLUDE ytab.dw
Palette label byte
i = 0
REPT 63
db 0,0,i
i = i + 1
ENDM
i = 0
REPT 63
db 0,i,0
i = i + 1
ENDM
i = 0
REPT 63
db i,i,i
i = i + 1
ENDM
db 768 dup(63)
;******************
;VARIABLES
;******************
ALIGN 2
CurrentPage dw 32000
DisplayPage dw 0
AngleX dw 0
AngleY dw 256
AngleZ dw 200
Depth dd 800
SinX dd 0
SinY dd 0
SinZ dd 0
CosX dd 0
CosY dd 0
CosZ dd 0
Add1 dd 0
Add2 dd 0
Add3 dd 0
Add4 dd 0
Add5 dd 0
Add6 dd 0
Add7 dd 0
Add8 dd 0
Add9 dd 0
XPos dw 0
YPos dw 0
XDir dw 0
YDir dw 0
CtrlPts dd 6*3 dup(0)
Points label word
dw (DIST*GRIDX)/2 ,(DIST*GRIDY)/2,(DIST*GRIDZ)/2
dw ((DIST*GRIDX)/2)-DIST,(DIST*GRIDY)/2,(DIST*GRIDZ)/2
dw (DIST*GRIDX)/2,(DIST*GRIDY)/2 ,(DIST*GRIDZ)/2
dw (DIST*GRIDX)/2,((DIST*GRIDY)/2)-DIST,(DIST*GRIDZ)/2
dw (DIST*GRIDX)/2,(DIST*GRIDY)/2,(DIST*GRIDZ)/2
dw (DIST*GRIDX)/2,(DIST*GRIDY)/2,((DIST*GRIDZ)/2)-DIST
;**********************************
;*** ROTATES THE CONTROL POINTS ***
;**********************************
ALIGN 2
RotControl PROC
mov si, [cs:AngleX]
shl si, 2
mov eax, [cs:Sinetable+si]
mov ebx, [cs:Costable+si]
mov [cs:SinX], eax
mov [cs:CosX], ebx
mov si, [cs:AngleY]
shl si, 2
mov eax, [cs:Sinetable+si]
mov ebx, [cs:Costable+si]
mov [cs:SinY], eax
mov [cs:CosY], ebx
mov si, [cs:AngleZ]
shl si, 2
mov eax, [cs:Sinetable+si]
mov ebx, [cs:Costable+si]
mov [cs:SinZ], eax
mov [cs:CosZ], ebx
mov cx, 6
sub si, si
sub di, di
ALIGN 2
Rotloop:
push cx
mov bx, [cs:Points+si] ;Get X
mov cx, [cs:Points+si+2] ;Get Y
mov bp, [cs:Points+si+4] ;Get Z
movsx ebx, bx
movsx ecx, cx
movsx ebp, bp
push si
push di
mov eax, [cs:CosX] ;Around X
imul ecx
mov edi, eax
mov eax, [cs:SinX]
imul ebp
sub edi, eax
mov eax, [cs:SinX]
imul ecx
mov esi, eax
mov eax, [cs:CosX]
imul ebp
add esi, eax
sar esi, 8
sar edi, 8
mov ecx, edi
mov ebp, esi
mov eax, [cs:CosZ] ;Around Z
imul ebx
mov edi, eax
mov eax, [cs:SinZ]
imul ecx
sub edi, eax
mov eax, [cs:SinZ]
imul ebx
mov esi, eax
mov eax, [cs:CosZ]
imul ecx
add esi, eax
sar edi, 14
sar esi, 14
mov ebx, edi
mov ecx, esi
mov eax, [cs:CosY] ;around Y
imul ebx
mov edi, eax
mov eax, [cs:SinY]
imul ebp
sub edi, eax
mov eax, [cs:SinY]
imul ebx
mov esi, eax
mov eax, [cs:CosY]
imul ebp
add esi, eax
sar esi, 14
sar edi, 14
mov ebx, edi
mov ebp, esi
pop di
pop si
mov [cs:CtrlPts+di], ebx
mov [cs:CtrlPts+di+4], ecx
mov [cs:CtrlPts+di+8], ebp
pop cx
add di, 12
add si, 6
dec cx
jnz Rotloop
ret
RotControl EndP
;***********************************************************
;*** CALCULATES THE DISTANCES BETWEEN THE CONTROL POINTS ***
;***********************************************************
ALIGN 2
CalculateDistances PROC
mov eax, [cs:CtrlPts]
mov ebx, [cs:CtrlPts+4]
mov ecx, [cs:CtrlPts+12]
mov edx, [cs:CtrlPts+16]
sub ecx, eax
sub edx, ebx
mov [cs:Add1], ecx
mov [cs:Add2], edx
mov eax, [cs:CtrlPts+8]
mov ebx, [cs:CtrlPts+20]
sub ebx, eax
mov [cs:Add3], ebx
mov eax, [cs:CtrlPts+24]
mov ebx, [cs:CtrlPts+28]
mov ecx, [cs:CtrlPts+36]
mov edx, [cs:CtrlPts+40]
sub ecx, eax
sub edx, ebx
mov [cs:Add4], ecx
mov [cs:Add5], edx
mov eax, [cs:CtrlPts+32]
mov ebx, [cs:CtrlPts+44]
sub ebx, eax
mov [cs:Add6], ebx
mov eax, [cs:CtrlPts+48]
mov ebx, [cs:CtrlPts+52]
mov ecx, [cs:CtrlPts+60]
mov edx, [cs:CtrlPts+64]
sub ecx, eax
sub edx, ebx
mov [cs:Add7], ecx
mov [cs:Add8], edx
mov eax, [cs:CtrlPts+56]
mov ebx, [cs:CtrlPts+68]
sub ebx, eax
mov [cs:Add9], ebx
ret
CalculateDistances EndP
;***********************************************************
;*** CALCULATES THE GRID FROM THE ROTATED CONTROL POINTS ***
;***********************************************************
ALIGN 2
MakeGrid PROC
mov ax, PointData
mov ds, ax
sub si, si
mov edx, [cs:CtrlPts]
mov ebp, [cs:CtrlPts+4]
mov edi, [cs:CtrlPts+8]
mov cx, GridZ
mov ebx, [cs:Add1]
ALIGN 2
ZLoop: push cx
push edx
push ebp
push edi
mov cx, GridY
ALIGN 2
YLoop: push cx
push edx
push ebp
push edi
mov cx, GridX
ALIGN 2
XLoop: mov eax, edx
sar eax, SVAL_2
mov ds:[si], eax
mov eax, ebp
sar eax, SVAL_2
mov ds:[si+4], eax
mov eax, edi
sar eax, SVAL_2
mov ds:[si+8], eax
add edx, ebx
add ebp, [cs:Add2]
add edi, [cs:Add3]
add si, 12
dec cx
jnz XLoop
pop edi
pop ebp
pop edx
add edx, [cs:Add4]
add ebp, [cs:Add5]
add edi, [cs:Add6]
pop cx
dec cx
jnz YLoop
pop edi
pop ebp
pop edx
add edx, [cs:Add7]
add ebp, [cs:Add8]
add edi, [cs:Add9]
pop cx
dec cx
jnz ZLoop
ret
MakeGrid EndP
;**********************************************************
;*** TRANSFORMS THE GRID POINTS INTO SCREEN COORDINATES ***
;**********************************************************
ALIGN 2
TransformGrid PROC
mov ax, PointData
mov ds, ax
mov ax, PointData2
mov es, ax
mov cx, GridPoints
sub si, si
sub di, di
ALIGN 2
TransformLoop:
push cx
mov ebx, ds:[si]
mov ecx, ds:[si+4]
mov ebp, ds:[si+8]
add ebp, [cs:Depth]
cmp ebp, 20
jge NoZTrunc
mov ebp, 20
mov eax, ebx
movsx dx, ah
sal eax, 8
idiv bp
add ax, MidX
mov es:[di], ax
mov eax, ecx
movsx dx, ah
sal eax, 8
idiv bp
add ax, MidY
mov es:[di+2], ax
pop cx
add si, 12
add di, 6
dec cx
jnz TransformLoop
ret
ALIGN 2
NoZTrunc:
mov eax, ebx
movsx dx, ah
sal eax, 8
idiv bp
add ax, MidX
mov es:[di], ax
mov eax, ecx
movsx dx, ah
sal eax, 8
idiv bp
add ax, MidY
mov es:[di+2], ax
pop cx
add si, 12
add di, 6
dec cx
jnz TransformLoop
ret
TransformGrid EndP
;***********************************
;*** Maps the land over the grid ***
;***********************************
ALIGN 2
PutLand PROC
mov ax, Land
mov ds, ax
mov ax, PointData2
mov es, ax
sub si, si
mov bx, [cs:YPos]
shl bx, 1
add si, [cs:YTab+bx]
add si, [cs:XPos]
sub di, di
mov bp, GridZ
ALIGN 2
PZLoop: mov cx, GridY
PYLoop: sub bx, bx
mov ax, es:[di+2]
mov bl, BYTE PTR ds:[si]
mov es:[di+4], bx
sar bx, 1
sub ax, bx
mov es:[di+2], ax
inc si
add di, 6
dec cx
jnz PYLoop
add si, 320-GridY
dec bp
jnz PZLoop
ret
PutLand EndP
;*************************
;*** CLEARS THE SCREEN ***
;*************************
ALIGN 2
Clear PROC
mov dx, SC_INDEX
mov ax, 0f02h
out dx, ax
mov ax, 0a000h
mov es, ax
mov di, [cs:CurrentPage]
mov cx, 19200/4
sub eax, eax
rep stosd
ret
Clear EndP
;**********************
;*** Draws the land ***
;**********************
ALIGN 2
DrawLand PROC
mov ax, PointData2
mov ds, ax
mov ax, 0a000h
mov es, ax
sub si, si
mov di, [cs:CurrentPage]
mov bp, GridPoints
mov dx, SC_INDEX
ALIGN 2
DrawLoop:
mov ax, ds:[si]
cmp ax, ClipL
jl ClipThis
cmp ax, ClipR
jg ClipThis
mov bx, ds:[si+2]
cmp bx, ClipT
jl ClipThis
cmp bx, ClipB
jg ClipThis
mov cx, ax ;Store X
sar ax, 2
shl bx, 1
add ax, [cs:YTable+bx]
mov bx, ax
and cl, 011b
mov ax, 0100h + 2
shl ah, cl
out dx, ax
mov ax, ds:[si+4]
mov es:[di+bx], al
add si, 6
dec bp
jnz DrawLoop
ret
ALIGN 2
ClipThis:
add si, 6
dec bp
jnz DrawLoop
ret
DrawLand EndP
;*************************************
;*** MOVES THE LAND IN Y-DIRECTION ***
;*************************************
ALIGN 2
MoveLandY PROC
cmp [cs:YDir], 1
jz ThatWayY
add [cs:YPos], 1
cmp [cs:YPos], 200-GridZ
jnz NoCYDir
mov [cs:YDir], 1
NoCYDir:
ret
ALIGN 2
ThatWayY:
sub [cs:YPos], 1
cmp [cs:YPos], 0
jnz NoCYDir
mov [cs:YDir], 0
ret
MoveLandY EndP
;*************************************
;*** MOVES THE LAND IN X-DIRECTION ***
;*************************************
ALIGN 2
MoveLandX PROC
cmp [cs:XDir], 1
jz ThatWayX
add [cs:XPos], 1
cmp [cs:XPos], 320-GridY
jnz NoCXDir
mov [cs:XDir], 1
NoCXDir:
ret
ALIGN 2
ThatWayX:
sub [cs:XPos], 1
cmp [cs:XPos], 0
jnz NoCXDir
mov [cs:XDir], 0
ret
MoveLandX EndP
GETPIX macro x, y ;Getpixel macro
mov bx,x
mov cx,y
add bh,cl
shl cx,6
add bx,cx
mov al,es:[bx]
EndM
SETPIX macro x, y ;Setpixel macro
mov bx,x
mov cx,y
add bh,cl
shl cx,6
add bx,cx
mov es:[bx],al
endm
PUSHI macro a,b,c,d,e,f ;Multiple push
ifnb <a>
push a
PUSHI b,c,d,e,f
endif
endm
GenLand proc
pusha ;Save registers
push ds
push es
push cs ;DS = CS
pop ds
push 0 ;ES = 0
pop es
mov eax,es:[046Ch] ;Seed RNG
mov dword ptr RandNum,eax
mov ax,seg Land ;ES = land segment
mov es,ax
mov ax,192 ;Set corner pixels to random colors
call Rand
inc ax
mov es:[0],al
mov ax,192
call Rand
inc ax
mov es:[319],al
mov ax,192
call Rand
inc ax
mov es:[63360],al
mov ax,192
call Rand
inc ax
mov es:[63999],al
PUSHI 199 319 0 0 ;Draw plasma
call Plasma
pop es ;Restore registers
pop ds
popa
ret ;Return
GenLand endp
;**************************** Plasma -- Recursive plasma procedure
Plasma proc
push bp ;Set up stack frame
mov bp,sp
pusha ;Save all registers
mov ax,[bp+8] ;x2 - x1 < 2, done
sub ax,[bp+4]
cmp ax,2
jb P_Done
mov ax,[bp+4] ;Get values
mov bx,[bp+6]
mov cx,[bp+8]
mov dx,[bp+10]
mov si,ax ;x = (x1 + x2) / 2
add si,cx
sar si,1
mov di,bx ;y = (y1 + y2) / 2
add di,dx
sar di,1
pusha ;Save registers
PUSHI bx si bx cx bx ax ;Adjust top side
call Adjust
PUSHI dx si dx cx dx ax ;Adjust bottom side
call Adjust
PUSHI di ax dx ax bx ax ;Adjust left side
call Adjust
PUSHI di cx dx cx bx cx ;Adjust right side
call Adjust
GETPIX si,di ;Center pixel on, recurse
test al,al
jnz P_Recurse
xor dx,dx ;Zero DX, AH
xor ah,ah
GETPIX [bp+4],[bp+6] ;DX = sum of corners
add dx,ax
GETPIX [bp+8],[bp+6]
add dx,ax
GETPIX [bp+4],[bp+10]
add dx,ax
GETPIX [bp+8],[bp+10]
add dx,ax
shr dx,2 ;DX = average of corners
mov al,dl
SETPIX si,di ;Set center pixel
P_Recurse: popa ;Restore registers
PUSHI di si bx ax ;Plasma x1, y1, x, y
call Plasma
PUSHI di cx bx si ;Plasma x, y1, x2, y
call Plasma
PUSHI dx cx di si ;Plasma x, y, x2, y2
call Plasma
PUSHI dx si di ax ;Plasma x1, y, x, y2
call Plasma
P_Done: popa ;Restore registers
pop bp ;Delete stack frame
ret 8 ;Return, pop args
Plasma endp
;**************************** Adjust -- Random adjust pixel midpoint
Adjust proc
push bp ;Set up stack frame
mov bp,sp
pusha ;Save all registers
GETPIX [bp+12],[bp+14] ;Check pixel
test al,al ;Already on, done
jnz A_Done
mov ax,[bp+8] ;BX = |x2 - x1| + |y2 - y1|
sub ax,[bp+4]
mov bx,[bp+10]
sub bx,[bp+6]
test ax,ax ;get absolute values...
jge $+4
neg ax
test bx,bx
jge $+4
neg bx
add bx,ax
mov ax,bx ;AX = BX * 2 + 1
add ax,ax
inc ax
mov bx,ax ;Get random number
call Rand ;positive and negative
sar bx,1
sub ax,bx
mov dx,ax ;in DX
GETPIX [bp+4],[bp+6] ;AX = average of ends + DX
push ax
GETPIX [bp+8],[bp+10]
pop bx
xor ah,ah
add al,bl
adc ah,0
sar ax,1
add ax,dx
cmp ax,1 ;Make sure it's in range
jge $+5
mov ax,1
cmp ax,192
jle $+5
mov ax,192
SETPIX [bp+12],[bp+14] ;Set center pixel
A_Done: popa ;Restore registers
pop bp ;Delete stack frame
ret 12 ;Return, pop args
Adjust endp
;**************************** Rand -- Random number generator
Rand proc
push edx
push ebx
mov bx,ax
imul eax,RandNum,015A4E35h
inc eax
mov RandNum,eax
shr eax,15
xor dx,dx
div bx
mov ax,dx
pop edx
pop ebx
ret
RandNum dd ?
Rand endp
;********************
;*** MAIN PROGRAM ***
;********************
START: call GenLand
@SetModeX x320, y480, 2, 320
mov ax, cs
mov ds, ax
mov si, OFFSET Palette
mov ax, 0
mov cx, 256
call WritePalette
Mainloop:
call Clear
call RotControl
call CalculateDistances
call MakeGrid
call TransformGrid
call PutLand
call DrawLand
mov bx, [cs:CurrentPage]
mov ax, [cs:DisplayPage]
mov [cs:CurrentPage], ax
mov [cs:DisplayPage], bx
call Set_Start_Offset
call MoveLandX
; call MoveLandY
add [cs:AngleX], 4
cmp [cs:AngleX], 1023
jle NoWrap
sub [cs:AngleX], 1023
NoWrap:
; add [cs:AngleZ], 4
cmp [cs:AngleZ], 1023
jle NoWrap2
sub [cs:AngleZ], 1023
NoWrap2:
; add [cs:AngleY], 4
cmp [cs:AngleY], 1023
jle NoWrap3
sub [cs:AngleY], 1023
NoWrap3:
call Wait_FVR1
mov ah, 1
int 16h
jz Mainloop
mov ah, 0
int 16h
cmp al, 27
jz Bye
jmp Mainloop
BYE: mov ax, 3h
int 10h
mov ax, 4c00h
int 21h
END START
end