Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This sample is based upon the Ray Tracer sample by Jonas Sicking at: | 5 // This sample is based upon the Ray Tracer sample by Jonas Sicking at: |
| 6 // http://www.khronos.org/webgl/wiki/Demo_Repository | 6 // http://www.khronos.org/webgl/wiki/Demo_Repository |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * A sample GL application. | 9 * A sample GL application. |
| 10 */ | 10 */ |
|
vsm
2013/02/04 18:18:41
I think we should make a separate sample. E.g., s
gram
2013/02/04 22:02:28
Done.
| |
| 11 library raytrace; | 11 library raytrace; |
| 12 | 12 |
| 13 import 'gl.dart'; | 13 import 'gl.dart'; |
| 14 import 'dart:math' as Math; | 14 import 'dart:math' as Math; |
| 15 | 15 |
| 16 WebGLRenderingContext gl = null; | |
| 17 | |
| 16 // Note: The first line of the fragment shader ("precision mediump float") | 18 // Note: The first line of the fragment shader ("precision mediump float") |
| 17 // is not portable. It is required for WebGL and OpenGL ES. Desktop OpenGL | 19 // is not portable. It is required for WebGL and OpenGL ES. Desktop OpenGL |
| 18 // does not use precision specifiers. Some desktop systems treat this as a | 20 // does not use precision specifiers. Some desktop systems treat this as a |
| 19 // no-op and some treat it as a syntax error. In particular, this line needs | 21 // no-op and some treat it as a syntax error. In particular, this line needs |
| 20 // to be removed to this this shader on a MAc. | 22 // to be removed to this this shader on a MAc. |
| 21 const FRAGMENT_PROGRAM = """ | 23 const FRAGMENT_PROGRAM = """ |
| 22 // TODO(vsm): Remove this ifdef. It's a temporary workaround to get | 24 // TODO(vsm): Remove this ifdef. It's a temporary workaround to get |
| 23 // this sample running on the Mac desktop emulator. | 25 // this sample running on the Mac desktop emulator. |
| 24 #ifdef GL_ES | 26 #ifdef GL_ES |
| 25 precision mediump float; | 27 precision mediump float; |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 var cameraPersp = 6.0; | 294 var cameraPersp = 6.0; |
| 293 var up = new Vector(0.0, 1.0, 0.0); | 295 var up = new Vector(0.0, 1.0, 0.0); |
| 294 var cameraDir = normalize(vectSub(cameraTo, cameraFrom)); | 296 var cameraDir = normalize(vectSub(cameraTo, cameraFrom)); |
| 295 | 297 |
| 296 var cameraLeft = normalize(crossProd(cameraDir, up)); | 298 var cameraLeft = normalize(crossProd(cameraDir, up)); |
| 297 var cameraUp = normalize(crossProd(cameraLeft, cameraDir)); | 299 var cameraUp = normalize(crossProd(cameraLeft, cameraDir)); |
| 298 // cameraFrom + cameraDir * cameraPersp | 300 // cameraFrom + cameraDir * cameraPersp |
| 299 var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp)); | 301 var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp)); |
| 300 | 302 |
| 301 // cameraCenter + cameraUp + cameraLeft * ratio | 303 // cameraCenter + cameraUp + cameraLeft * ratio |
| 302 var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), | 304 log("cameraLeft = ${cameraLeft}"); |
| 303 vectMul(cameraLeft, ratio)); | 305 log("ratio = ${ratio}"); |
| 304 var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), | 306 var vl = vectMul(cameraLeft, ratio); |
| 305 vectMul(cameraLeft, ratio)); | 307 var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), vl); |
| 306 var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), | 308 //vectMul(cameraLeft, ratio)); |
| 307 vectMul(cameraLeft, ratio)); | 309 var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), vl); |
| 308 var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), | 310 //vectMul(cameraLeft, ratio)); |
| 309 vectMul(cameraLeft, ratio)); | 311 var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), vl); |
| 312 //vectMul(cameraLeft, ratio)); | |
| 313 var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), vl); | |
| 314 //vectMul(cameraLeft, ratio)); | |
| 310 | 315 |
| 311 var corners = []; | 316 var corners = []; |
| 312 pushVec(cameraTopRight, corners); | 317 pushVec(cameraTopRight, corners); |
| 313 pushVec(cameraTopLeft, corners); | 318 pushVec(cameraTopLeft, corners); |
| 314 pushVec(cameraBotRight, corners); | 319 pushVec(cameraBotRight, corners); |
| 315 pushVec(cameraBotLeft, corners); | 320 pushVec(cameraBotLeft, corners); |
| 316 | 321 |
| 317 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, wrapVertices(corners), | 322 gl.bufferData(WebGLRenderingContext.ARRAY_BUFFER, wrapVertices(corners), |
| 318 WebGLRenderingContext.STATIC_DRAW); | 323 WebGLRenderingContext.STATIC_DRAW); |
| 319 | 324 |
| 320 gl.uniform3f(cameraPos, cameraFrom.x, cameraFrom.y, cameraFrom.z); | 325 gl.uniform3f(cameraPos, cameraFrom.x, cameraFrom.y, cameraFrom.z); |
| 321 gl.uniform3f(sphere1Center, x1, y1, z1); | 326 gl.uniform3f(sphere1Center, x1, y1, z1); |
| 322 gl.uniform3f(sphere2Center, x2, y2, z2); | 327 gl.uniform3f(sphere2Center, x2, y2, z2); |
| 323 gl.uniform3f(sphere3Center, x3, y3, z3); | 328 gl.uniform3f(sphere3Center, x3, y3, z3); |
| 324 | 329 |
| 325 gl.drawArrays(WebGLRenderingContext.TRIANGLE_STRIP, 0, 4); | 330 gl.drawArrays(WebGLRenderingContext.TRIANGLE_STRIP, 0, 4); |
| 326 | 331 |
| 327 t += 0.03; | 332 t += 0.03; |
| 328 if (t > Math.PI * 200) { | 333 if (t > Math.PI * 200) { |
| 329 t -= Math.PI * 200; | 334 t -= Math.PI * 200; |
| 330 } | 335 } |
| 331 } | 336 } |
| 332 | 337 |
| 333 void setup(int width, int height) { | 338 bool is3d = false; |
| 334 initShaders(); | 339 var ctx; |
| 335 gl.clearColor(0.0, 0.0, 0.0, 1.0); | 340 var width, height; |
| 336 gl.clearDepth(1.0); | 341 int testnum = 3; |
| 337 initBuffers(); | 342 bool isDirty = true; |
| 338 resize(width, height); | 343 |
| 339 } | 344 void setup(canvas, int w, int h) { |
| 340 | 345 if (canvas == null) { |
| 341 void resize(int width, int height) { | 346 canvas = new CanvasElement(width: w, height: h); |
| 342 ratio = width / height; | 347 } else { |
| 343 gl.viewport(0, 0, width, height); | 348 // called from gl_driver.dart. |
| 344 t -= 0.03; | 349 // This is a kludge; we need a clean way of handling events. |
| 345 drawScene(); | 350 canvas.on.mouseDown.add((e) { |
| 351 ++testnum; | |
| 352 }); | |
| 353 } | |
| 354 if (is3d) { | |
| 355 gl = canvas.getContext("webgl"); | |
| 356 initShaders(); | |
| 357 gl.clearColor(0.0, 0.0, 0.0, 1.0); | |
| 358 gl.clearDepth(1.0); | |
| 359 initBuffers(); | |
| 360 } else { | |
| 361 ctx = canvas.getContext("2d"); | |
| 362 if (ctx == null) | |
| 363 throw "Failed to get 2D context"; | |
| 364 } | |
| 365 resize(w, h); | |
| 366 log("Done setup"); | |
| 367 } | |
| 368 | |
| 369 void resize(int w, int h) { | |
| 370 width = w; | |
| 371 height = h; | |
| 372 if (is3d) { | |
| 373 gl.viewport(0, 0, width, height); | |
| 374 ratio = width / height; | |
| 375 t -= 0.03; | |
| 376 drawScene(); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 resetCanvas() { | |
| 381 ctx.globalCompositeOperation = "source-over"; | |
| 382 ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| 383 ctx.fillStyle = "#FFFFFF"; | |
| 384 ctx.clearRect(0, 0, width, height); | |
| 385 ctx.shadowOffsetX = ctx.shadowOffsetY = ctx.shadowBlur = 0.0; | |
| 386 ctx.beginPath(); | |
| 387 } | |
| 388 | |
| 389 helloWorld() { | |
| 390 ctx.font = "30px Courier"; | |
| 391 ctx.strokeStyle = "#7F7F7F"; | |
| 392 ctx.fillStyle = "#7F7F7F"; | |
| 393 ctx.textAlign = "center"; | |
| 394 ctx.lineWidth = 2; | |
| 395 ctx.strokeText("Align Center", width / 2, height / 4); | |
| 396 ctx.textAlign = "left"; | |
| 397 ctx.fillText("Align Left", width / 2, height / 2); | |
| 398 ctx.textAlign = "right"; | |
| 399 ctx.fillText("Align Right", width / 2, 3 * height / 4); | |
| 400 } | |
| 401 | |
| 402 blocks() { | |
| 403 ctx.fillStyle = "#FF0000"; | |
| 404 ctx.fillRect(width / 10, height / 10, width / 2, height / 25); | |
| 405 ctx.fillStyle = "#00FF00"; | |
| 406 ctx.fillRect(width / 4, height / 5, width / 20, height / 8); | |
| 407 //ctx.fillStyle = "rgba(0,0,255,0.8)"; | |
| 408 ctx.strokeStyle = "rgba(128,128,128, 0.5)"; | |
| 409 //ctx.fillStyle = "#7F7F7F"; | |
| 410 ctx.strokeRect(width / 5, height / 10, width / 2, height / 8); | |
| 411 } | |
| 412 | |
| 413 square(left, top, width, height) { | |
| 414 ctx.beginPath(); | |
| 415 ctx.moveTo(left, top); | |
| 416 ctx.lineTo(left + width, top); | |
| 417 ctx.lineTo(left + width, top + height); | |
| 418 ctx.lineTo(left, top + height); | |
| 419 ctx.closePath(); //lineTo(left, top); | |
| 420 } | |
| 421 | |
| 422 squares() { | |
| 423 ctx.strokeStyle = "black"; | |
| 424 ctx.fillStyle = "#FF0000"; | |
| 425 ctx.lineWidth = 4; | |
| 426 square(width / 10, height / 10, width / 2, height / 25); | |
| 427 ctx.fill(); | |
| 428 ctx.stroke(); | |
| 429 ctx.fillStyle = "#00FF00"; | |
| 430 square(width / 4, height / 5, width / 20, height / 8); | |
| 431 ctx.fill(); | |
| 432 ctx.stroke(); | |
| 433 ctx.fillStyle = "rgba(128,128,128, 0.5)"; | |
| 434 square(width / 5, height / 10, width / 2, height / 8); | |
| 435 ctx.fill(); | |
| 436 ctx.stroke(); | |
| 437 } | |
| 438 | |
| 439 lineJoin() { | |
| 440 ctx.strokeStyle = "black"; | |
| 441 ctx.fillStyle = "#FF0000"; | |
| 442 ctx.lineWidth = 8; | |
| 443 ctx.lineJoin = "round"; | |
| 444 square(width / 10, height / 10, width / 2, height / 25); | |
| 445 ctx.stroke(); | |
| 446 ctx.fillStyle = "#00FF00"; | |
| 447 ctx.lineJoin = "bevel"; | |
| 448 square(width / 4, height / 5, width / 20, height / 8); | |
| 449 ctx.stroke(); | |
| 450 ctx.fillStyle = "rgba(128,128,128, 0.5)"; | |
| 451 ctx.lineJoin = "miter"; | |
| 452 square(width / 5, height / 10, width / 2, height / 8); | |
| 453 ctx.stroke(); | |
| 454 } | |
| 455 | |
| 456 grid() { | |
| 457 ctx.lineWidth = 1; | |
| 458 for (var x = 0.5; x < width; x += 10) { | |
| 459 ctx.moveTo(x, 0); | |
| 460 ctx.lineTo(x, height); | |
| 461 } | |
| 462 for (var y = 0.5; y < height; y += 10) { | |
| 463 ctx.moveTo(0, y); | |
| 464 ctx.lineTo(width, y); | |
| 465 } | |
| 466 ctx.strokeStyle = "#eee"; | |
| 467 ctx.stroke(); | |
| 468 } | |
| 469 | |
| 470 line(x1, y1, x2, y2) { | |
| 471 ctx.beginPath(); | |
| 472 ctx.moveTo(x1, y1); | |
| 473 ctx.lineTo(x2, y2); | |
| 474 } | |
| 475 | |
| 476 strokeLines() { | |
| 477 ctx.lineWidth = height / 40; | |
| 478 ctx.strokeStyle = '#0000ff'; | |
| 479 // butt line cap (top line) | |
| 480 line(width / 4, height / 4, 3 * width / 4, height / 4); | |
| 481 ctx.lineCap = 'butt'; | |
| 482 ctx.stroke(); | |
| 483 | |
| 484 // round line cap (middle line) | |
| 485 line(width / 4, height / 2, 3 * width / 4, height / 2); | |
| 486 ctx.lineCap = 'round'; | |
| 487 ctx.stroke(); | |
| 488 | |
| 489 // square line cap (bottom line) | |
| 490 line(width / 4, 3 * height / 4, 3 * width / 4, 3 * height / 4); | |
| 491 ctx.lineCap = 'square'; | |
| 492 ctx.stroke(); | |
| 493 } | |
| 494 | |
| 495 colors() { | |
| 496 var colors = [ | |
| 497 "maroon", | |
| 498 "red", | |
| 499 "orange", | |
| 500 "yellow", | |
| 501 "olive", | |
| 502 "purple", | |
| 503 "fuschia", | |
| 504 "white", | |
| 505 "lime", | |
| 506 "green", | |
| 507 "navy", | |
| 508 "blue", | |
| 509 "aqua", | |
| 510 "teal", | |
| 511 "silver", | |
| 512 "gray", | |
| 513 "black" | |
| 514 ]; | |
| 515 | |
| 516 var i = 1; | |
| 517 var yinc = height / (2 * colors.length + 1); | |
| 518 | |
| 519 ctx.textAlign = "center"; | |
| 520 ctx.font = "${yinc}px Courier"; | |
| 521 | |
| 522 for (var color in colors) { | |
| 523 ctx.fillStyle = color; | |
| 524 ctx.fillRect(width / 4, i * 2 * yinc, width / 2, 3 * yinc / 2); | |
| 525 ctx.fillStyle = (color == "gray") ? "white" : "gray"; | |
| 526 ctx.fillText(color, width / 2, i * 2 * yinc + 7 * yinc / 8); | |
| 527 ++i; | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 | |
| 532 smiley() { | |
| 533 ctx.translate(width / 2 - 80, height / 2 - 75); | |
| 534 | |
| 535 ctx.beginPath(); | |
| 536 ctx.arc(100,80,75,0,Math.PI*2,true); | |
| 537 ctx.fillStyle = "rgb(255,255,204)"; | |
| 538 ctx.fill(); | |
| 539 ctx.stroke(); | |
| 540 | |
| 541 ctx.fillStyle = "black"; | |
| 542 ctx.beginPath(); | |
| 543 ctx.arc(80,55,8,0,Math.PI*2,true); | |
| 544 ctx.fill(); | |
| 545 | |
| 546 ctx.beginPath(); | |
| 547 ctx.arc(120,55,8,0,Math.PI*2,true); | |
| 548 ctx.fill(); | |
| 549 | |
| 550 ctx.beginPath(); | |
| 551 ctx.arc(100,85,10,4,Math.PI*2,true); | |
| 552 ctx.stroke(); | |
| 553 | |
| 554 ctx.beginPath(); | |
| 555 ctx.arc(100,95,30,0,Math.PI,false); | |
| 556 ctx.stroke(); | |
| 557 | |
| 558 ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| 559 } | |
| 560 | |
| 561 rot(txt1, [txt2, sx = 1.0, sy = 1.0]) { | |
| 562 if (txt2 == null) txt2 = txt1; | |
| 563 ctx.font = "50px sans serif"; | |
| 564 ctx.translate(width / 2, height / 2); | |
| 565 ctx.textAlign = "right"; | |
| 566 ctx.fillStyle = "red"; | |
| 567 ctx.fillText(txt1, 0, 0); | |
| 568 ctx.rotate(Math.PI / 2); | |
| 569 ctx.scale(sx, sy); | |
| 570 ctx.fillStyle = "green"; | |
| 571 ctx.fillText(txt2, 0, 0); | |
| 572 ctx.scale(sx, sy); | |
| 573 ctx.rotate(Math.PI / 2); | |
| 574 ctx.fillStyle = "blue"; | |
| 575 ctx.fillText(txt1, 0, 0); | |
| 576 ctx.scale(sx, sy); | |
| 577 ctx.rotate(Math.PI / 2); | |
| 578 ctx.fillStyle = "yellow"; | |
| 579 ctx.fillText(txt2, 0, 0); | |
| 580 ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| 581 } | |
| 582 | |
| 583 alpha() { | |
| 584 ctx.fillStyle = "gray"; | |
| 585 ctx.fillRect(0, 0, width, height); | |
| 586 grid(); | |
| 587 ctx.globalAlpha = 0.5; | |
| 588 rot("Global", "Alpha"); | |
| 589 ctx.globalAlpha = 1.0; | |
| 590 } | |
| 591 | |
| 592 scale() { | |
| 593 rot("Scale", "Test", 0.8, 0.5); | |
| 594 } | |
| 595 | |
| 596 curves() { | |
| 597 // See http://www.html5canvastutorials.com/tutorials/html5-canvas-quadratic-cu rves/ | |
| 598 ctx.beginPath(); | |
| 599 ctx.moveTo(188, 150); | |
| 600 ctx.quadraticCurveTo(288, 0, 388, 150); | |
| 601 ctx.lineWidth = 2; | |
| 602 ctx.strokeStyle = 'red'; | |
| 603 ctx.stroke(); | |
| 604 // See http://www.html5canvastutorials.com/tutorials/html5-canvas-bezier-curve s/ | |
| 605 ctx.beginPath(); | |
| 606 ctx.moveTo(188, 130); | |
| 607 ctx.bezierCurveTo(140, 10, 388, 10, 388, 170); | |
| 608 ctx.lineWidth = 5; | |
| 609 ctx.strokeStyle = 'blue'; | |
| 610 ctx.stroke(); | |
| 611 var x1, x2, y1, y2, ex, ey; | |
| 612 ctx.beginPath(); | |
| 613 x1 = width / 4; | |
| 614 y1 = height / 2; | |
| 615 x2 = width / 2; | |
| 616 y2 = height / 4; | |
| 617 ex = 3 * width / 4; | |
| 618 ey = y1; | |
| 619 ctx.moveTo(x1, x2); | |
| 620 ctx.quadraticCurveTo(x2, y2, ex, ey); | |
| 621 ctx.lineWidth = 10; | |
| 622 ctx.strokeStyle = 'green'; | |
| 623 ctx.stroke(); | |
| 624 | |
| 625 ctx.beginPath(); | |
| 626 ctx.moveTo(188, 130); | |
| 627 x1 = width / 8; | |
| 628 x2 = 7 * width / 8; | |
| 629 y1 = height / 50; | |
| 630 y2 = y1; | |
| 631 ex = x2; | |
| 632 ey = height / 2; | |
| 633 ctx.bezierCurveTo(x1, y1, x2, y2, ex, ey); | |
| 634 ctx.lineWidth = 7; | |
| 635 ctx.strokeStyle = 'black'; | |
| 636 ctx.stroke(); | |
| 637 } | |
| 638 | |
| 639 void shadows() { | |
| 640 ctx.shadowBlur=20; | |
| 641 ctx.shadowColor="black"; | |
| 642 ctx.fillStyle="red"; | |
| 643 var w = width / 2; | |
| 644 if (w > height / 2) w = height / 2; | |
| 645 ctx.fillRect(width / 2 - w / 2, height / 4 - w / 2, w, w); | |
| 646 ctx.shadowOffsetX = 10; | |
| 647 ctx.shadowOffsetY = 10; | |
| 648 ctx.shadowColor="green"; | |
| 649 ctx.fillRect(width / 2 - w / 2, 3 * height / 4 - w / 2, w, w); | |
| 650 } | |
| 651 | |
| 652 void lineJoins() { | |
| 653 ctx.lineWidth=10; | |
| 654 ctx.lineJoin="miter"; | |
| 655 ctx.moveTo(width / 2 - 25, height / 4 - 10); | |
| 656 ctx.lineTo(width /2 + 25, height / 4); | |
| 657 ctx.lineTo(width / 2 - 25, height / 4 + 10); | |
| 658 ctx.stroke(); | |
| 659 ctx.lineJoin="round"; | |
| 660 ctx.moveTo(width / 2 - 25, height / 2 - 10); | |
| 661 ctx.lineTo(width /2 + 25, height / 2); | |
| 662 ctx.lineTo(width / 2 - 25, height / 2 + 10); | |
| 663 ctx.stroke(); | |
| 664 ctx.lineJoin="bevel"; | |
| 665 ctx.moveTo(width / 2 - 25, 3 * height / 4 - 10); | |
| 666 ctx.lineTo(width /2 + 25, 3 * height / 4); | |
| 667 ctx.lineTo(width / 2 - 25, 3 * height / 4 + 10); | |
| 668 ctx.stroke(); | |
| 669 } | |
| 670 | |
| 671 void saveRestore() { | |
| 672 ctx.font = "30px courier"; | |
| 673 ctx.fillStyle = "red"; | |
| 674 ctx.strokeStyle = "black"; | |
| 675 ctx.shadowBlur = 5; | |
| 676 ctx.shadowColor = "green"; | |
| 677 ctx.lineWidth = 1; | |
| 678 ctx.textAlign = "left"; | |
| 679 ctx.rotate(Math.PI / 30); | |
| 680 ctx.fillText("State 1", width /2, height / 6); | |
| 681 ctx.strokeText("State 1", width /2, height / 6); | |
| 682 ctx.save(); | |
| 683 | |
| 684 ctx.font = "40px sans serif"; | |
| 685 ctx.fillStyle = "blue"; | |
| 686 ctx.strokeStyle = "orange"; | |
| 687 ctx.shadowBlur = 8; | |
| 688 ctx.shadowOffsetX = 5; | |
| 689 ctx.shadowColor = "black"; | |
| 690 ctx.lineWidth = 2; | |
| 691 ctx.textAlign = "right"; | |
| 692 ctx.rotate(Math.PI / 30); | |
| 693 ctx.fillText("State 2", width /2, 2 * height / 6); | |
| 694 ctx.strokeText("State 2", width /2, 2 * height / 6); | |
| 695 ctx.save(); | |
| 696 | |
| 697 ctx.font = "50px times roman"; | |
| 698 ctx.fillStyle = "yellow"; | |
| 699 ctx.strokeStyle = "gray"; | |
| 700 ctx.shadowBlur = 8; | |
| 701 ctx.shadowOffsetX = 5; | |
| 702 ctx.shadowColor = "red"; | |
| 703 ctx.lineWidth = 3; | |
| 704 ctx.textAlign = "center"; | |
| 705 ctx.rotate(-Math.PI / 15); | |
| 706 ctx.fillText("State 3", width /2, 3 * height / 6); | |
| 707 ctx.strokeText("State 3", width /2, 3 * height / 6); | |
| 708 | |
| 709 ctx.restore(); | |
| 710 ctx.fillText("State 2", width /2, 4 * height / 6); | |
| 711 ctx.strokeText("State 2", width /2, 4 * height / 6); | |
| 712 | |
| 713 ctx.restore(); | |
| 714 ctx.fillText("State 1", width /2, 5 * height / 6); | |
| 715 ctx.strokeText("State 1", width /2, 5 * height / 6); | |
| 716 } | |
| 717 | |
| 718 void mirror() { | |
| 719 // translate context to center of canvas | |
| 720 ctx.translate(width / 2, height / 2); | |
| 721 | |
| 722 // flip context horizontally | |
| 723 ctx.scale(-1, 1); | |
| 724 | |
| 725 ctx.font = '30pt Calibri'; | |
| 726 ctx.textAlign = 'center'; | |
| 727 ctx.fillStyle = 'blue'; | |
| 728 ctx.fillText('Magic Mirror', 0, 0); | |
| 729 } | |
| 730 | |
| 731 void oval() { | |
| 732 var centerX = 0; | |
| 733 var centerY = 0; | |
| 734 var radius = 50; | |
| 735 | |
| 736 // save state | |
| 737 ctx.save(); | |
| 738 | |
| 739 // translate context | |
| 740 ctx.translate(width / 2, height / 2); | |
| 741 | |
| 742 // scale context horizontally | |
| 743 ctx.scale(2, 1); | |
| 744 | |
| 745 // draw circle which will be stretched into an oval | |
| 746 ctx.beginPath(); | |
| 747 ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); | |
| 748 | |
| 749 // restore to original state | |
| 750 ctx.restore(); | |
| 751 | |
| 752 // apply styling | |
| 753 ctx.fillStyle = '#8ED6FF'; | |
| 754 ctx.fill(); | |
| 755 ctx.lineWidth = 5; | |
| 756 ctx.strokeStyle = 'black'; | |
| 757 ctx.stroke(); | |
| 758 } | |
| 759 | |
| 760 void lineDash() { | |
| 761 ctx.setLineDash([ 5, 8, 3 ]); | |
| 762 ctx.strokeStyle = "#FF0000"; | |
| 763 ctx.strokeRect(width / 10, height / 10, width / 2, height / 25); | |
| 764 ctx.lineDashOffset = 1; | |
| 765 ctx.strokeStyle = "#00FF00"; | |
| 766 ctx.strokeRect(width / 4, height / 5, width / 20, height / 8); | |
| 767 ctx.setLineDash([]); | |
| 768 ctx.strokeStyle = "#0000FF"; | |
| 769 ctx.strokeStyle = "rgba(128,128,128, 0.5)"; | |
| 770 ctx.strokeRect(width / 5, height / 10, width / 2, height / 8); | |
| 771 log("Width = $width"); | |
| 772 } | |
| 773 | |
| 774 // TODO(gram) - apparently a canvas can have only one op in its lifetime, | |
| 775 // so this test won't work until we can use off-screen canvases. | |
| 776 void compositeOp() { | |
| 777 var num = 0; | |
| 778 ctx.font = '10pt Verdana'; | |
| 779 var numPerRow = width ~/ 95; | |
| 780 log("Width = $width, numPerRow = $numPerRow\n"); | |
| 781 // For some bizarre reason, we get width = 0 above. | |
| 782 // Kludge this: | |
| 783 for (var mode in [ 'source-atop', 'source-in', | |
| 784 'source-out', 'source-over', | |
| 785 'destination-atop', 'destination-in', | |
| 786 'destination-out', 'destination-over', | |
| 787 'lighter', 'darker', | |
| 788 'xor', 'copy']) { | |
| 789 var col = num % numPerRow; | |
| 790 var row = num ~/ numPerRow; | |
| 791 ctx.globalCompositeOperation = mode; | |
| 792 ctx.translate(95 * col, 100 * row); | |
| 793 log("Doing $mode at row $row, col $col\n"); | |
| 794 ctx.beginPath(); | |
| 795 ctx.rect(0, 0, 55, 55); | |
| 796 ctx.fillStyle = 'blue'; | |
| 797 ctx.fill(); | |
| 798 ctx.beginPath(); | |
| 799 ctx.arc(50, 50, 35, 0, 2 * Math.PI, false); | |
| 800 ctx.fillStyle = 'red'; | |
| 801 ctx.fill(); | |
| 802 ctx.fillStyle = 'black'; | |
| 803 ctx.fillText(mode, 0, 100); | |
| 804 ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| 805 ++num; | |
| 806 } | |
| 807 } | |
| 808 | |
| 809 void loadImage() { | |
| 810 var imageObj = new ImageElement(); | |
| 811 imageObj.on.load.add((e) { | |
| 812 ctx.drawImage(imageObj, 69, 50); | |
| 813 }); | |
| 814 imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader. bmp'; | |
| 346 } | 815 } |
| 347 | 816 |
| 348 void update() { | 817 void update() { |
| 349 drawScene(); | 818 if (is3d) { |
| 819 drawScene(); | |
| 820 } else { | |
| 821 if (!isDirty) return; | |
| 822 resetCanvas(); | |
| 823 switch(testnum) { | |
| 824 case 0: | |
| 825 helloWorld(); | |
| 826 break; | |
| 827 case 1: | |
| 828 smiley(); | |
| 829 break; | |
| 830 case 2: | |
| 831 blocks(); | |
| 832 break; | |
| 833 case 3: | |
| 834 squares(); | |
| 835 break; | |
| 836 case 4: | |
| 837 grid(); | |
| 838 break; | |
| 839 case 5: | |
| 840 strokeLines(); | |
| 841 break; | |
| 842 case 6: | |
| 843 lineJoin(); | |
| 844 break; | |
| 845 case 7: | |
| 846 colors(); | |
| 847 break; | |
| 848 case 8: | |
| 849 rot("Dart"); | |
| 850 break; | |
| 851 case 9: | |
| 852 alpha(); | |
| 853 break; | |
| 854 case 10: | |
| 855 scale(); | |
| 856 break; | |
| 857 case 11: | |
| 858 curves(); | |
| 859 break; | |
| 860 case 12: | |
| 861 shadows(); | |
| 862 break; | |
| 863 case 13: | |
| 864 lineJoins(); | |
| 865 break; | |
| 866 case 14: | |
| 867 saveRestore(); | |
| 868 break; | |
| 869 case 15: | |
| 870 mirror(); | |
| 871 break; | |
| 872 case 16: | |
| 873 oval(); | |
| 874 break; | |
| 875 case 17: | |
| 876 lineDash(); | |
| 877 break; | |
| 878 case 18: | |
| 879 loadImage(); | |
| 880 return; // keep dirty | |
| 881 //compositeOp(); | |
| 882 break; | |
| 883 default: | |
| 884 testnum = 0; | |
| 885 update(); | |
| 886 break; | |
| 887 } | |
| 888 isDirty = false; | |
| 889 } | |
| 350 } | 890 } |
| 351 | 891 |
| 352 /* | 892 /* |
| 353 TODO(gram): below are the current entry points for input events for the | 893 TODO(gram): below are the current entry points for input events for the |
| 354 native code version. We need to integrate these somehow with the WebGL | 894 native code version. We need to integrate these somehow with the WebGL |
| 355 version: | 895 version: |
| 356 | 896 */ |
| 357 onMotionDown(num when, num x, num y) {} | 897 onMotionDown(num when, num x, num y) { |
| 898 ++testnum; | |
| 899 isDirty = true; | |
| 900 log("Marking dirty"); | |
| 901 } | |
| 358 onMotionUp(num when, num x, num y) {} | 902 onMotionUp(num when, num x, num y) {} |
| 359 onMotionMove(num when, num x, num y) {} | 903 onMotionMove(num when, num x, num y) {} |
| 360 onMotionCancel(num when, num x, num y) {} | 904 onMotionCancel(num when, num x, num y) {} |
| 361 onMotionOutside(num when, num x, num y) {} | 905 onMotionOutside(num when, num x, num y) {} |
| 362 onMotionPointerDown(num when, num x, num y) {} | 906 onMotionPointerDown(num when, num x, num y) { |
| 907 ++testnum; | |
| 908 isDirty = true; | |
| 909 log("Marking dirty"); | |
| 910 } | |
| 911 | |
| 363 onMotionPointerUp(num when, num x, num y) {} | 912 onMotionPointerUp(num when, num x, num y) {} |
| 364 onKeyDown(num when, int flags, int keycode, int metastate, int repeat) {} | 913 |
| 914 onKeyDown(num when, int flags, int keycode, int metastate, int repeat) { | |
| 915 ++testnum; | |
| 916 isDirty = true; | |
| 917 log("Marking dirty"); | |
| 918 } | |
| 919 | |
| 365 onKeyUp(num when, int flags, int keycode, int metastate, int repeat) {} | 920 onKeyUp(num when, int flags, int keycode, int metastate, int repeat) {} |
| 921 | |
| 366 onKeyMultiple(num when, int flags, int keycode, int metastate, int repeat) { | 922 onKeyMultiple(num when, int flags, int keycode, int metastate, int repeat) { |
| 367 } | 923 } |
| 368 */ | 924 |
| 369 | 925 |
| OLD | NEW |