From SizeCoding
Jump to: navigation, search

Essence by Hellmood

As you might have guessed, real path tracing and lighting is (yet) impossible in 64 bytes of assembler ;) but still, it's at least possible to generate the impression of both.


; "Essence" - by HellMood/DESiRE - 5th October 2019
; 64 bytes msdos intro, showing animated raycasted objects
; with fake pathtracing and fake lighting while playing
; ambient MIDI sound, which is coded for DosBox 0.74.
; On a real MsDos or FreeDos, the demo will work
; but no sound will be played unless a MIDI capable
; soundcard is present. On Dosbox, a custom configuration
; is needed, to provide sufficient emulation power and
; enable the MIDI UART mode, which saves a few bytes.
; --------------------------------------------------------------
; released at
; published at
; see also :
; assemble with "nasm.exe" <this> -fbin -o <this>.com
; --------------------------------------------------------------
; Set ES to the screen, to perform the "Rrrola Trick", see
push 0x9FF6
pop es
; Set mode to 0x13, +0x80 means not deleting the screen content
; that is 320x200 pixels in 256 colors
mov al,93h
int 10h
; Setting port to MIDI data port, assuming it is in UART mode
; 0x3F has to be sent to 0x331 first, if UART mode is not on.
mov dx,0x330
; Effectively outputting all the code to the MIDI data port.
; CX=255 at start, DS=CS, SI=0x100, see MIDI section below.
rep outsb
; Setting DS to zero, top stack normally contains the return
; adress. DS is needed to be 0 to access a timer later on.
pop ds
; CL is the iteration count for a ray, CH is 0 all the time.
; The value is chosen to generate a blue background texture.
; Chosing 64 instead would lead to a totally black background 
X: mov cl,63
; BL is the current depth of a ray, we start with minus(!) 64.
; We cast rays in negative direction to calculate the point
; in 3D and the texture color at the same time. if a ray hits
; an object from this side, the object function has a reasonable
; texture value, from the other side it would be always black.
; CL, BL are decoupled because decrementing -128 leads to 127
; and since we are using signed multiplication for keeping things
; centered, that would result in very buggy and ugly behaviour.
; They are also decoupled because of visual beauty: because of
; the usage of signed 8 bit coordinates, objects close to the
; projection center are way too coarse and move way too fast.
mov bl,-64
; At this point, AL contains the color of the previous pixel.
; By design of the object formula, the last 4 bits contain the
; texture value while the 5th bit is always set, which maps it
; to the 16 color gray scale subtable of the VGA default
; colors. Other bits may be set, too, so they are masked.
; Simultaneously, the object function, in combination with the
; palette subset, creates the impression of lighting from the
; front top left. The right, bottom and back side appears to
; be black. Changing the object formula will result in
; changing the texture, visibility and lighting as well.
and al,31
; Outputting the pixel on the screen and increment pointer
; Instead of going pixel by pixel, the following jumps
; Pseudorandomly across the screen, this smoothes the
; animation a lot and looks a bit like pathtracing.
imul di,byte 117
; The inner loop for each ray, decrementing BX means
; advancing the ray in negative direction by 1
L: dec bx
; Assign the Rrrola constant to register AX
mov ax,0xcccd
; Place the signed coordinates X and Y into DL and DH
mul di
; Centering for X is implicitly done by offsetting the segment
; Centering Y has to be done "manually". any value can be used
; as long as it doesn't show the signed overflow on screen.
mov al,dh
sbb al,73
; Multiply AL=Y by the current distance, to get a projection(1)
imul bl
; Get X into AL, while saving the result in DX (DH)
xchg ax,dx
; Multiply AL=X by the current distance, to get a projection(2)
imul bl
; Considering an implicit division by 256, the projected 
; coordinates now reside in DH and AH, while the depth is in BL.
; the following sequence calculates whether the current 3D
; position belongs to an object. Objects are normal cubes
; defined by f(X,Y,Z) = (X & Y & Z & 16 != 0)
mov al,dh
; offset X by timer, effectively producing 18.2 FPS
add ah,[0x46c]
and al,ah
and al,bl
test al,16
; the inner loop is done when either the iteration count has
; reached zero or the function f(X,Y,Z) is true (object hit)
loopz L
; the outer loop repeats endlessly
jmp short X
; MIDI Data Section, actually code above and memory below is
; sent to the MIDI data port as well, but it does not matter
db 0xc0 ; set instrument on channel 0 to the next value
db 89   ; instrument 89 = Pad2 of general MIDI
db 0x90 ; play notes on channel 0, minor chord over 4 octaves
db 28   ; note 1, very deep
db 127  ; volume 1, maximum value to let the subwoofers shake
db 59   ; note 2 fitting to note 1  
db 80   ; volume 2, a bit reduced to not overshadow the bass
db 67   ; note 3 fitting to notes 1 & 2
db 65   ; volume 3, even more reduced to fit the other notes
;      #                   ´                           #
;      #                   greetings                   #
;      #     sensenstahl,homecoded,rrrola,frag,T$      #
;      #     Optimus,Trixter,igor,gentleman,VileR      #
;      #     Whizart,g0blinish,Rudi,ryg,TomCat    .    #
;      #     orbitaldecay,wysiwtf,Kuemmel,p01,Lara     #
;      #     Oscar Toledo,Drift,maugli,Harekiet,etc    #