Skip to content

Instantly share code, notes, and snippets.

@ohAitch
Last active March 8, 2020 06:25
Show Gist options
  • Save ohAitch/187fd864cd9976b230e7c123a724ac10 to your computer and use it in GitHub Desktop.
Save ohAitch/187fd864cd9976b230e7c123a724ac10 to your computer and use it in GitHub Desktop.
// Adapted from https://fabiensanglard.net/rayTracing_back_of_business_card/
#include <stdlib.h> // card > aek.ppm
#include <stdio.h>
#include <math.h>
#include <time.h>
typedef int i;typedef float f;struct v{
f x,y,z;v operator+(v r){return v(x+r.x
,y+r.y,z+r.z);}v operator*(v r){return
v(x*r.x,y*r.y,z*r.z);}v operator*(f r){return
v(x*r,y*r,z*r);}f operator%(v r){return
x*r.x+y*r.y+z*r.z;}v(){}v operator^(v r
){return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.
y-y*r.x);}v(f a,f b,f c){x=a;y=b;z=c;}v
operator!(){return*this*(1/sqrt(*this%*
this));}};i G[]={247951,133265,67729,36623,18433,247809,2062};
f R(){return(f)rand()/RAND_MAX;}
static i WH = 512;
static i GAP = 51;
static i RAYS = 1;
static i gap = 0;
static i iters = 0;
static v letr(0,0,4);
void regap(){GAP =
// WH*WH*RAYS <= 1<<16 ? 7 :
WH*WH*RAYS <= 1<<17 ? 21 :
WH*WH*RAYS <= 1<<20 ? 51 :
WH*WH*RAYS <= 1<<23 ? 171 :
/* else */ 667 ;}
extern "C" void scoot(f scoot){letr = v(0,0,scoot); iters=0;RAYS=1;regap();}
i T(v o,v d,f&t,v&n){t=1e9;i m=0;f p=-o.z/d.z;
if(.01<p)t=p,n=v(0,0,1),m=1;
for(i k=19;k--;)for(i j=7;j--;)if(G[j]&1<<k){
v p=o+(v(k,0,j)+letr)*-1;f b=p%d,c=p%p-.9,q=b*b-c;
if(q>0){f s=-b-sqrt(q);
if(s<t&&s>.01)t=s,n=!(p+d*t),m=2+(1&(j^k));}}
return m;}
v S(v o,v d){f t;v n;i m=T(o,d,t,n);if(!m)return
v(.7,.6,1)*1*pow(1-d.z,4);
v h=o+d*t,l=!(v(9+R(),9+R(),16)+h*-1),r=d+n*(n%d*-2);f b=l%n;
if(b<0||T(h,l,t,n))b=0;f p=pow(l%r*(b>0),99);
if(m<2){h=h*.2;return(
(i)(ceil(h.x)+ceil(h.y))&1?v(3,1,1):v(3,3,3))*(b*.2+.1);}
return v(1,1,1)*p+S(h,r)*.5;}
extern "C" void reset(i wh){WH=wh;RAYS=1;regap(); iters=0;}
extern "C" i gaps(){return GAP;}
i main(){
if(!iters) iters=GAP+1;
gap+=2*384+1;
printf("%d\t", gap);
// printf("%d\n", RAND_MAX); return 0;
// printf("P6 256 256 255 ");
v g=!v
(-6,-16,0),a=!(v(0,0,1)^g)*(1./WH),b=!(g^a
)*(1./WH),c=(a+b)*-(WH*.5)+g;
for(i y=WH;y--;)for(i x=WH;x--;){if(gap--) continue; gap = GAP;
v p(0,0,0);
for(i r=RAYS;r--;){v t=(a*(R()-.5)*99+b*(R()-.5)*99)*fmax(1.,log2(RAYS)/3.)*(WH/512.);
p=S(v(16,16,8)+t,!(t*-1+(a*(R()+x)+b*(y+R())+c)*16))*(64/RAYS)*3.5+p;}
printf("%d\t",(0xff&(i)p.x) + 0x100*(0xff&(i)p.y) + 0x10000*(0xff&(i)p.z));
// printf("%d %d %d\t",0xff&(i)p.x,0xff&(i)p.y,0xff&(i)p.z);
}printf("\n");
if(!--iters) {
if(RAYS>=64) puts("\n");
else {printf("%d\n", RAYS); RAYS*=2; regap();}
}
}
%init-scripts%
<style>
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
div {
position: absolute;
left: 10px;
right: 10px;
top: 10px;
bottom: 10px;
padding: 10px;
background-color: aliceblue;
overflow: auto;
}
pre {
margin: 0px;
}
</style>
<div>
<button onclick="window.rr()">go</button>
<button onclick="clearTimeout(window.todo)">stop</button>
<br>Size:
<input type=radio onchange="rr()" name=dim value=256>256</input>
<input type=radio onchange="rr()" name=dim value=384>384</input>
<input type=radio onchange="rr()" name=dim value=512 checked>512</input>
<input type=radio onchange="rr()" name=dim value=768>768</input>
<br> Letters up <input type=range id=letr min=-100 max=200 value=40
oninput="rp({letter:this.value/10})" />
<output id=letrOut>4.0</output>
<br>
<canvas id=out></canvas>
<pre id='consoole'><br></pre>
</div>
<script src=https://unpkg.com/osc-js@2.0.4/lib/osc.min.js ></script>
<!-- <script>
osc = new OSC()
osc.open()
osc.on("*",({address, args}) => {
// console.log(address, ...args)
window.rp({letter:30*args[0]-10})
})
</script> -->
<script>
'use strict';
let n = 0;
let t0 = Date.now()
let t = t0
let out = document.getElementById('out');
out.width = out.height = 768
let compose = out.getContext("2d");
let scratch = new OffscreenCanvas(out.width, out.height)
let draw = scratch.getContext("2d");
let raw = new OffscreenCanvas(out.width, out.height).getContext("2d");
out.width = out.height = 512
window.rp = ({letter})=> {
consoole.textContent = consoole.textContent.replace(/\n[.\n]*/g,'')
letr.value = letter*10;
letrOut.value = letter.toFixed(1)
let dim = out.width
if(Date.now()<window.rp.throttle){
clearTimeout(window.rp.timeout)
return window.rp.timeout = setTimeout(
()=> window.rp({letter}), window.rp.throttle-Date.now()
)
}
window.rp.throttle = Date.now()+dim/15
raw.save(); {
raw.globalCompositeOperation = "multiply"
raw.fillStyle = "#f3f3f3"
raw.fillRect(0,0,dim,dim)
}; raw.restore()
n=0, t0 = Date.now(), clearTimeout(window.todo)
wasmExports.scoot(letr.value/10)
wasmExports.main()
}
let $ = document.querySelector.bind(document)
window.rr = ()=> {
consoole.textContent = ''
let dim = +$('[name="dim"]:checked').value
n=0, t0 = Date.now(), clearTimeout(window.todo)
let ddim = out.width
out.width = out.height = dim
raw.width = raw.height = scratch.width = scratch.height = out.width
if(dim!=ddim) raw.clearRect(0,0,dim,dim)
wasmExports.reset(dim)
wasmExports.main()
}
let premultiply = new OffscreenCanvas(out.width, out.height).getContext("2d")
let consoole = document.getElementById('consoole');
emModule.printErr = emModule.print = msg => {
try {
if(!msg) return clearTimeout(window.todo)
if(msg.length<100){
if(msg==+msg){consoole.textContent += ` ${msg}rpp\n`; n=0}
else { console.warn(msg)}
return
}
let tt = Date.now()
consoole.textContent = consoole.textContent.replace(
/.*$/, `${(1000/(tt-t))|0}fps ${n++} ${(t-t0)/1000}s`
)
t=tt
// console.log(msg)
draw.globalCompositeOperation = 'copy'
draw.fillStyle = `#131313`
draw.fillRect(0,0,out.width,out.height)
let buf = new Uint32Array(
raw.getImageData(0,0,out.width,out.height).data.buffer
)
let i = null;
let gap = wasmExports.gaps()
msg.split('\t').forEach(s => {
if(i==null) return i=+s
buf[i]=0xff*0x1000000+(+s); i+=1+gap
// let [r,g,b]= s.split(' ').map(n=>+n)
// buf[i]=0xff*0x1000000+(b*0x10000+g*0x100+r); i+=1+gap
})
raw.putImageData(
new ImageData(
new Uint8ClampedArray(buf.buffer)
,out.width,out.height)
,0,0)
draw.globalCompositeOperation = 'lighter'
draw.drawImage(raw.canvas,0,0)
draw.globalCompositeOperation = 'destination-in'
draw.drawImage(raw.canvas,0,0)
{
let empty = (gap-n)/gap
compose.filter = `blur(${(1+8*empty)*(out.height/256)}px)`
compose.globalCompositeOperation = 'lighten'
{
compose.globalCompositeOperation = 'multiply'
compose.fillStyle = `#444`
compose.fillRect(0,0,out.width,out.height)
}
compose.globalCompositeOperation = 'lighten'
compose.drawImage(draw.canvas,0,0)
compose.filter = "none"
}
compose.globalCompositeOperation = 'source-over'
compose.drawImage(scratch,0,0)
clearTimeout(window.todo)
window.todo=setTimeout(()=> wasmExports.main(), 2)
} catch(e){
console.warn(e)
debugger
}
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment