Category : Assembly Language Source Code
Archive   : 3DROTATE.ZIP
Filename : 3DROTATE.ASM

 
Output of file : 3DROTATE.ASM contained in archive : 3DROTATE.ZIP
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; TITLE: 3d rotate
;WRITTEN BY: DRAEDEN /VLA CODER /iCE VGA CODER
; FOR: Phantasm, (206) 232-5912
; The first programing oriented board to hit the 206 area.
; Any questions regarding this or ANY code in ANY programming
; language can, and will be answered on Phantasm.
; Send messages to 'Draeden' or post in the VLA programming
; section.
;
; The Deep (TDT/VLA), (305) 888-7824
; Our first distribution site. Messages will also be answered
; if posted at this location.
; Send messages to 'The Kabal'.
;
; DATE: 02/25/93
;
; NOTES: Compiled with TASM 2.51, TLINK 4.0
; Must have a 386 or better to run, Moderate speed.
; This program was chosen as an example because it utilizes
; a lot of the neat little tricks you can do in assembly,
; mainly Structures (STRUC), Unions (UNION), INCLUDEs,
; the REPT macro, and the DUP() macro. It also introduces
; palette rotates in a less-than-boring application.
;
;ASSOCIATED FILES:
;
; BWPRINT.ASM => Displays signed and unsigned bytes, words, or
; > double words
;
; SINCOS.DW => Contains data for the sine and cosine operations
;
; 3DROTATE.TXT=> A text file that further explains palette rotates
; > and the basic 3d stuff.
;
; MAKE.BAT => The file that'll put it all together into an .EXE
;
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

DOSSEG ;tells compiler to sort segments according to the
;DOS standards- code, data, stack
.MODEL SMALL
.STACK 200h ;sets up a 512 byte stack
.DATA ;starts the data segment (empty)
.CODE ;starts the code segment
.386 ;tells compiler to allow 386 instructions
ASSUME CS:@CODE, DS:@CODE
;tells compiler to assume offsets are taken from
;the code segment
LOCALS ;turns local labels on eg. @@local:

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== GLOBALS -used to link multiple programs together

GLOBAL PrintByte:PROC, PrintWord:PROC, PrintBig:PROC
;above is for the file BWPRINT.ASM

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== Data Includes -include physically puts the file in this one on compile

INCLUDE sincos.dw ;Labels SINE: and COSINE: contains sine(0-255)*256

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== DATA Structures

Angle_Union UNION
B db 0
W dw 0
Angle_Union ENDS ;creates a new data type (eg. DW, DB, DD) called
;Angle_Union. Used just like in C
Point_Struc STRUC
X dw ?
Y dw ?
Z dw ?
dw 0 ;a blank area to buffer it out to 8 bytes
; this is done so that access to each point
; is rapid; I can use a SHL XX,3 instead of
; a imul XX,6 saving a few cycles...
Point_Struc ENDS ;Create a structure (or a record)

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== DATA

INCXV EQU 3b00h ;scan code/ascii code for f1
DECXV EQU 3c00h ;f2
INCYV EQU 3d00h ;f3
DECYV EQU 3e00h ;f4
INCZV EQU 3f00h ;f5
DECZV EQU 4000h ;f6
INCDV EQU 4100h ;f7
DecDV EQU 4200h ;f8
StopRot EQU 3920h ;space bar
ZeroAN EQU 1c0dh ;enter key

IncPV1 EQU 0231h ;"1"
DecPV1 EQU 0332h ;"2"
IncPV2 EQU 0433h ;"3"
DecPV2 EQU 0534h ;"4"

MaxLag EQU 15 ;for now, leave at 15

MinDist EQU 200
MaxDist EQU 10000
Distance dw 300
DistanceVel dw 0

STPS EQU 10 ;size of each step
NST EQU 100/STPS
NumPts EQU NST*NST*NST/2 ;the number of points the program
; will rotate and display

;uses nested rept macros to build a solid cube
XYZcord LABEL Point_Struc
i=-25
REPT NST/2
j=-50
REPT NST
k=-50
REPT NST
Point_Struc
k=k+STPS
ENDM
j=j+STPS
ENDM
i=i+STPS
ENDM

