-
Notifications
You must be signed in to change notification settings - Fork 0
/
galaga.html
294 lines (243 loc) · 8.55 KB
/
galaga.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
<!doctype html>
<html>
<head>
<title>Galaga</title>
<script src="./scripts/jquery.js"></script>
<script src="./scripts/underscore.js"></script>
<script src="./scripts/webgl-utils.js"></script>
<script src="./game.js"></script>
<style type="text/css">
body {
padding: 0;
margin: 0;
}
#playground {
position: relative;
overflow: hidden;
}
#canvas {
position: absolute;
top: 0;
left: 0;
background: black;
}
#frame {
position:absolute;
top:0;
left:0;
}
.btn {
width: 300px;
height: 100px;
border: 1px dashed blue;
background: #def;
display: inline-block;
text-align: center;
padding-top: 50px;
font-size: 60px;
font-family: monospace;
}
.btn:hover {
background: #7df;
cursor: pointer;
}
#left_btn {
}
#right_btn {
}
#shoot_btn {
background: red;
}
</style>
</head>
<body>
<canvas id="canvas" width="1024" height="1024"></canvas>
<canvas id="playground" width="1024" height="1024"></canvas>
<div id="buttons">
<div class="btn" id="left_btn">LEFT</div>
<div class="btn" id="right_btn">RIGHT</div>
<div class="btn" id="shoot_btn">SHOOT</div>
</div>
<img src="assets/frame.png" id="frame"/>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
uniform float u_rotation;
uniform vec2 u_center;
varying vec2 v_texCoord;
vec2 doRotation (vec2 ipos, float r) {
return vec2 (
ipos.x*cos (r) - ipos.y*sin (r),
ipos.x*sin (r) + ipos.y*cos (r));
}
void main() {
vec2 zeroToOne = doRotation (a_position / u_resolution, u_rotation );
vec2 centerPos = u_center / u_resolution;
vec2 vPos = ((zeroToOne + centerPos)*2.0 - vec2 (1.0, 1.0)) ;
gl_Position = vec4(vPos * vec2(1, -1)*vec2(0.8, 0.8), 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
// our texture
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>
<script id="2d-tv-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4 (a_position, 0, 1);
v_texCoord = a_texCoord;
}
</script>
<script id="2d-tv-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
// our texture
uniform sampler2D u_image;
uniform sampler2D u_noise;
uniform float u_time;
uniform vec2 u_resolution;
#define M_PI (3.1415926535897932384626433832795)
#define iGlobalTime u_time
#define iResolution u_resolution
#define iChannel0 u_image
#define iChannel1 u_noise
#define iChannelResolution u_resolution
float qScanLine (vec2 uv, float n) {
return abs (sin (uv.y*M_PI*n)) ;
}
float qVignete (vec2 uv,float q, float o) {
float x = clamp (1.0 - distance (uv, vec2 (0.5,0.5))*q, 0.0, 1.0);
return (log((o - 1.0/exp (o))*x + 1.0/exp (o)) + o)/(log(o) + o);
}
vec2 vCrtCurvature (vec2 uv, float q) {
/*float x = 1.0- distance (uv, vec2 (0.5, 0.5));
vec2 g = vec2 (0.5, 0.5) - uv;
return uv + g*x*q ;*/
vec2 cuv = (uv - vec2 (0.5, 0.5))*2.0;
float d = distance (cuv, vec2 (0.0));
cuv = (cuv + cuv*d*0.5)*0.75;
return clamp (cuv/2.0 + vec2 (0.5, 0.5),0.0,1.0);
}
vec3 v2DNoiseSample (vec2 gPos) {
vec2 nPos = vec2(
mod (gPos.x+iGlobalTime*9.66,1.0),
mod (gPos.y+iGlobalTime*7.77,1.0)
);
return texture2D (iChannel1, nPos).xyz;
}
vec3 v1DNoiseSample (float idx, float s) {
return texture2D (iChannel1, vec2 (
mod (idx, 1.0),
mod (iGlobalTime*s, 1.0))
).xyz;
}
float q2DNoiseSample (vec2 gPos) {
vec3 nPnt = v2DNoiseSample (gPos);
return (nPnt.x + nPnt.y + nPnt.z) / 3.0;
}
float q1DNoiseSample (float idx, float s){
vec3 nPnt = v1DNoiseSample (idx, s);
return (nPnt.x + nPnt.y + nPnt.z) / 3.0;
}
vec3 cSignalNoise (vec3 c,float q, vec2 gPos) {
return c*(1.0 - q) + q*q2DNoiseSample(gPos);
}
vec2 vScanShift (vec2 uv, float q, float dy, float dt) {
return vec2 (uv.x + q1DNoiseSample (uv.y*dy, dt)*q, uv.y);
}
vec2 vFrameShift (vec2 uv, float q, float dt) {
float s = (q1DNoiseSample (0.5, dt) - 0.5)/500.0;
return vec2 (uv.x, mod (uv.y + iGlobalTime*(q+s), 1.0));
}
vec2 vDirShift (vec2 uv, float angle, float q) {
float a =(angle/180.0)*M_PI;
vec2 dir = vec2 (sin (a), cos (a));
return uv + dir*q;
}
vec3 vRGBWithShift (vec2 uv, float angle, float q) {
vec2 rPos = vDirShift (uv, angle, q);
vec2 gPos = uv;
vec2 bPos = vDirShift (uv, -angle, q);
vec4 rPix = texture2D (iChannel0, rPos);
vec4 gPix = texture2D (iChannel0, gPos);
vec4 bPix = texture2D (iChannel0, bPos);
return vec3 (rPix.x, gPix.y, bPix.z);
}
vec3 vPowerNoise (vec3 col, vec2 uv, float b, float dt, float w) {
float s = q1DNoiseSample (0.0, 0.001)/500.0;
float y = mod (iGlobalTime * (dt + s) , 1.0);
float d = 1.0 - clamp (abs (uv.y - y), 0.0, w)/w;
return pow (col,vec3(1.0/(1.0 + b*d)) ) ;
}
vec3 qGamma (vec3 i, vec3 g){
return pow(i, 1.0/g);
}
vec3 vRGBTint (vec3 col, vec3 g, float q) {
return qGamma (col, g)*q + (1.0 - q)*col;
}
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec3 vColorDrift (vec3 col, float q) {
vec3 hsv = rgb2hsv (col.xyz);
hsv.y = mod (hsv.y * q, 1.0);
return vec3 (hsv2rgb (hsv));
}
vec3 vStar (vec3 sPix, vec2 gPos) {
vec4 nPix = texture2D (iChannel1, vec2 (gPos.x/3.0, mod (gPos.y/3.0 + iGlobalTime/50.0,1.0)));
float g = (nPix.x + nPix.y + nPix.z)/3.0;
float d = distance (sPix, vec3 (0.0));
if (g > 0.98 && d < 0.05) {
return nPix.xyz;
}
return sPix;
}
void main(void)
{
vec2 cRes = iChannelResolution.xy;
vec2 gRes = iResolution.xy;
vec2 gPos = gl_FragCoord.xy / gRes;
vec2 cPos = gPos ;
vec3 cCol = vec3(1.0);
vec2 bPos = vec2(1.0);
float qNoise = q1DNoiseSample(0.01,0.01);
cPos = vScanShift (cPos, 0.01, 0.5, 0.1); // scanline shift
cPos = vCrtCurvature (cPos, 0.3); // crt curving of coords
bPos = vCrtCurvature (gPos, 0.3); // curvature for the noize bar
cPos = vFrameShift (cPos, -0.0, -0.0); // frame shift
cCol = vRGBWithShift (cPos, 120.0, 0.002); // sample signal color
cCol = vStar (cCol, cPos);
cCol = vColorDrift (cCol, 0.5 + 0.5*(1.0 - qNoise));
cCol = cSignalNoise (cCol, qNoise * 0.4, gPos); // add signal noise
cCol = vPowerNoise (cCol, bPos, 4.0, -0.2, 0.1); // power line noize
cCol = vRGBTint (cCol, vec3 (0.5, 0.8, 0.9), 1.0); // gamma tint
cCol = cCol * qScanLine (gPos, 256.0); // add scanlines
cCol = cCol * qVignete (gPos, 1.5, 3.0); // add edge darkening
gl_FragColor = vec4 (cCol, 1.0);
}
</script>
</body>
</html>