| OLD | NEW |
| (Empty) | |
| 1 #!mojo:js_content_handler |
| 2 |
| 3 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 4 // Use of this source code is governed by a BSD-style license that can be |
| 5 // found in the LICENSE file. |
| 6 |
| 7 define("main", [ |
| 8 "console", |
| 9 "mojo/services/public/js/application", |
| 10 "mojo/services/public/interfaces/gpu/command_buffer.mojom", |
| 11 "mojo/services/public/interfaces/geometry/geometry.mojom", |
| 12 "mojo/services/public/interfaces/gpu/gpu.mojom", |
| 13 "mojo/services/public/interfaces/native_viewport/native_viewport.mojom", |
| 14 "mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom", |
| 15 "mojo/public/js/core", |
| 16 "services/js/modules/gl", |
| 17 "services/js/modules/clock", |
| 18 "timer", |
| 19 ], function(console, |
| 20 appModule, |
| 21 cbModule, |
| 22 geoModule, |
| 23 gpuModule, |
| 24 nvModule, |
| 25 vplModule, |
| 26 coreModule, |
| 27 glModule, |
| 28 clockModule, |
| 29 timerModule) { |
| 30 |
| 31 const VERTEX_SHADER_SOURCE = [ |
| 32 'uniform mat4 u_mvpMatrix;', |
| 33 'attribute vec4 a_position;', |
| 34 'void main()', |
| 35 '{', |
| 36 ' gl_Position = u_mvpMatrix * a_position;', |
| 37 '}' |
| 38 ].join('\n'); |
| 39 |
| 40 const FRAGMENT_SHADER_SOURCE = [ |
| 41 'precision mediump float;', |
| 42 'void main()', |
| 43 '{', |
| 44 ' gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );', |
| 45 '}' |
| 46 ].join('\n'); |
| 47 |
| 48 class ESMatrix { |
| 49 constructor() { |
| 50 this.m = new Float32Array(16); |
| 51 } |
| 52 |
| 53 getIndex(x, y) { |
| 54 return x * 4 + y; |
| 55 } |
| 56 |
| 57 set(x, y, v) { |
| 58 this.m[this.getIndex(x, y)] = v; |
| 59 } |
| 60 |
| 61 get(x, y) { |
| 62 return this.m[this.getIndex(x, y)]; |
| 63 } |
| 64 |
| 65 loadZero() { |
| 66 for (var i = 0; i < this.m.length; i++) { |
| 67 this.m[i] = 0; |
| 68 } |
| 69 } |
| 70 |
| 71 loadIdentity() { |
| 72 this.loadZero(); |
| 73 for (var i = 0; i < 4; i++) { |
| 74 this.set(i, i, 1); |
| 75 } |
| 76 } |
| 77 |
| 78 multiply(a, b) { |
| 79 var result = new ESMatrix(); |
| 80 for (var i = 0; i < 4; i++) { |
| 81 result.set(i, 0, |
| 82 (a.get(i, 0) * b.get(0, 0)) + |
| 83 (a.get(i, 1) * b.get(1, 0)) + |
| 84 (a.get(i, 2) * b.get(2, 0)) + |
| 85 (a.get(i, 3) * b.get(3, 0))); |
| 86 |
| 87 result.set(i, 1, |
| 88 (a.get(i, 0) * b.get(0, 1)) + |
| 89 (a.get(i, 1) * b.get(1, 1)) + |
| 90 (a.get(i, 2) * b.get(2, 1)) + |
| 91 (a.get(i, 3) * b.get(3, 1))); |
| 92 |
| 93 result.set(i, 2, |
| 94 (a.get(i, 0) * b.get(0, 2)) + |
| 95 (a.get(i, 1) * b.get(1, 2)) + |
| 96 (a.get(i, 2) * b.get(2, 2)) + |
| 97 (a.get(i, 3) * b.get(3, 2))); |
| 98 |
| 99 result.set(i, 3, |
| 100 (a.get(i, 0) * b.get(0, 3)) + |
| 101 (a.get(i, 1) * b.get(1, 3)) + |
| 102 (a.get(i, 2) * b.get(2, 3)) + |
| 103 (a.get(i, 3) * b.get(3, 3))); |
| 104 } |
| 105 for (var i = 0; i < result.m.length; i++) { |
| 106 this.m[i] = result.m[i]; |
| 107 } |
| 108 } |
| 109 |
| 110 frustrum(left, right, bottom, top, nearZ, farZ) { |
| 111 var deltaX = right - left; |
| 112 var deltaY = top - bottom; |
| 113 var deltaZ = farZ - nearZ; |
| 114 |
| 115 if (nearZ < 0 || farZ < 0 || deltaZ < 0 || deltaY < 0 || deltaX < 0) { |
| 116 return; |
| 117 } |
| 118 |
| 119 var frust = new ESMatrix(); |
| 120 frust.set(0, 0, 2 * nearZ / deltaX); |
| 121 |
| 122 frust.set(1, 1, 2 * nearZ / deltaY); |
| 123 |
| 124 frust.set(2, 0, (right + left) / deltaX); |
| 125 frust.set(2, 1, (top + bottom) / deltaY); |
| 126 frust.set(2, 2, -(nearZ + farZ) / deltaZ); |
| 127 frust.set(2, 3, -1); |
| 128 |
| 129 frust.set(3, 2, -2 * nearZ * farZ / deltaZ); |
| 130 |
| 131 this.multiply(frust, this); |
| 132 } |
| 133 |
| 134 perspective(fovY, aspect, nearZ, farZ) { |
| 135 var frustrumH = Math.tan(fovY / 360 * Math.PI) * nearZ; |
| 136 var frustrumW = frustrumH * aspect; |
| 137 this.frustrum(-frustrumW, frustrumW, -frustrumH, frustrumH, nearZ, farZ); |
| 138 } |
| 139 |
| 140 translate(tx, ty, tz) { |
| 141 this.set(3, 0, this.get(3, 0) + this.get(0, 0) * |
| 142 tx + this.get(1, 0) * ty + this.get(2, 0) * tz); |
| 143 this.set(3, 1, this.get(3, 1) + this.get(0, 1) * |
| 144 tx + this.get(1, 1) * ty + this.get(2, 1) * tz); |
| 145 this.set(3, 2, this.get(3, 2) + this.get(0, 2) * |
| 146 tx + this.get(1, 2) * ty + this.get(2, 2) * tz); |
| 147 this.set(3, 3, this.get(3, 3) + this.get(0, 3) * |
| 148 tx + this.get(1, 3) * ty + this.get(2, 3) * tz); |
| 149 } |
| 150 |
| 151 rotate(angle, x, y, z) { |
| 152 var mag = Math.sqrt(x * x + y * y + z * z); |
| 153 var sinAngle = Math.sin(angle * Math.PI / 180); |
| 154 var cosAngle = Math.cos(angle * Math.PI / 180); |
| 155 if (mag <= 0) { |
| 156 return; |
| 157 } |
| 158 |
| 159 var xx, yy, zz, xy, yz, zx, xs, ys, zs, oneMinusCos; |
| 160 var rotation = new ESMatrix(); |
| 161 |
| 162 x /= mag; |
| 163 y /= mag; |
| 164 z /= mag; |
| 165 |
| 166 xx = x * x; |
| 167 yy = y * y; |
| 168 zz = z * z; |
| 169 xy = x * y; |
| 170 yz = y * z; |
| 171 zx = z * x; |
| 172 xs = x * sinAngle; |
| 173 ys = y * sinAngle; |
| 174 zs = z * sinAngle; |
| 175 oneMinusCos = 1 - cosAngle; |
| 176 |
| 177 rotation.set(0, 0, (oneMinusCos * xx) + cosAngle); |
| 178 rotation.set(0, 1, (oneMinusCos * xy) - zs); |
| 179 rotation.set(0, 2, (oneMinusCos * zx) + ys); |
| 180 rotation.set(0, 3, 0); |
| 181 |
| 182 rotation.set(1, 0, (oneMinusCos * xy) + zs); |
| 183 rotation.set(1, 1, (oneMinusCos * yy) + cosAngle); |
| 184 rotation.set(1, 2, (oneMinusCos * yz) - xs); |
| 185 rotation.set(1, 3, 0); |
| 186 |
| 187 rotation.set(2, 0, (oneMinusCos * zx) - ys); |
| 188 rotation.set(2, 1, (oneMinusCos * yz) + xs); |
| 189 rotation.set(2, 2, (oneMinusCos * zz) + cosAngle); |
| 190 rotation.set(2, 3, 0); |
| 191 |
| 192 rotation.set(3, 0, 0); |
| 193 rotation.set(3, 1, 0); |
| 194 rotation.set(3, 2, 0); |
| 195 rotation.set(3, 3, 1); |
| 196 |
| 197 this.multiply(rotation, this); |
| 198 } |
| 199 } |
| 200 |
| 201 function loadProgram(gl) { |
| 202 var vertexShader = gl.createShader(gl.VERTEX_SHADER); |
| 203 gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE); |
| 204 gl.compileShader(vertexShader); |
| 205 |
| 206 var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); |
| 207 gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE); |
| 208 gl.compileShader(fragmentShader); |
| 209 |
| 210 var program = gl.createProgram(); |
| 211 gl.attachShader(program, vertexShader); |
| 212 gl.attachShader(program, fragmentShader); |
| 213 |
| 214 gl.linkProgram(program); |
| 215 // TODO(aa): Check for errors using getProgramiv and LINK_STATUS. |
| 216 |
| 217 gl.deleteShader(vertexShader); |
| 218 gl.deleteShader(fragmentShader); |
| 219 |
| 220 return program; |
| 221 } |
| 222 |
| 223 var vboVertices; |
| 224 var vboIndices; |
| 225 function generateCube(gl) { |
| 226 var numVertices = 24 * 3; |
| 227 var numIndices = 12 * 3; |
| 228 |
| 229 var cubeVertices = new Float32Array([ |
| 230 -0.5, -0.5, -0.5, |
| 231 -0.5, -0.5, 0.5, |
| 232 0.5, -0.5, 0.5, |
| 233 0.5, -0.5, -0.5, |
| 234 -0.5, 0.5, -0.5, |
| 235 -0.5, 0.5, 0.5, |
| 236 0.5, 0.5, 0.5, |
| 237 0.5, 0.5, -0.5, |
| 238 -0.5, -0.5, -0.5, |
| 239 -0.5, 0.5, -0.5, |
| 240 0.5, 0.5, -0.5, |
| 241 0.5, -0.5, -0.5, |
| 242 -0.5, -0.5, 0.5, |
| 243 -0.5, 0.5, 0.5, |
| 244 0.5, 0.5, 0.5, |
| 245 0.5, -0.5, 0.5, |
| 246 -0.5, -0.5, -0.5, |
| 247 -0.5, -0.5, 0.5, |
| 248 -0.5, 0.5, 0.5, |
| 249 -0.5, 0.5, -0.5, |
| 250 0.5, -0.5, -0.5, |
| 251 0.5, -0.5, 0.5, |
| 252 0.5, 0.5, 0.5, |
| 253 0.5, 0.5, -0.5 |
| 254 ]); |
| 255 |
| 256 var cubeIndices = new Uint16Array([ |
| 257 0, 2, 1, |
| 258 0, 3, 2, |
| 259 4, 5, 6, |
| 260 4, 6, 7, |
| 261 8, 9, 10, |
| 262 8, 10, 11, |
| 263 12, 15, 14, |
| 264 12, 14, 13, |
| 265 16, 17, 18, |
| 266 16, 18, 19, |
| 267 20, 23, 22, |
| 268 20, 22, 21 |
| 269 ]); |
| 270 |
| 271 // TODO(aa): The C++ program branches here on whether the pointer is |
| 272 // non-NULL. |
| 273 vboVertices = gl.createBuffer(); |
| 274 gl.bindBuffer(gl.ARRAY_BUFFER, vboVertices); |
| 275 gl.bufferData(gl.ARRAY_BUFFER, cubeVertices, gl.STATIC_DRAW); |
| 276 gl.bindBuffer(gl.ARRAY_BUFFER, 0); |
| 277 |
| 278 vboIndices = gl.createBuffer(); |
| 279 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vboIndices); |
| 280 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cubeIndices, gl.STATIC_DRAW); |
| 281 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0); |
| 282 |
| 283 return cubeIndices.length; |
| 284 } |
| 285 |
| 286 class GLES2ClientImpl { |
| 287 constructor (remotePipe, size) { |
| 288 this.gl_ = new glModule.Context(remotePipe, this.contextLost.bind(this)); |
| 289 this.lastTime_ = clockModule.seconds(); |
| 290 this.angle_ = 45; |
| 291 |
| 292 this.program_ = loadProgram(this.gl_); |
| 293 this.positionLocation_ = |
| 294 this.gl_.getAttribLocation(this.program_, 'a_position'); |
| 295 this.mvpLocation_ = |
| 296 this.gl_.getUniformLocation(this.program_, 'u_mvpMatrix'); |
| 297 this.numIndices_ = generateCube(this.gl_); |
| 298 this.mvpMatrix_ = new ESMatrix(); |
| 299 this.mvpMatrix_.loadIdentity(); |
| 300 |
| 301 this.gl_.clearColor(0, 0, 0, 0); |
| 302 this.setDimensions(size); |
| 303 this.timer_ = |
| 304 timerModule.createRepeating(16, this.handleTimer.bind(this)); |
| 305 } |
| 306 |
| 307 setDimensions(size) { |
| 308 this.width_ = size.width; |
| 309 this.height_ = size.height; |
| 310 this.gl_.resize(size.width, size.height, 1); |
| 311 } |
| 312 |
| 313 drawCube() { |
| 314 this.gl_.viewport(0, 0, this.width_, this.height_); |
| 315 this.gl_.clear(this.gl_.COLOR_BUFFER_BIT); |
| 316 this.gl_.useProgram(this.program_); |
| 317 this.gl_.bindBuffer(this.gl_.ARRAY_BUFFER, vboVertices); |
| 318 this.gl_.bindBuffer(this.gl_.ELEMENT_ARRAY_BUFFER, vboIndices); |
| 319 this.gl_.vertexAttribPointer(this.positionLocation_, 3, this.gl_.FLOAT, |
| 320 false, 12, 0); |
| 321 this.gl_.enableVertexAttribArray(this.positionLocation_); |
| 322 this.gl_.uniformMatrix4fv(this.mvpLocation_, false, this.mvpMatrix_.m); |
| 323 this.gl_.drawElements(this.gl_.TRIANGLES, this.numIndices_, |
| 324 this.gl_.UNSIGNED_SHORT, 0); |
| 325 this.gl_.swapBuffers(); |
| 326 }; |
| 327 |
| 328 handleTimer() { |
| 329 var now = clockModule.seconds(); |
| 330 var secondsDelta = now - this.lastTime_; |
| 331 this.lastTime_ = now; |
| 332 |
| 333 this.angle_ += this.getRotationForTimeDelta(secondsDelta); |
| 334 this.angle_ = this.angle_ % 360; |
| 335 |
| 336 var aspect = this.width_ / this.height_; |
| 337 |
| 338 var perspective = new ESMatrix(); |
| 339 perspective.loadIdentity(); |
| 340 perspective.perspective(60, aspect, 1, 20); |
| 341 |
| 342 var modelView = new ESMatrix(); |
| 343 modelView.loadIdentity(); |
| 344 modelView.translate(0, 0, -2); |
| 345 modelView.rotate(this.angle_, 1, 0, 1); |
| 346 |
| 347 this.mvpMatrix_.multiply(modelView, perspective); |
| 348 |
| 349 this.drawCube(); |
| 350 }; |
| 351 |
| 352 getRotationForTimeDelta(secondsDelta) { |
| 353 return secondsDelta * 40; |
| 354 }; |
| 355 |
| 356 contextLost() { |
| 357 console.log('GLES2ClientImpl.prototype.contextLost'); |
| 358 }; |
| 359 |
| 360 quit() { |
| 361 if (this.timer_) { |
| 362 console.log("CANCEL"); |
| 363 this.timer_.cancel(); |
| 364 this.timer_ = null; |
| 365 } |
| 366 } |
| 367 } |
| 368 |
| 369 class CubeDemo extends appModule.Application { |
| 370 initialize(args) { |
| 371 this.viewport = this.shell.connectToService( |
| 372 "mojo:native_viewport_service", nvModule.NativeViewport, this); |
| 373 |
| 374 this.gpu = this.shell.connectToService( |
| 375 "mojo:native_viewport_service", gpuModule.Gpu); |
| 376 |
| 377 var app = this; |
| 378 var viewportSize = new geoModule.Size({width: 800, height: 600}); |
| 379 this.viewport.create(viewportSize).then( |
| 380 function(result) { |
| 381 app.onViewportCreated(result.native_viewport_id, viewportSize); |
| 382 }); |
| 383 |
| 384 this.eventDispatcher = |
| 385 new nvModule.NativeViewportEventDispatcher.stubClass(this); |
| 386 this.viewport.setEventDispatcher(this.eventDispatcher); |
| 387 this.viewport.show(); |
| 388 } |
| 389 |
| 390 onViewportCreated(id, size) { |
| 391 this.vpl = new vplModule.ViewportParameterListener.stubClass({ |
| 392 onVSyncParametersUpdated: function(timebase, interval) { |
| 393 console.log("onVSyncParametersUpdated"); |
| 394 } |
| 395 }); |
| 396 var pipe = coreModule.createMessagePipe(); |
| 397 this.gpu.createOnscreenGLES2Context(id, size, pipe.handle1, this.vpl); |
| 398 this.gles2_ = new GLES2ClientImpl(pipe.handle0, size); |
| 399 } |
| 400 |
| 401 onEvent(event) { |
| 402 return Promise.resolve(); // This just gates the next event delivery |
| 403 } |
| 404 |
| 405 onSizeChanged(size) { |
| 406 if (this.gles2_) |
| 407 this.gles2_.setDimensions(size); |
| 408 } |
| 409 |
| 410 onDestroyed() { |
| 411 this.quit(); |
| 412 } |
| 413 } |
| 414 |
| 415 return CubeDemo; |
| 416 }); |
| OLD | NEW |