RotCord Point_Struc NumPts DUP(<>) ;holds rotated cordinates

HeadDi dw 0
OldDi dw NumPts*MaxLag DUP (0) ;holds old di for quick erasing
;for MaxLag stored frames
OffToCurDi dw offset OldDi ;points to the correct frame
;to erase and fill
Zan Angle_Union
Yan Angle_Union ; the '?' defaults to zero, but you can't
Xan Angle_Union ;specify in a Union
PathAn1 Angle_Union
PathAn2 Angle_Union

ZanVel db 1 ;angle velocities
YanVel db 3
XanVel db -2
P1Vel db 1
P2Vel db 3

PreAddX dw 0 ;amount to ADD to each X, Y & Z >BEFORE<
PreAddY dw 0 ;the distance transforms
PreAddZ dw 0 ;causes the change to be scaled

PostAddX dw 160 ;amount to ADD to each X & Y >AFTER<
PostAddY dw 100 ;the distance transforms

Palette db 3 dup (0)
db 14 dup (60,40,30)

db 63,0,0
db 2,0,0
db 7,0,0
db 9,0,0
db 12,0,0
db 15,0,0
db 17,0,0
db 20,0,0
db 22,0,0
db 25,0,0
db 30,0,0
db 35,0,0
db 40,0,0
db 45,0,0
db 50,0,0
db 63,0,0

PalTmp db 32*3 DUP(0)

Color db 15

AngleMsg db "Ang: $"
AngleVelMsg db "Vel: $"
Control db "Control the angular velocity by hitting F1-F6 and 1 & 2",13,10
db "The distance is controlled by F7 & F8. Hit a key to start.$"
Credits db 13,10,"Coded by Draeden of VLA",13,10,"$"

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;=== Code Includes ;none.
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== SUBROUTINES

;DESTROYS: ax,dx,si,di,es,ds
;Input: BX= X CX= Y BP= Z
;OutPut:BX= X CX= Y BP= Z
RotateXYZ proc near
mov ax,cs
mov ds,ax ; X-rotation
; Y := cos(Xan) * y - sin(Xan) * z
; Z := sin(Xan) * y + cos(Xan) * z

mov si,[Xan.W]
add si,si ; si = angle x
mov ax,[Cosine+si] ; ax = cos(angle x)
imul cx ; ax = cos(angle x) * y
mov di,dx
shl edi,16
mov di,ax ; store for later use
mov ax,[Sine+si] ; ax = sin(angle x)
imul bp ; ax = sin(angle x) * z
shl edx,16
mov dx,ax
sub edi,edx ; di = di-ax = cos(vx)*y - sin(vz)*z
sar edi,8 ; remove the (co)sin "256-factor"
mov es,di ; es = x-coordinate

mov ax,[sine+si] ; ax = sin(angle x)
imul cx ; ax = sin(angle x) * y
mov di,dx
shl edi,16
mov di,ax
mov ax,[cosine+si] ; ax = cos(angle x)
imul bp ; ax = cos(angle x) * z
shl edx,16
mov dx,ax
add edi,edx ; di = di-ax = sin(vx)*y + cos(vx)*z
sar edi,8 ; remove the (co)sin "256-factor"

mov cx,es ; update y
mov bp,di ; update z

; Y-rotation
; X := cos(vy) * xc + sin(vy) * zc
; Z := -sin(vy) * xc + cos(vy) * zc
mov si,[Yan.W]
add si,si ; si = angle y
mov ax,[Cosine+si] ; ax = cos(angle y)
imul bx ; ax = cos(angle y) * x
mov di,dx
shl edi,16
mov di,ax ; store for later use
mov ax,[Sine+si] ; ax = sin(angle y)
imul bp ; ax = sin(angle y) * z
shl edx,16
mov dx,ax
add edi,edx ; di = di+ax = cos(vy)*x + sin(vy)*z
sar edi,8 ; remove the (co)sin "256-factor"
mov es,di ; es = x-coordinate

