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: ; init star data to zeroes mov di,stardata mov cx,numstars*4 xor ax,ax cld ; other STOcc ops also assume DF clear rep stosw ; 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 ; (also assume the palette is standard) ; let's just point the random seed to some uninited memory %define disable_randseed_func 1 %define randseed_loc therandomseed ; also the only place we use rand, we can afford dx destroyed %define rand_nosave_dx 1 %macro for_all_stars 1 mov cx,numstars mov bx,stardata %%loop: call %1 ; assume function moves bx to next star loop %%loop %endmacro .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 ; vga palette has 16-31 as black-white and dx,15 ; but we have small-large as close-distant mov ax,31 ; so invert our range and bring into 16-31 range sub ax,dx ; so we get a nice gradient as stars zoom closer 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 stosb stosb ret ; Seed random number generator ; ; Entry: ; nothing ; Exit: ; nothing randseed: %ifndef disable_randseed_func ; 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 %ifdef randseed_loc mov [randseed_loc],dx %else mov [.seed],dx %endif ; restore popa ret %endif %ifndef randseed_loc .seed: dw 0 %define randseed_loc randseed.seed %endif ; Get random bits ; ; Entry: ; nothing ; Exit: ; ax contains random bits rand: ; save %ifndef rand_nosave_cx push cx %endif %ifndef rand_nosave_dx push dx %endif ; load seed and multiplier mov ax,[randseed_loc] mov cx,16807 ; multiply mul cx ; add inc ax ; store new seed mov [randseed_loc],ax ; restore %ifndef rand_nosave_dx pop dx %endif %ifndef rand_nosave_cx pop cx %endif ret endofcode: therandomseed equ $ stardata equ $+4