OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import "dart:math" as Math; |
| 6 import "android_extension.dart"; |
| 7 |
| 8 const FRAGMENT_PROGRAM = """ |
| 9 precision mediump float; |
| 10 |
| 11 const vec3 lightDir = vec3(0.577350269, 0.577350269, -0.577350269); |
| 12 varying vec3 vPosition; |
| 13 uniform vec3 cameraPos; |
| 14 uniform vec3 sphere1Center; |
| 15 uniform vec3 sphere2Center; |
| 16 uniform vec3 sphere3Center; |
| 17 |
| 18 bool intersectSphere(vec3 center, vec3 lStart, vec3 lDir, |
| 19 out float dist) { |
| 20 vec3 c = center - lStart; |
| 21 float b = dot(lDir, c); |
| 22 float d = b*b - dot(c, c) + 1.0; |
| 23 if (d < 0.0) { |
| 24 dist = 10000.0; |
| 25 return false; |
| 26 } |
| 27 |
| 28 dist = b - sqrt(d); |
| 29 if (dist < 0.0) { |
| 30 dist = 10000.0; |
| 31 return false; |
| 32 } |
| 33 |
| 34 return true; |
| 35 } |
| 36 |
| 37 vec3 lightAt(vec3 N, vec3 V, vec3 color) { |
| 38 vec3 L = lightDir; |
| 39 vec3 R = reflect(-L, N); |
| 40 |
| 41 float c = 0.3 + 0.4 * pow(max(dot(R, V), 0.0), 30.0) + 0.7 * dot(L, N); |
| 42 |
| 43 if (c > 1.0) { |
| 44 return mix(color, vec3(1.6, 1.6, 1.6), c - 1.0); |
| 45 } |
| 46 |
| 47 return c * color; |
| 48 } |
| 49 |
| 50 bool intersectWorld(vec3 lStart, vec3 lDir, out vec3 pos, |
| 51 out vec3 normal, out vec3 color) { |
| 52 float d1, d2, d3; |
| 53 bool h1, h2, h3; |
| 54 |
| 55 h1 = intersectSphere(sphere1Center, lStart, lDir, d1); |
| 56 h2 = intersectSphere(sphere2Center, lStart, lDir, d2); |
| 57 h3 = intersectSphere(sphere3Center, lStart, lDir, d3); |
| 58 |
| 59 if (h1 && d1 < d2 && d1 < d3) { |
| 60 pos = lStart + d1 * lDir; |
| 61 normal = pos - sphere1Center; |
| 62 color = vec3(0.0, 0.0, 0.9); |
| 63 if (fract(pos.x / 1.5) > 0.5 ^^ |
| 64 fract(pos.y / 1.5) > 0.5 ^^ |
| 65 fract(pos.z / 1.5) > 0.5) { |
| 66 color = vec3(1.0, 0.0, 1.0); |
| 67 } |
| 68 else { |
| 69 color = vec3(1.0, 1.0, 0.0); |
| 70 } |
| 71 } |
| 72 else if (h2 && d2 < d3) { |
| 73 pos = lStart + d2 * lDir; |
| 74 normal = pos - sphere2Center; |
| 75 color = vec3(0.9, mod(normal.y * 2.5, 1.0), 0.0); |
| 76 } |
| 77 else if (h3) { |
| 78 pos = lStart + d3 * lDir; |
| 79 normal = pos - sphere3Center; |
| 80 color = vec3(0.0, clamp(sphere3Center.y/1.5, 0.0, 0.9), |
| 81 clamp(0.9 - sphere3Center.y/1.5, 0.0, 0.9)); |
| 82 } |
| 83 else if (lDir.y < -0.01) { |
| 84 pos = lStart + ((lStart.y + 2.7) / -lDir.y) * lDir; |
| 85 if (pos.x*pos.x + pos.z*pos.z > 30.0) { |
| 86 return false; |
| 87 } |
| 88 normal = vec3(0.0, 1.0, 0.0); |
| 89 if (fract(pos.x / 5.0) > 0.5 == fract(pos.z / 5.0) > 0.5) { |
| 90 color = vec3(1.0); |
| 91 } |
| 92 else { |
| 93 color = vec3(0.0); |
| 94 } |
| 95 } |
| 96 else { |
| 97 return false; |
| 98 } |
| 99 |
| 100 return true; |
| 101 } |
| 102 |
| 103 void main(void) |
| 104 { |
| 105 vec3 cameraDir = normalize(vPosition - cameraPos); |
| 106 |
| 107 vec3 p1, norm, p2; |
| 108 vec3 col, colT, colM, col3; |
| 109 if (intersectWorld(cameraPos, cameraDir, p1, |
| 110 norm, colT)) { |
| 111 col = lightAt(norm, -cameraDir, colT); |
| 112 colM = (colT + vec3(0.2)) / 1.2; |
| 113 cameraDir = reflect(cameraDir, norm); |
| 114 if (intersectWorld(p1, cameraDir, p2, norm, colT)) { |
| 115 col += lightAt(norm, -cameraDir, colT) * colM; |
| 116 colM *= (colT + vec3(0.2)) / 1.2; |
| 117 cameraDir = reflect(cameraDir, norm); |
| 118 if (intersectWorld(p2, cameraDir, p1, norm, colT)) { |
| 119 col += lightAt(norm, -cameraDir, colT) * colM; |
| 120 } |
| 121 } |
| 122 |
| 123 gl_FragColor = vec4(col, 1.0); |
| 124 } |
| 125 else { |
| 126 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); |
| 127 } |
| 128 } |
| 129 """; |
| 130 |
| 131 const VERTEX_PROGRAM = """ |
| 132 attribute vec2 aVertexPosition; |
| 133 attribute vec3 aPlotPosition; |
| 134 |
| 135 varying vec3 vPosition; |
| 136 |
| 137 void main(void) |
| 138 { |
| 139 gl_Position = vec4(aVertexPosition, 1.0, 1.0); |
| 140 vPosition = aPlotPosition; |
| 141 } |
| 142 """; |
| 143 |
| 144 loadShader(final type, final program) { |
| 145 final shader = gl.createShader(type); |
| 146 gl.shaderSource(shader, program); |
| 147 gl.compileShader(shader); |
| 148 if (gl.getShaderParameter(shader, WebGLRenderingContext.COMPILE_STATUS) |
| 149 != WebGLRenderingContext.TRUE) { |
| 150 log("Could not compile shader: ${gl.getShaderInfoLog(shader)}"); |
| 151 throw new Exception("Could not compile shader"); |
| 152 } |
| 153 |
| 154 return shader; |
| 155 } |
| 156 |
| 157 var shaderProgram; |
| 158 var aVertexPosition; |
| 159 var aPlotPosition; |
| 160 var cameraPos; |
| 161 var sphere1Center; |
| 162 var sphere2Center; |
| 163 var sphere3Center; |
| 164 var ratio; |
| 165 |
| 166 initShaders() { |
| 167 var vertexShader = loadShader(WebGLRenderingContext.VERTEX_SHADER, |
| 168 VERTEX_PROGRAM); |
| 169 var fragmentShader = loadShader(WebGLRenderingContext.FRAGMENT_SHADER, |
| 170 FRAGMENT_PROGRAM); |
| 171 |
| 172 shaderProgram = gl.createProgram(); |
| 173 if (shaderProgram == 0) { |
| 174 throw new Exception("Could not create program."); |
| 175 } |
| 176 |
| 177 gl.attachShader(shaderProgram, vertexShader); |
| 178 gl.attachShader(shaderProgram, fragmentShader); |
| 179 gl.linkProgram(shaderProgram); |
| 180 |
| 181 if (gl.getProgramParameter(shaderProgram, WebGLRenderingContext.LINK_STATUS) |
| 182 != WebGLRenderingContext.TRUE) { |
| 183 log("Could not link program: ${gl.getProgramInfoLog(shaderProgram)}"); |
| 184 throw new Exception("Could not initialize shaders"); |
| 185 } |
| 186 |
| 187 gl.useProgram(shaderProgram); |
| 188 |
| 189 aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition"); |
| 190 gl.enableVertexAttribArray(aVertexPosition); |
| 191 |
| 192 aPlotPosition = gl.getAttribLocation(shaderProgram, "aPlotPosition"); |
| 193 gl.enableVertexAttribArray(aPlotPosition); |
| 194 |
| 195 cameraPos = gl.getUniformLocation(shaderProgram, "cameraPos"); |
| 196 sphere1Center = gl.getUniformLocation(shaderProgram, "sphere1Center"); |
| 197 sphere2Center = gl.getUniformLocation(shaderProgram, "sphere2Center"); |
| 198 sphere3Center = gl.getUniformLocation(shaderProgram, "sphere3Center"); |
| 199 } |
| 200 |
| 201 initBuffers() { |
| 202 var vertexPositionBuffer = gl.createBuffer(); |
| 203 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); |
| 204 // TODO(gram): vertices should be a Float32Array to be consistent with WebGL. |
| 205 var vertices = [ |
| 206 1.0, 1.0, |
| 207 -1.0, 1.0, |
| 208 1.0, -1.0, |
| 209 -1.0, -1.0, |
| 210 ]; |
| 211 |
| 212 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, vertices, |
| 213 WebGLRenderingContext.STATIC_DRAW); |
| 214 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, vertexPositionBuffer); |
| 215 gl.vertexAttribPointer(aVertexPosition, 2, WebGLRenderingContext.FLOAT, |
| 216 false,0, 0); |
| 217 |
| 218 var plotPositionBuffer = gl.createBuffer(); |
| 219 gl.bindBuffer(WebGLRenderingContext.ARRAY_BUFFER, plotPositionBuffer); |
| 220 gl.vertexAttribPointer(aPlotPosition, 3, WebGLRenderingContext.FLOAT, |
| 221 false, 0, 0); |
| 222 } |
| 223 |
| 224 class Vector { |
| 225 var x; |
| 226 var y; |
| 227 var z; |
| 228 Vector(this.x, this.y, this.z); |
| 229 } |
| 230 |
| 231 // TODO(gram): This should be using vector_math. |
| 232 crossProd(v1, v2) { |
| 233 return |
| 234 new Vector( |
| 235 v1.y*v2.z - v2.y*v1.z, |
| 236 v1.z*v2.x - v2.z*v1.x, |
| 237 v1.x*v2.y - v2.x*v1.y); |
| 238 } |
| 239 |
| 240 normalize(v) { |
| 241 var l = Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z); |
| 242 return new Vector( v.x/l, v.y/l, v.z/l ); |
| 243 } |
| 244 |
| 245 vectAdd(v1, v2) { |
| 246 return new Vector( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); |
| 247 } |
| 248 |
| 249 vectSub(v1, v2) { |
| 250 return new Vector( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); |
| 251 } |
| 252 |
| 253 vectMul(v, l) { |
| 254 return new Vector( v.x*l, v.y*l, v.z*l ); |
| 255 } |
| 256 |
| 257 pushVec(v, arr) { |
| 258 arr.addAll([v.x, v.y, v.z]); |
| 259 } |
| 260 |
| 261 var t = 0; |
| 262 int width, height; |
| 263 |
| 264 drawScene() { |
| 265 var x1 = Math.sin(t * 1.1) * 1.5; |
| 266 var y1 = Math.cos(t * 1.3) * 1.5; |
| 267 var z1 = Math.sin(t + Math.PI/3) * 1.5; |
| 268 var x2 = Math.cos(t * 1.2) * 1.5; |
| 269 var y2 = Math.sin(t * 1.4) * 1.5; |
| 270 var z2 = Math.sin(t*1.25 - Math.PI/3) * 1.5; |
| 271 var x3 = Math.cos(t * 1.15) * 1.5; |
| 272 var y3 = Math.sin(t * 1.37) * 1.5; |
| 273 var z3 = Math.sin(t*1.27) * 1.5; |
| 274 |
| 275 var cameraFrom = new Vector( |
| 276 Math.sin(t * 0.4) * 18, |
| 277 Math.sin(t * 0.13) * 5 + 5, |
| 278 Math.cos(t * 0.4) * 18 ); |
| 279 var cameraTo = new Vector(0.0, 0.0, 0.0); |
| 280 var cameraPersp = 6.0; |
| 281 var up = new Vector(0.0, 1.0, 0.0); |
| 282 var cameraDir = normalize(vectSub(cameraTo, cameraFrom)); |
| 283 |
| 284 var cameraLeft = normalize(crossProd(cameraDir, up)); |
| 285 var cameraUp = normalize(crossProd(cameraLeft, cameraDir)); |
| 286 // cameraFrom + cameraDir * cameraPersp |
| 287 var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp)); |
| 288 |
| 289 // cameraCenter + cameraUp + cameraLeft * ratio |
| 290 var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), |
| 291 vectMul(cameraLeft, ratio)); |
| 292 var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), |
| 293 vectMul(cameraLeft, ratio)); |
| 294 var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), |
| 295 vectMul(cameraLeft, ratio)); |
| 296 var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), |
| 297 vectMul(cameraLeft, ratio)); |
| 298 |
| 299 // TODO(gram): corners should be a Float32Array to be consistent with WebGL. |
| 300 var corners = []; |
| 301 pushVec(cameraTopRight, corners); |
| 302 pushVec(cameraTopLeft, corners); |
| 303 pushVec(cameraBotRight, corners); |
| 304 pushVec(cameraBotLeft, corners); |
| 305 |
| 306 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, corners, |
| 307 WebGLRenderingContext.STATIC_DRAW); |
| 308 |
| 309 gl.uniform3f(cameraPos, cameraFrom.x, cameraFrom.y, cameraFrom.z); |
| 310 gl.uniform3f(sphere1Center, x1, y1, z1); |
| 311 gl.uniform3f(sphere2Center, x2, y2, z2); |
| 312 gl.uniform3f(sphere3Center, x3, y3, z3); |
| 313 |
| 314 gl.drawArrays(WebGLRenderingContext.TRIANGLE_STRIP, 0, 4); |
| 315 |
| 316 t += 0.03; |
| 317 if (t > Math.PI * 200) { |
| 318 t -= Math.PI * 200; |
| 319 } |
| 320 } |
| 321 |
| 322 setup(int w, int h) { |
| 323 initShaders(); |
| 324 gl.clearColor(0.0, 0.0, 0.0, 1.0); |
| 325 gl.clearDepth(1.0); |
| 326 initBuffers(); |
| 327 resize(w, h); |
| 328 } |
| 329 |
| 330 resize(int w, int h) { |
| 331 width = w; |
| 332 height = h; |
| 333 ratio = width / height; |
| 334 gl.viewport(0, 0, width, height); |
| 335 t -= 0.03; |
| 336 drawScene(); |
| 337 } |
| 338 |
| 339 update() { |
| 340 drawScene(); |
| 341 eglSwapBuffers(); |
| 342 } |
| 343 |
| 344 onMotionDown(num when, num x, num y) { |
| 345 t = (x / width) * Math.PI * 200; |
| 346 } |
| 347 |
| 348 onMotionUp(num when, num x, num y) {} |
| 349 onMotionMove(num when, num x, num y) {} |
| 350 onMotionCancel(num when, num x, num y) {} |
| 351 onMotionOutside(num when, num x, num y) {} |
| 352 onMotionPointerDown(num when, num x, num y) {} |
| 353 onMotionPointerUp(num when, num x, num y) {} |
| 354 onKeyDown(num when, int flags, int keycode, int metastate, int repeat) {} |
| 355 onKeyUp(num when, int flags, int keycode, int metastate, int repeat) {} |
| 356 onKeyMultiple(num when, int flags, int keycode, int metastate, int repeat) { |
| 357 } |
| 358 |
OLD | NEW |