mov ax,[Sine+si] ; ax = sin(angle y)
neg ax ; ax =-sin(angle y)
imul bx ; ax =-sin(angle y) * x
mov di,dx
shl edi,16
mov di,ax
mov ax,[Cosine+si] ; ax = cos(angle y)
imul bp ; ax = cos(angle y) * z
shl edx,16
mov dx,ax
add edi,edx ; di = di-ax = sin(vy)*x - cos(vy)*z
sar edi,8 ; remove the (co)sin "256-factor"

mov bx,es ; update x
mov bp,di ; update z

; Z-rotation
; X := cos(vz) * xc - sin(vz) * yc
; Y := sin(vz) * xc + cos(vz) * yc
mov si,[Zan.W]
add si,si ; si = angle z
mov ax,[Cosine+si] ; ax = cos(angle z)
imul bx ; ax = cos(angle z) * x
mov di,dx
shl edi,16
mov di,ax
mov ax,[Sine+si] ; ax = sin(angle z)
imul cx ; ax = sin(angle z) * y
shl edx,16
mov dx,ax
sub edi,edx ; di = di-ax = cos(vz)*x - sin(vz)*y
sar edi,8 ; remove the (co)sin "256-factor"
mov es,di ; es = x-coordinate

mov ax,[Sine+si] ; ax = sin(angle z)
imul bx ; ax = sin(angle z) * x
mov di,dx
shl edi,16
mov di,ax
mov ax,[Cosine+si] ; ax = cos(angle z)
imul cx ; ax = cos(angle z) * y
shl edx,16
mov dx,ax
add edi,edx ; di = di+ax = sin(vz)*x+cos(vz)*y
sar edi,8 ; remove the (co)sin "256-factor"

mov bx,es ; update x
mov cx,di ; update y

ret
RotateXYZ ENDP

;rotates all points and saves them
RotateBox PROC NEAR
pushad ;saves EVERYTHING (extended registers, too), except flags
mov ax,cs
mov ds,ax
mov es,ax

mov di,0 ;point counter
@@DoNextPoint:
;Input: BX= X CX= Y BP= Z
;OutPut:BX= X CX= Y BP= Z

mov bx,[XYZcord.X +di] ;load in cordinates to rotate
mov cx,[XYZcord.Y +di]
mov bp,[XYZcord.Z +di]

push di
call RotateXYZ
pop di

mov [RotCord.X +di],bx ;save rotated cordinates IN A DIFFERENT PLACE
mov [RotCord.Y +di],cx
add bp,[Distance]
mov [RotCord.Z +di],bp

add di,8 ;size of each entry
cmp di,NumPts*8 ;are we done, yet?
jb @@DoNextPoint ;No. Do another

popad
ret
RotateBox ENDP

;draws the dots to the screen
DrawBox PROC NEAR
pusha ;saves only non extended registers
mov ax,0a000h ;segment to VGA memory
mov es,ax
mov ax,cs
mov ds,ax

mov bp,0 ;point counter
mov al,[Color]
mov bx,[OffToCurDi]
@@DoNextPoint:
mov si,bp
add si,si
shl si,2 ;si= bp*8

mov ax,[HeadDi]
add al,16

mov di,cs:[bx]
cmp BYTE PTR es:[di],al ;makes sure that we only erase the dots we
;are sposed to.. works OK, BUT because we
;erase and draw to the same frame, a dot
;that we just drew in this loop could be
;erase, causing black spots in the object
;zoom it out too see what I'm saying
jne NotMineDontErase
mov BYTE PTR es:[di],0 ;clear out old point

NotMineDontErase:

;pixel location = ScreenWidth*Ypos + Xpos = 320 * (Y+AddY) + X + AddX
mov cx,[RotCord.Z +si]
add cx,[PreAddZ]

mov ax,[RotCord.Y +si]
add ax,[PreAddY]
movsx dx,ah
shl ax,8
idiv cx ;you are witnessing the evils of depth emulation-
add ax,[PostAddY] ; the divide that you just can't get rid of
mov di,ax
cmp di,200
jae DontDraw
imul di,320

mov ax,[RotCord.X +si]
add ax,[PreAddX]
movsx dx,ah
shl ax,8
idiv cx ;Aaarrrgghh! Another one!
add ax,[PostAddX]
cmp ax,320
jae DontDraw
add di,ax
mov [bx],di

