|
1 <!DOCTYPE html> |
|
2 <html> |
|
3 <head> |
|
4 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
5 <script type="text/javascript"> |
|
6 |
|
7 var ripples = { |
|
8 frame: 0, |
|
9 |
|
10 get frames() { |
|
11 return this.frame; |
|
12 }, |
|
13 |
|
14 // Size of buffer. |
|
15 width: 80, |
|
16 height: 80, |
|
17 |
|
18 // Render size. |
|
19 renderWidth: 1200, |
|
20 renderHeight: 700, |
|
21 |
|
22 // Canvas size. |
|
23 canvasWidth: 1200, |
|
24 canvasHeight: 700, |
|
25 |
|
26 // Ripple start points. |
|
27 ripplePoints: [ |
|
28 {x:0.5,y:0.5,start:0}, |
|
29 {x:0.2,y:0.3,start:0}, |
|
30 {x:0.7,y:0.6,start:0}, |
|
31 {x:0.2,y:0.2,start:4000}, |
|
32 {x:0.7,y:0.2,start:6000}, |
|
33 {x:0.2,y:0.8,start:8000}, |
|
34 {x:0.5,y:0.3,start:12000}, |
|
35 {x:0.2,y:0.6,start:16000}, |
|
36 {x:0.8,y:0.2,start:20000}, |
|
37 {x:0.3,y:0.8,start:24000}, |
|
38 {x:0.6,y:0.2,start:28000} |
|
39 ], |
|
40 |
|
41 a: false, // previous frame |
|
42 b: false, // frame before previous frame |
|
43 |
|
44 pixelWidth: 0, |
|
45 pixelHeight: 0, |
|
46 |
|
47 init: function() { |
|
48 // Get start time. |
|
49 var d = new Date(); |
|
50 this.startTime = d.getTime(); |
|
51 |
|
52 // Pixel sizes. |
|
53 this.pixelWidth = Math.floor(this.renderWidth / this.width); |
|
54 this.pixelHeight = Math.floor(this.renderHeight / this.height); |
|
55 |
|
56 // Top left corner position of the rendered effect. |
|
57 this.xPosition = this.canvasWidth / 2 - (this.pixelWidth * this.width) / 2; |
|
58 this.yPosition = this.canvasHeight / 2 - (this.pixelHeight * this.height) / 2; |
|
59 |
|
60 |
|
61 // Init canvas. |
|
62 var canvas = document.getElementById('ripples'); |
|
63 this.ctx = canvas.getContext('2d'); |
|
64 |
|
65 // Create buffers. |
|
66 this.a = new Buffer(this.width, this.height); |
|
67 this.b = new Buffer(this.width, this.height); |
|
68 |
|
69 }, |
|
70 |
|
71 processBuffers: function() { |
|
72 var damping = 0.02; |
|
73 for (var x = 2; x < this.width - 2; x++) { |
|
74 for (var y = 2; y < this.height - 2; y++) { |
|
75 this.b.set(x, y, |
|
76 ( |
|
77 this.a.get(x - 2, y) |
|
78 + this.a.get(x + 2, y) |
|
79 + this.a.get(x, y - 2) |
|
80 + this.a.get(x, y + 2) |
|
81 + this.a.get(x - 1, y) |
|
82 + this.a.get(x + 1, y) |
|
83 + this.a.get(x, y - 1) |
|
84 + this.a.get(x, y + 1) |
|
85 + this.a.get(x - 1, y - 1) |
|
86 + this.a.get(x + 1, y + 1) |
|
87 + this.a.get(x + 1, y - 1) |
|
88 + this.a.get(x - 1, y + 1) |
|
89 ) / 12 * 2 - this.b.get(x, y)); |
|
90 this.b.set(x, y, this.b.get(x, y) - this.b.get(x, y) * damping); |
|
91 } |
|
92 } |
|
93 }, |
|
94 |
|
95 render: function() { |
|
96 |
|
97 for (var x = 2; x < this.width - 2; x++) { |
|
98 for (var y = 2; y < this.height - 2; y++) { |
|
99 |
|
100 var color = this.b.get(x, y); |
|
101 |
|
102 var progress = color / 256; |
|
103 var rMin = 0, rMax = 255, |
|
104 gMin = 0, gMax = 255, |
|
105 bMin = 0, bMax = 255; |
|
106 |
|
107 var rDelta = (rMax - rMin) / 2; |
|
108 var rValue = Math.round(rMin + rDelta + rDelta * progress); |
|
109 var gDelta = (gMax - gMin) / 2; |
|
110 var gValue = Math.round(gMin + gDelta + gDelta * progress); |
|
111 var bDelta = (bMax - bMin) / 2; |
|
112 var bValue = Math.round(bMin + bDelta + bDelta * progress); |
|
113 this.ctx.fillStyle = "rgb("+rValue+", "+gValue+", "+bValue+")"; |
|
114 this.ctx.fillRect(this.xPosition + x * this.pixelWidth, |
|
115 this.yPosition + y * this.pixelHeight, |
|
116 this.pixelWidth, |
|
117 this.pixelHeight); |
|
118 } |
|
119 } |
|
120 }, |
|
121 |
|
122 swapBuffers: function() { |
|
123 var c = this.b; |
|
124 this.b = this.a; |
|
125 this.a = c; |
|
126 }, |
|
127 |
|
128 clear: function() { |
|
129 this.ctx.clearRect(0, 0, this.width, this.height); |
|
130 }, |
|
131 |
|
132 addRipple: function(time) { |
|
133 |
|
134 var ripplePoints = new Array(); |
|
135 for (var i = 0; i < this.ripplePoints.length; i++) { |
|
136 if (this.ripplePoints[i].start < time) { |
|
137 this.a.sphere( |
|
138 Math.floor(this.width * this.ripplePoints[i].x), |
|
139 Math.floor(this.height * this.ripplePoints[i].y), |
|
140 Math.floor(this.width * 0.1), 256); |
|
141 } else { |
|
142 ripplePoints.push(this.ripplePoints[i]); |
|
143 } |
|
144 } |
|
145 this.ripplePoints = ripplePoints; |
|
146 |
|
147 }, |
|
148 |
|
149 run: function(time) { |
|
150 this.clear(); |
|
151 this.addRipple(time); |
|
152 this.processBuffers(); |
|
153 this.render(); |
|
154 this.swapBuffers(); |
|
155 this.frame++; |
|
156 } |
|
157 } |
|
158 |
|
159 function Buffer(newWidth, newHeight) { |
|
160 this.width = newWidth; |
|
161 this.height = newHeight; |
|
162 this.data = new Array(); |
|
163 |
|
164 for (var x = 0; x < this.width; x++) { |
|
165 this.data[x] = new Array(); |
|
166 for (var y = 0; y < this.height; y++) { |
|
167 this.data[x][y] = 0; |
|
168 } |
|
169 } |
|
170 |
|
171 this.sphere = function(sphereX, sphereY, radius, depth) { |
|
172 for (var x = 0; x < this.width; x++) { |
|
173 for (var y = 0; y < this.height; y++) { |
|
174 var d = this.distance(sphereX, sphereY, x, y); |
|
175 if (d < radius) { |
|
176 this.data[x][y] = this.data[x][y] + depth * ((radius - Math.sqrt(d)) / radius); |
|
177 //this.data[x][y] = this.data[x][y] + Math.round((1 - d / radius) * 256); |
|
178 if (this.data[x][y] > 256) this.data[x][y] = 256; |
|
179 } |
|
180 } |
|
181 } |
|
182 } |
|
183 |
|
184 this.ripple = function(sphereX, sphereY, radius) { |
|
185 for (var x = 0; x < this.width; x++) { |
|
186 for (var y = 0; y < this.height; y++) { |
|
187 var d = this.distance(sphereX, sphereY, x, y); |
|
188 if (d < radius) { |
|
189 this.set(x, y, Math.sin((d / radius) * Math.PI) * 70);//Math.round((1 - d / radius) * 256); |
|
190 } |
|
191 } |
|
192 } |
|
193 } |
|
194 |
|
195 this.hardRipple = function(sphereX, sphereY, radius) { |
|
196 for (var x = 0; x < this.width; x++) { |
|
197 for (var y = 0; y < this.height; y++) { |
|
198 var d = this.distance(sphereX, sphereY, x, y); |
|
199 if (d < radius && d > radius * 0.8) { |
|
200 this.set(x, y, 256);//Math.round((1 - d / radius) * 256); |
|
201 } |
|
202 } |
|
203 } |
|
204 } |
|
205 |
|
206 this.distance = function(x1, y1, x2, y2) { |
|
207 return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); |
|
208 } |
|
209 |
|
210 this.get = function(x, y) { |
|
211 if (typeof(this.data[x]) != "undefined" && typeof(this.data[x][y]) != "undefined") { |
|
212 return this.data[x][y]; |
|
213 } else { |
|
214 return 0; |
|
215 } |
|
216 } |
|
217 |
|
218 this.set = function(x, y, value) { |
|
219 if (typeof(this.data[x]) != "undefined" && typeof(this.data[x][y]) != "undefined") { |
|
220 this.data[x][y] = Math.round(value); |
|
221 } |
|
222 } |
|
223 } |
|
224 |
|
225 function run() { |
|
226 ripples.init(); |
|
227 var now = new Date(); |
|
228 var start = window.mozAnimationStartTime; |
|
229 function step(timestamp) { |
|
230 progress = timestamp - start; |
|
231 ripples.run(progress); |
|
232 var time = new Date(); |
|
233 var diff = time.getTime() - now.getTime(); |
|
234 if (diff < 5000) { // five seconds |
|
235 window.mozRequestAnimationFrame(step); |
|
236 } else { |
|
237 var evt = document.createEvent("CustomEvent"); |
|
238 evt.initCustomEvent("test", true, false, { testName: "ripples", frames: ripples.frames, msec: diff }); |
|
239 window.dispatchEvent(evt); |
|
240 } |
|
241 } |
|
242 window.mozRequestAnimationFrame(step); |
|
243 } |
|
244 |
|
245 </script> |
|
246 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
|
247 <style> |
|
248 </style> |
|
249 <meta charset="utf-8"> |
|
250 </head> |
|
251 <body onload="setTimeout(run, 1000);"> |
|
252 <div id="anchor"><canvas id="ripples" width="1200" height="700"></canvas></div> |
|
253 </body> |
|
254 </html> |