; ; TinyDemo, Andreas Agorander ; Begin 2002-10-21 ; Graphics demo made to fit on the bootsector of a diskette ; (that is, I have 510 byte to do something with) ; ; Compile with 'nasm -fbin -o demo demo.asm' ; Put on bootsector with 'dd if=demo of=/dev/fd0' ; ; The demo does a couple of things: ; It renders the "mandelbrot" fractal into a sprite ; area, and continuously uses this as texture for a ; simple raycasted tunnel. ; ; The view goes forward and wobbles sideways in the tunnel ; [CPU 686] ;Uninitialized dataarea adress constants sprite equ 32768 pxline equ 49150 pxheight equ 49152 [BITS 16] [ORG 0x0] init: ; ------------------------------------------------------ ; Here we are making our register and data initializing ; ------------------------------------------------------ ; Init our datasegment, the code loaded may be max 510 byte, but ; I intend to use a lot more of data mov ax, 0x7C0 mov ds, ax ; Init stack area mov ax, 0x9000 mov ss, ax mov sp, ax ; Enter gfxmode,320x200 8bit colors mov ax, 0x13 int 0x10 ; Lets set up our pointer to VGA graphics area mov ax, 0xA000 mov es, ax ; ---- End init ---- ; ------------------------------------------------------------------------ ; This is the main loop ; ------------------------------------------------------------------------ round: mov bp,64 rmand: call rendermandelbrot dec bp jnz rmand call renderraycast call movearound jmp round ; ------------------------------------------------------------------------ ; Now, this is the mandelbrot render part ; It renders to an area 128x128 pixels ; ------------------------------------------------------------------------ rendermandelbrot: finit ;First, calculate the floating point value of the current ; pixel -2 to 2 for 0-127 fld1 ;ST0 = 1 fidiv word [fdivc] ;ST0 = 1/32 fst ST1 ;ST1 = 1/32 fimul word [curx] ;ST0 = 1/32*curx fisub word [two] ;ST0 = 1/32*curx-2 fst ST6 ;ST6 = --- " --- fxch ;ST0 = 1/32 , ST1 = 1/16*curx-4 fimul word [cury] ;ST0 = 1/32*cury fisub word [two] ;ST0 = 1/32*cury-2 fst ST7 ;ST7 = --- " --- ; cury is now in ST0 and curx in ST1 ; max 32 iterations for the pixel mov cx, [numiter] iteration: ;The new values for the pixel is calculated ;curx is the real part and cury the imaginary part ; Formula : ; curx = curx^2 - cury^2 + curx ; cury = 2*curx*cury + cury ; ST0 = ST7 = cury ; ST1 = ST6 = curx fst ST2 ;cury fxch fst ST3 ;curx ; ST0 = ST3 = ST6 = curx ; ST1 = ST2 = ST7 = cury fmul ST0 ;ST0 = curx^2 fxch ;ST0 = cury , ST1 = curx^2 fmul ST0 ;ST0 = cury^2 fxch ;ST0 = curx^2 , ST1 = cury^2 fsub ST1 ;ST0 = curx^2 - cury^2 fadd ST6 ;ST0 = curx^2 - cury^2 + curx fst ST4 ;ST4 = curx^2 - cury^2 + curx ; ST0 = ST4 = curx^2 - cury^2 + curx ; ST1 = curx^2 ; ST2 = ST7 = cury ; ST3 = ST6 = curx ; Now for the imaginary part fxch ST2 ;cury -> ST0 fmul ST3 ; cury*curx fimul word [two] ; 2*cury*curx fadd ST7 ; 2*cury*curx + cury ; ST0 = 2*cury*curx + cury ; ST1 = curx^2 ; ST2 = curx^2 - cury^2 + curx ; ST3 = ST6 = curx ; ST4 = curx^2 - cury^2 + curx ; ST7 = cury ; Now ST0 contains the new cury and ST4 contains the new curx ; Time to check if the distance from origo is more than 2 fst ST2 ;cury -> ST2 fabs fxch ST4 fst ST3 ;curx -> ST3 fabs fadd ST4 ficom word [two] fstsw ax sahf ja enditer fxch ST3 fxch ST1 fxch ST2 ; Next iteration loop iteration enditer: ; Calculate pixel position in sprite mov si, sprite mov ax, [cury] shl ax, 7 add si, ax mov bx, [curx] add si, bx ; Paint pixel mov [si], cl ; Now increase curx and cury to correct values shr ax, 7 ;cury inc al jns contx xor ax, ax inc bl jns contx xor bx, bx rol byte [numiter], 1 contx: mov [curx], bx mov [cury], ax ret ; ---- End ---- ; -------------------------------------------------------- ; Render a textured tunnel ; -------------------------------------------------------- renderraycast: ;Raycast a tunnel with all sides square, textured with the ;Mandelbrot sprite finit fild word [wobble2] fldpi fidiv word [heighty] fild word [wobble] fild word [view] fidiv word [scrwidth] fmul ST2 ;Convert to radians fild word [startang] fmul ST3 ;Convert to radians ; ST0 = start angle ; ST1 = decrease in angle for new column ; ST2 = distance from left wall ; ST3 = pi/180 ; ST4 = distance from right wall leftwall: ; Render the 159 leftmost columns mov cx, 159 mov dx, 0 ;dx = current column leftloop: fst ST5 ;Save current angle fptan fincstp ffree ST7 fst ST6 fdivr ST2 ;ST2/ST0 -> ST0 call texture push dx mov ax, 319 sub ax, dx mov dx, ax fxch ST6 fdivr ST4 call texture pop dx inc dx fxch ST5 ;restore current angle fsub ST1 ;Change angle loop leftloop ret texture: fist word [pxline] fidiv word [scrwidth] ;Scale distance ;The distance is now in ST0, we need to ;Calculate the height now ;The height is 180/distance ;But first we store the distance to an integer ;So we know what line in our sprite we shall ;render fidivr word [heighty] ;Now we have a workable height for our textures fist word [pxheight] ;Now it's time for some integer math for texturing ;Where in our texture do we start? mov si, sprite mov di, dx push dx xor dx, dx mov ax, [pxline] shr ax, 2 add ax, [addoffs] mov bx, 128 div bx add si, dx mov bx, [pxheight] ;Now we want the spritepixel increase per screen ;pixel, and to that in integer by getting that ;value shifted left << 16 mov ax, 128 shl eax, 16 xor edx, edx div ebx ;Now eax contains spritepixels per screenpixel << 16 cmp bx, 200 jb simple ;If we are inside this part of the code the height is ;"above" the screen, so we need to figure out how big ;offset in the sprite it is before the screen starts mov bp,bx sub bp,200 shr bp,1 ; bp now contains the amount of surplus pixels on the top ; multiplicating with ax gives the offset down to be added push ax mul bp ;Now dx contains the offset to be added, but of course, it ;needs to be shifted left 7 steps (128 pixels per row in sprite) shl dx, 7 add si, dx pop ax jmp nosimple simple: ;Here the wall is lower than the screen, so we need to change ;di and paint the leftover black : ; (height-200)/2 ; push cx mov dl, 0 mov cx, 200 sub cx, bx shr cx, 1 jz psmloop smloop: mov [es:di] ,dl add di, 320 loop smloop psmloop pop cx nosimple: ;Now we loop through all pixels on row until no more height or ;No more screen xor ebp, ebp lineloop: push ax mov al, [si] mov [es:di],al pop ax add ebp, eax ror ebp, 16 shl bp, 7 add si, bp xor bp, bp ror ebp, 16 add di, 320 dec bx jz endtxt check: cmp di,64000 jb lineloop endtxt: push ax mov al, 0 endl: cmp di,64000 jae endd mov [es:di], al add di,320 jmp endl endd: pop ax pop dx ret ; --------------------------------------------------------- ; Moves view ; --------------------------------------------------------- movearound: inc byte [addoffs] xor ecx, ecx mov ecx, 64 mov eax, [wlowbits] shr eax, 16 sub ecx, eax imul ecx, 4 add [wspd], ecx mov ecx, [wspd] add [wlowbits], ecx sub [wlowbits2], ecx ret ; --------------------------------------------------------- ; Variables with initialized values ; --------------------------------------------------------- startang: fdivc: dw 32 two: dw 2 wlowbits:dw 0 wobble: dw 10 wlowbits2:dw 0 wobble2:dw 118 wspd: dd 0 curx: dw 0 cury: dw 0 scrwidth:dw 320 view: dw 64 heighty:dw 180 addoffs:dw 0 numiter:dw 1 ;Pad with zero until there is only 2 bytes left on sector ;times 510-($-$$) db 0 ; Not needed now because the program is the exakt correct size anyway ;Boot signature, (needed for the sector to load at boot-time) dw 0xAA55