ORG 100h numstars equ 100 ; star: ; word x ; word y ; word z ; word unused ; total 8 bytes, shl 3 bigthreshold equ 70 ; Z less than this makes a big star SECTION .text main: ; point es to vga memory push 0A000h pop es ; switch to graphics mode 13h mov ax,0013h ; INT10h AH=00h BIOS Set video mode int 10h ; mode 13h 320x200 8 bit single page ; don't clear screen, assume switching mode does that call randseed %macro for_all_stars 1 mov cx,numstars mov bx,stardata %%loop: call %1 ; assume function moves bx to next star loop %%loop %endmacro ; don't init stars, use whatever is already in memory ;for_all_stars resetstar .mainloop: ; process all stars for_all_stars updatestar ; check for keyboard input mov ah,01h ; haha bios function leaves keystroke in buffer int 16h ; so dos gets it too jz .mainloop ; out of mainloop, reset mode mov ax,0003h ; INT10h AH=00h BIOS Set video mode int 10h ; text 80x25 colour .exit: ; terminate to dos int 20h ; Initialise a star to a new location ; Entry: ; ds:bs points to star to init ; Exit: ; ax destroyed ; ds:bx points to next star resetstar: ; generate x call .gencoord ; generate y call .gencoord ; set z to 511-256 call rand and ax,00FFh add ax,256 mov [bx],ax add bx,4 ; next star ret .gencoord: call rand sar ax,1 mov [bx],ax add bx,2 ret ; Move and redraw a star ; Entry: ; ds:bx points to star to update ; Exit: ; no change updatestar: ; save pusha ; read star x and y, abuse si/di for temp storage mov si,[bx] add bx,2 mov di,[bx] add bx,2 ; read star z into cx which we'll be dividing by mov cx,[bx] cmp cx,0 jz .needreset ; get screen coordinates call getscreenxy ; determine painting attributes from z xor ax,ax cmp cx,bigthreshold setbe ah ; clear old star position (al=0 i.e. black, from xor) call drawstar ; update star z dec cx jz .needreset ; hit zero, time to spawn a new star to avoid singularity mov [bx],cx ; store back ; move back to start of star and re-read it sub bx,2 mov di,[bx] sub bx,2 mov si,[bx] ; cx has updated z coord, get screen new coordinates call getscreenxy ; check coordinates are inside screen bounds cmp si,0 jl .needreset cmp si,318 jg .needreset cmp di,0 jl .needreset cmp di,198 jg .needreset ; if star is too distant, skip it cmp cx,255 ja .skipdraw ; inside bounds, so draw mov dx,cx ; get 4 upper bits of distance shr dx,4 and dx,15 mov ax,15 ; distant stars (dx now large) must have small values (darker) sub ax,dx add ax,16 ; make 16-31 (grays in vga palette) xor ah,ah cmp cx,bigthreshold ; check size setbe ah call drawstar .skipdraw: ; restore popa add bx,8 ret .needreset: popa jmp resetstar ; Calculate the screen x/y of a star ; Entry: ; cx has z coordinate ; si has x coordinate ; di has y coordinate ; Exit: ; ax destroyed ; dx destroyed ; cx unchanged ; si has screen x coordinate ; di has screen y coordinate getscreenxy: %macro work 2 mov ax,%1 mov dx,%1 sar dx,16 idiv cx add ax,%2 mov %1,ax %endmacro work si,160 ; calculate star x screen coordinate work di,100 ; calculate star y screen coordinate %undef work ret ; Draw a star ; ; Entry: ; ah is size (0 small, else large) ; al is colour to use for drawing ; si is X coordinate ; di is Y coordinate ; es has vga memory segment ; Exit: ; ah destroyed ; dx destroyed ; di destroyed drawstar: ; set di = 320*di + si ; 320 = 101000000b mov dx,di shl di,2 add di,dx shl di,6 add di,si ; fill first pixel stosb ; check if big cmp ah,0 jne .big ret .big: stosb add di,318 mov ah,al stosw ret ; Seed random number generator ; ; Entry: ; nothing ; Exit: ; nothing randseed: ; save pusha ; get system time for seeding mov ah,2Ch ; INT21h AH=2Ch get system time int 21h ; stores hour/min in cx and sec/csec in dx ; store seed mov [.seed],dx ; restore popa ret .seed: dw 0 ; Get random bits ; ; Entry: ; nothing ; Exit: ; ax contains random bits rand: ; save (can't use pusha/popa since ax needs to be returned) push cx push dx ; load seed and multiplier mov ax,[randseed.seed] mov cx,16807 ; multiply mul cx ; add add ax,1 ; store new seed mov [randseed.seed],ax ; restore pop dx pop cx ret stardata: ; end of code, store star data here