Essence
From SizeCoding
Revision as of 23:18, 2 November 2019 by Trixter (talk | contribs) (Created page with "Category:Case Study Essence by Hellmood {{#ev:youtube|https://youtu.be/JqQbv12Dp9g}} As you might have guessed, real path tracing and lighting is (yet) impossible in 64...")
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.
Code:
; "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 https://deadline.untergrund.net/2019/
; published at https://www.pouet.net/prod.php?which=83204
; see also : http://www.sizecoding.org/wiki/Main_Page
; assemble with "nasm.exe" <this> -fbin -o <this>.com
; --------------------------------------------------------------
; Set ES to the screen, to perform the "Rrrola Trick", see
; http://www.sizecoding.org/wiki/General_Coding_Tricks
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.
; https://www.fountainware.com/EXPL/vga_color_palettes.htm
; 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
stosb
; 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
; http://vitaly_filatov.tripod.com/ng/asm/asm_002.29.html
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 #