mov ax,[HeadDi]
add al,16
stosb
RESUMEDRAW:
add bx,2
inc bp
cmp bp,NumPts ;are we done, yet?
jb @@DoNextPoint ;No. Do another

;adjust head pointer
call ChangePalette

inc [HeadDi]
cmp [HeadDi],MaxLag
jb NotAtEnd
mov [HeadDi],0
NotAtEnd:
mov bx,[Headdi]
add bx,bx
imul bx,NumPts
add bx,offset OldDi
mov [OffToCurDi],bx

popa
ret
DontDraw:
mov byte ptr [bx],0
jmp short RESUMEDRAW
DrawBox ENDP

ChangePalette PROC NEAR
pusha
mov ax,cs
mov ds,ax
mov es,ax

mov si,offset Palette+3*15
mov di,offset PalTmp
mov bp,[HeadDi]

mov cx,bp ;this bit of code is a quick way to
add bp,bp ;
add bp,cx ;multiply bp by 3

add di,bp ;sets up for copy #1
mov cx,16*3
sub cx,bp
rep movsb ;copies block #1

or bp,bp
je NoBlock2

mov di,offset PalTmp
mov cx,bp
rep movsb

NoBlock2:
mov al,16 ;we start the write at color #16
mov dx,03c8h
out dx,al
inc dx
mov si,offset PalTmp
mov cx,16*3 ;write 16 colors (3 bytes per color)
rep outsb

popa
ret
ChangePalette ENDP

;DESTROYS: flags and AX
;updates all the distances, angles, ect...
AddAngles PROC NEAR
mov ax,[DistanceVel]
add [Distance],ax
cmp [Distance],MinDist
jge DistMinOk
mov [DistanceVel],0
mov [Distance],MinDist
DistMinOk:
cmp [Distance],MaxDist
jle DistMaxOk
mov [DistanceVel],0
mov [Distance],MaxDist
DistMaxOk:
mov al,[P1Vel]
add [PathAn1.b],al
mov al,[P2Vel]
add [PathAn2.b],al

mov al,[ZanVel]
add [Zan.b],al
mov al,[YanVel]
add [Yan.b],al
mov al,[XanVel]
add [Xan.b],al ;note that by just increasing the byte part, the
;ranging is automatic (stays in 0-255 range)

mov bx,[PathAn1] ;this little section of code fixes up the
add bx,bx ;path that the object travels
mov ax,[Sine+bx] ;PathAn1 controls the X-Z PreAdds and
mov cx,[Cosine+bx] ;PathAn2 controls PreYadd
sar ax,3 ;Because the sine and cosine chart are
sar cx,4 ;multiplied by 256, dividing by 8 and 16
mov [PreAddX],ax ;is the same as multiplying the (co)sine by
mov [PreAddZ],cx ;32 and 16 respectivly
;this gives the object a slightly nauseating
mov bx,[PathAn2] ;bobbing pattern
add bx,bx
mov ax,[Sine+bx]
sar ax,4
mov [PreAddY],ax
ret
AddAngles ENDP

;DESTROYS: AX,BX,DX, FLAGS
;puts all the text up top
DisplayStuff PROC NEAR
mov ah,2
mov bx,0
mov dx,0
int 10h ;set cursor pos to (dl,dh) on page BX

mov ah,9
mov dx,offset AngleMsg
int 21h

mov al,[Xan.B]
clc ;says print it unsigned
call PrintByte
mov al,[Yan.B]
clc ;says print it unsigned
call PrintByte
mov al,[Zan.B]
clc ;says print it unsigned
call PrintByte
mov ax,[Distance]
clc ;says print it unsigned
call PrintWord

mov al,[PathAn1.B]
clc ;says print it unsigned
call PrintByte
mov al,[PathAn2.B]
clc ;says print it unsigned
call PrintByte

mov ah,2
mov bx,0
mov dx,0100h
int 10h ;set cursor pos to (dl,dh) on page BX

mov ah,9
mov dx,offset AngleVelMsg
int 21h

