-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path2013-spring-comanche.html
122 lines (101 loc) · 6.03 KB
/
2013-spring-comanche.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>JS1k, 1k demo submission [ID]</title>
<meta charset="utf-8">
</head>
<body>
<canvas id="c"></canvas>
<script>
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
</script>
<script>
// start of submission //
/*
* global variables
*
* h : current hour, in radians (2.pi = 24h)
* i : helicopter altitude (Y coordinate)
* l : helicopter X coordinate
* m : helicopter Z coordinate
* p : terrain heightmap
* v : array of helicopter controls
* G : helicopter yaw
* R : helicopter roll
* S : helicopter speed
*/
i=c.width=c.height=512; // resize canvas and set altitude
/* landscape generation */
v=p=[];
for (S=R=t=x=y=0;256>y;y+=!(x=x+1&255)) // 2-in-1 loop on x and y
p.push(Math.min(1,52-55*Math.cos(x/40-Math.sin(y/40)))-1); // initialize the heightmap with a sine-shaped river over a flat land
for (n=0;++n-5e5;t=13*t+2+9*Math.cos(t)&-1) { // 500.000 steps of pseudo-random walk
x+=[0,1,0,-1][t&3]; // not using actual random() to always generate the same heightmap
y+=[0,1,0,-1][3-t&3];
v[t&3]=0; // use the loop to initialize the controls as well
for (l=-3;++l-3;G=h=11) for(m=-3;++m-3;) // 11 ~ -1.57 radian : start at dawn, facing the sunset
p[256*(y+m&255)+(x+l&255)]+=.01; // raise the land around : flat convolution filter
}
m=-115; // start at (3, -115) on the river bank
setInterval( function (t) {
S=S*.97+2*v[2]-2*v[0]; // alter speed when tilted forward or backward
x=y=0;
l+=S*Math.cos(G=Math.atan2(Math.sin(G),Math.cos(G))+R); // restrict yaw in [-pi, pi] as its raw value is used to position the sun
m+=S*Math.sin(G);
r = 55;
R=R/2+v[1]-v[3];
i=.9*i+5+5*Math.max(0,p[256*(y+m&255)+(x+l&255)]); // altitude autopilot, always fly above the ground
/* sky color */
t = a.createLinearGradient(256+256*R*30,-200*S,256,256-200*S); // sky gradient
g = 118+112*Math.cos(h+=1/256); // zenith color
b = 55+200*Math.max(0,Math.min(1,4*Math.cos(h)));
t.addColorStop(0, "rgba("+(r&255)+","+(g&255)+","+(b&255)+",255)");
g = 255*Math.max(0,Math.cos(h-.2)); // horizon color
b = 55+200*Math.max(0,Math.min(1,3*Math.cos(h+.5)));
r = 220*Math.max(0,Math.min(1,.5+2*Math.cos(h)));
t.addColorStop(1, "rgba("+(r&255)+","+(g&255)+","+(b&255)+",255)");
a.fillStyle=t;
a.fillRect(0,0,512,512);
/* sun color and halo */
d = 432*G-672*Math.sin(h); // sun X screen coordinate, needs yaw (G) in [-pi, pi]
w = 256-200*S+d*R*30-384*Math.cos(h); // sun Y screen coordinate, even below the horizon
t = a.createRadialGradient(256+d, w, 256, 256+d, w, 25);
r = 255; // sun color
g = 255*Math.max(0,Math.cos(h));
b = 55+200*Math.max(0,Math.cos(h));
t.addColorStop(0, "rgba("+(r&255)+","+(g&255)+","+(b&255)+",0)");
t.addColorStop(.95, "rgba("+(r&255)+","+(g&255)+","+(b&255)+",128)");
b = g; // sun halo
g = 100+155*Math.sqrt(Math.max(0,Math.cos(h))); // gradient goes from sun color to transparent halo
t.addColorStop(1, "rgba("+(r&255)+","+(g&255)+","+(b&255)+",255)");
a.fillStyle = t;
a.fillRect(0,0,512,512);
/* draw the landscape */
for (d=-256; 256>d; d+=8) // step size adjusted to get a reasonable framerate
for (f=512, e=1; ++e-200; ) { // initialize y-buffer, drawing front to back
x=e*Math.cos(G)+e*Math.sin(G)*d/400; // (x,y) matching world coordinate
y=-d/400*e*Math.cos(G)+e*Math.sin(G);
n=Math.max(0,p[256*(y+m&255)+(x+l&255)]); // altitude at (x,y)
w=256-200*S+d*R*30-384*2*n/e+15*i/e; // pixel height of the hill
if(f>w) { // y-buffer : only plot landscape visible behind the pixels already drawn
++y; // shadow computed from altitude difference along Y and sun direction
t=Math.max(0,Math.min(1,.4+(n-Math.max(0,p[256*(y+m&255)+(x+l&255)]))*Math.sin(h)));
r=g=255*Math.max(0,Math.cos(h)); // land color at horizon, dark blue at night, white at noon
b=55+200*Math.max(0,Math.cos(h));
x=n/20; // grass color (n/20, n/20+0.5, n/20) : green at water level, white at altitude
r *= (x*(1-e/200)+e/200)*t; // water color (0/20, 0/20+0.5, 1)
x+=.5; g*=(x*(1-e/200)+e/200)*t;
x=n/20||1;b *= (x*(1-e/200)+e/200)*t; // blend color depending on distance and shadow
a.fillStyle="rgba("+(r&255)+","+(g&255)+","+(b&255)+",255)";
a.fillRect(256+d,w,8,f+1-(f=w));
}
}
}, 40); // target 25 FPS
onkeydown = function(t) {v[t.keyCode&3]=.01;};
onkeyup = function(t) {v[t.keyCode&3]=0;}
// end of submission //
</script>
</body></html>