mov al,[XanVel]
stc ;says print it signed
call PrintByte
mov al,[YanVel]
stc ;says print it signed
call PrintByte
mov al,[ZanVel]
stc ;says print it signed
call PrintByte
mov ax,[DistanceVel]
stc ;says print it signed
call PrintWord

mov al,[P1Vel.B]
stc ;says print it signed
call PrintByte
mov al,[P2Vel.B]
stc ;says print it signed
call PrintByte

ret
DisplayStuff ENDP

;DESTROYS: a bunch of registers
;does all the keyboard oriented stuff..
;clears carry if we are to continue, sets it if we are to quit
DoKeyInput PROC NEAR
mov ah,11h
int 16h ;has a key been pressed? Z flag is set if not
jnz GetTheKey
clc ;we continue
ret

GetTheKey:
mov ah,10h ;a key has been pressed,
int 16h ; get it in AX (al= ascii, ah=scan code)

cmp al,27 ;was it the ESCAPE key?
jne KeepGoing
stc ;we signal a quit
ret

KeepGoing: ;despite its apparent ungainly look, this
cmp ax,INCXV ;is very fast..as little as 2 clocks for each
je DoINCXV ;unsuccessful compare on the 486 and 5 clocks on
cmp ax,DECXV ;the 386... A rather quick way to do it...
je DoDECXV
cmp ax,INCYV
je DoINCYV
cmp ax,DECYV
je DoDECYV
cmp ax,INCZV
je DoINCZV
cmp ax,DECZV
je DoDECZV
cmp ax,INCDV
je DoIncDV
cmp ax,DECDV
je DoDecDV
cmp ax,ZEROAN
je DoZeroAn
cmp ax,STOPROT
je DoStopRot

cmp ax,INCPV1
je DoIncPv1
cmp ax,DECPV1
je DoDecPv1
cmp ax,INCPV2
je DoIncPv2
cmp ax,DECPV2
je DoDecPv2

clc ;no valid keypress... Continue
ret

DoINCXV:
inc [XanVel]
clc
ret
DoINCYV:
inc [YanVel]
clc
ret
DoINCZV:
inc [ZanVel]
clc
ret

DoDECXV:
dec [XanVel]
clc
ret
DoDECYV:
dec [YanVel]
clc
ret
DoDECZV:
dec [ZanVel]
clc
ret
DoINCDV:
inc [DistanceVel]
clc
ret
DoDECDV:
dec [DistanceVel]
clc
ret
DoStopRot:
mov [XanVel],0
mov [YanVel],0
mov [ZanVel],0
mov [DistanceVel],0
clc
ret
DoZeroAn:
mov [Xan.W],0
mov [Yan.W],0
mov [Zan.W],0
clc
ret
DoINCPv1:
inc [P1Vel]
clc
ret
DoDECPv1:
dec [P1Vel]
clc
ret
DoINCPv2:
inc [P2Vel]
clc
ret
DoDECPv2:
dec [P2Vel]
clc
ret

DoKeyInput ENDP
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;=== CODE

START:
mov ax,cs
mov ds,ax
mov es,ax

mov ah,9 ;print a dollar sign terminating string
mov dx,offset control
int 21h

mov ah,0
int 16h ;wait for a keypress

mov ax,0013h ;set 320x200x256 mode
int 10h

mov dx,offset Palette ;ES:DX points to palette data
mov ax,1012h ; WRITE palette
mov bx,0 ;start at color 0
mov cx,16 ; and write 16 of 'em
int 10h

MainLoop:
call RotateBox
call AddAngles

mov dx,3dah
VRT:
in al,dx
test al,8
jnz VRT ;wait until Verticle Retrace starts
NoVRT:
in al,dx
test al,8
jz NoVRT ;wait until Verticle Retrace Ends

call DrawBox
call DisplayStuff
call DoKeyInput
jnc MainLoop ;jump if carry is clear

ByeBye:
mov ax,0003h ;set 80x25x16 text
int 10h
push cs
pop ds
mov ah,9
mov dx,offset credits
int 21h
mov ax,4c00h ;return control to DOS
int 21h
END START


  3 Responses to “Category : Assembly Language Source Code
Archive   : 3DROTATE.ZIP
Filename : 3DROTATE.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/