| Index: samples/openglui/src/raytrace.dart
|
| ===================================================================
|
| --- samples/openglui/src/raytrace.dart (revision 17737)
|
| +++ samples/openglui/src/raytrace.dart (working copy)
|
| @@ -13,6 +13,8 @@
|
| import 'gl.dart';
|
| import 'dart:math' as Math;
|
|
|
| +WebGLRenderingContext gl = null;
|
| +
|
| // Note: The first line of the fragment shader ("precision mediump float")
|
| // is not portable. It is required for WebGL and OpenGL ES. Desktop OpenGL
|
| // does not use precision specifiers. Some desktop systems treat this as a
|
| @@ -299,14 +301,17 @@
|
| var cameraCenter = vectAdd(cameraFrom, vectMul(cameraDir, cameraPersp));
|
|
|
| // cameraCenter + cameraUp + cameraLeft * ratio
|
| - var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp),
|
| - vectMul(cameraLeft, ratio));
|
| - var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp),
|
| - vectMul(cameraLeft, ratio));
|
| - var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp),
|
| - vectMul(cameraLeft, ratio));
|
| - var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp),
|
| - vectMul(cameraLeft, ratio));
|
| +log("cameraLeft = ${cameraLeft}");
|
| +log("ratio = ${ratio}");
|
| + var vl = vectMul(cameraLeft, ratio);
|
| + var cameraTopLeft = vectAdd(vectAdd(cameraCenter, cameraUp), vl);
|
| + //vectMul(cameraLeft, ratio));
|
| + var cameraBotLeft = vectAdd(vectSub(cameraCenter, cameraUp), vl);
|
| + //vectMul(cameraLeft, ratio));
|
| + var cameraTopRight = vectSub(vectAdd(cameraCenter, cameraUp), vl);
|
| + //vectMul(cameraLeft, ratio));
|
| + var cameraBotRight = vectSub(vectSub(cameraCenter, cameraUp), vl);
|
| + //vectMul(cameraLeft, ratio));
|
|
|
| var corners = [];
|
| pushVec(cameraTopRight, corners);
|
| @@ -330,40 +335,591 @@
|
| }
|
| }
|
|
|
| -void setup(int width, int height) {
|
| - initShaders();
|
| - gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
| - gl.clearDepth(1.0);
|
| - initBuffers();
|
| - resize(width, height);
|
| +bool is3d = false;
|
| +var ctx;
|
| +var width, height;
|
| +int testnum = 3;
|
| +bool isDirty = true;
|
| +
|
| +void setup(canvas, int w, int h) {
|
| + if (canvas == null) {
|
| + canvas = new CanvasElement(width: w, height: h);
|
| + } else {
|
| + // called from gl_driver.dart.
|
| + // This is a kludge; we need a clean way of handling events.
|
| + canvas.on.mouseDown.add((e) {
|
| + ++testnum;
|
| + });
|
| + }
|
| + if (is3d) {
|
| + gl = canvas.getContext("webgl");
|
| + initShaders();
|
| + gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
| + gl.clearDepth(1.0);
|
| + initBuffers();
|
| + } else {
|
| + ctx = canvas.getContext("2d");
|
| + if (ctx == null)
|
| + throw "Failed to get 2D context";
|
| + }
|
| + resize(w, h);
|
| + log("Done setup");
|
| }
|
|
|
| -void resize(int width, int height) {
|
| - ratio = width / height;
|
| - gl.viewport(0, 0, width, height);
|
| - t -= 0.03;
|
| - drawScene();
|
| +void resize(int w, int h) {
|
| + width = w;
|
| + height = h;
|
| + if (is3d) {
|
| + gl.viewport(0, 0, width, height);
|
| + ratio = width / height;
|
| + t -= 0.03;
|
| + drawScene();
|
| + }
|
| }
|
|
|
| +resetCanvas() {
|
| + ctx.globalCompositeOperation = "source-over";
|
| + ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| + ctx.fillStyle = "#FFFFFF";
|
| + ctx.clearRect(0, 0, width, height);
|
| + ctx.shadowOffsetX = ctx.shadowOffsetY = ctx.shadowBlur = 0.0;
|
| + ctx.beginPath();
|
| +}
|
| +
|
| +helloWorld() {
|
| + ctx.font = "30px Courier";
|
| + ctx.strokeStyle = "#7F7F7F";
|
| + ctx.fillStyle = "#7F7F7F";
|
| + ctx.textAlign = "center";
|
| + ctx.lineWidth = 2;
|
| + ctx.strokeText("Align Center", width / 2, height / 4);
|
| + ctx.textAlign = "left";
|
| + ctx.fillText("Align Left", width / 2, height / 2);
|
| + ctx.textAlign = "right";
|
| + ctx.fillText("Align Right", width / 2, 3 * height / 4);
|
| +}
|
| +
|
| +blocks() {
|
| + ctx.fillStyle = "#FF0000";
|
| + ctx.fillRect(width / 10, height / 10, width / 2, height / 25);
|
| + ctx.fillStyle = "#00FF00";
|
| + ctx.fillRect(width / 4, height / 5, width / 20, height / 8);
|
| + //ctx.fillStyle = "rgba(0,0,255,0.8)";
|
| + ctx.strokeStyle = "rgba(128,128,128, 0.5)";
|
| + //ctx.fillStyle = "#7F7F7F";
|
| + ctx.strokeRect(width / 5, height / 10, width / 2, height / 8);
|
| +}
|
| +
|
| +square(left, top, width, height) {
|
| + ctx.beginPath();
|
| + ctx.moveTo(left, top);
|
| + ctx.lineTo(left + width, top);
|
| + ctx.lineTo(left + width, top + height);
|
| + ctx.lineTo(left, top + height);
|
| + ctx.closePath(); //lineTo(left, top);
|
| +}
|
| +
|
| +squares() {
|
| + ctx.strokeStyle = "black";
|
| + ctx.fillStyle = "#FF0000";
|
| + ctx.lineWidth = 4;
|
| + square(width / 10, height / 10, width / 2, height / 25);
|
| + ctx.fill();
|
| + ctx.stroke();
|
| + ctx.fillStyle = "#00FF00";
|
| + square(width / 4, height / 5, width / 20, height / 8);
|
| + ctx.fill();
|
| + ctx.stroke();
|
| + ctx.fillStyle = "rgba(128,128,128, 0.5)";
|
| + square(width / 5, height / 10, width / 2, height / 8);
|
| + ctx.fill();
|
| + ctx.stroke();
|
| +}
|
| +
|
| +lineJoin() {
|
| + ctx.strokeStyle = "black";
|
| + ctx.fillStyle = "#FF0000";
|
| + ctx.lineWidth = 8;
|
| + ctx.lineJoin = "round";
|
| + square(width / 10, height / 10, width / 2, height / 25);
|
| + ctx.stroke();
|
| + ctx.fillStyle = "#00FF00";
|
| + ctx.lineJoin = "bevel";
|
| + square(width / 4, height / 5, width / 20, height / 8);
|
| + ctx.stroke();
|
| + ctx.fillStyle = "rgba(128,128,128, 0.5)";
|
| + ctx.lineJoin = "miter";
|
| + square(width / 5, height / 10, width / 2, height / 8);
|
| + ctx.stroke();
|
| +}
|
| +
|
| +grid() {
|
| + ctx.lineWidth = 1;
|
| + for (var x = 0.5; x < width; x += 10) {
|
| + ctx.moveTo(x, 0);
|
| + ctx.lineTo(x, height);
|
| + }
|
| + for (var y = 0.5; y < height; y += 10) {
|
| + ctx.moveTo(0, y);
|
| + ctx.lineTo(width, y);
|
| + }
|
| + ctx.strokeStyle = "#eee";
|
| + ctx.stroke();
|
| +}
|
| +
|
| +line(x1, y1, x2, y2) {
|
| + ctx.beginPath();
|
| + ctx.moveTo(x1, y1);
|
| + ctx.lineTo(x2, y2);
|
| +}
|
| +
|
| +strokeLines() {
|
| + ctx.lineWidth = height / 40;
|
| + ctx.strokeStyle = '#0000ff';
|
| + // butt line cap (top line)
|
| + line(width / 4, height / 4, 3 * width / 4, height / 4);
|
| + ctx.lineCap = 'butt';
|
| + ctx.stroke();
|
| +
|
| + // round line cap (middle line)
|
| + line(width / 4, height / 2, 3 * width / 4, height / 2);
|
| + ctx.lineCap = 'round';
|
| + ctx.stroke();
|
| +
|
| + // square line cap (bottom line)
|
| + line(width / 4, 3 * height / 4, 3 * width / 4, 3 * height / 4);
|
| + ctx.lineCap = 'square';
|
| + ctx.stroke();
|
| +}
|
| +
|
| +colors() {
|
| + var colors = [
|
| + "maroon",
|
| + "red",
|
| + "orange",
|
| + "yellow",
|
| + "olive",
|
| + "purple",
|
| + "fuschia",
|
| + "white",
|
| + "lime",
|
| + "green",
|
| + "navy",
|
| + "blue",
|
| + "aqua",
|
| + "teal",
|
| + "silver",
|
| + "gray",
|
| + "black"
|
| + ];
|
| +
|
| + var i = 1;
|
| + var yinc = height / (2 * colors.length + 1);
|
| +
|
| + ctx.textAlign = "center";
|
| + ctx.font = "${yinc}px Courier";
|
| +
|
| + for (var color in colors) {
|
| + ctx.fillStyle = color;
|
| + ctx.fillRect(width / 4, i * 2 * yinc, width / 2, 3 * yinc / 2);
|
| + ctx.fillStyle = (color == "gray") ? "white" : "gray";
|
| + ctx.fillText(color, width / 2, i * 2 * yinc + 7 * yinc / 8);
|
| + ++i;
|
| + }
|
| +}
|
| +
|
| +
|
| +smiley() {
|
| + ctx.translate(width / 2 - 80, height / 2 - 75);
|
| +
|
| + ctx.beginPath();
|
| + ctx.arc(100,80,75,0,Math.PI*2,true);
|
| + ctx.fillStyle = "rgb(255,255,204)";
|
| + ctx.fill();
|
| + ctx.stroke();
|
| +
|
| + ctx.fillStyle = "black";
|
| + ctx.beginPath();
|
| + ctx.arc(80,55,8,0,Math.PI*2,true);
|
| + ctx.fill();
|
| +
|
| + ctx.beginPath();
|
| + ctx.arc(120,55,8,0,Math.PI*2,true);
|
| + ctx.fill();
|
| +
|
| + ctx.beginPath();
|
| + ctx.arc(100,85,10,4,Math.PI*2,true);
|
| + ctx.stroke();
|
| +
|
| + ctx.beginPath();
|
| + ctx.arc(100,95,30,0,Math.PI,false);
|
| + ctx.stroke();
|
| +
|
| + ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| +}
|
| +
|
| +rot(txt1, [txt2, sx = 1.0, sy = 1.0]) {
|
| + if (txt2 == null) txt2 = txt1;
|
| + ctx.font = "50px sans serif";
|
| + ctx.translate(width / 2, height / 2);
|
| + ctx.textAlign = "right";
|
| + ctx.fillStyle = "red";
|
| + ctx.fillText(txt1, 0, 0);
|
| + ctx.rotate(Math.PI / 2);
|
| + ctx.scale(sx, sy);
|
| + ctx.fillStyle = "green";
|
| + ctx.fillText(txt2, 0, 0);
|
| + ctx.scale(sx, sy);
|
| + ctx.rotate(Math.PI / 2);
|
| + ctx.fillStyle = "blue";
|
| + ctx.fillText(txt1, 0, 0);
|
| + ctx.scale(sx, sy);
|
| + ctx.rotate(Math.PI / 2);
|
| + ctx.fillStyle = "yellow";
|
| + ctx.fillText(txt2, 0, 0);
|
| + ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| +}
|
| +
|
| +alpha() {
|
| + ctx.fillStyle = "gray";
|
| + ctx.fillRect(0, 0, width, height);
|
| + grid();
|
| + ctx.globalAlpha = 0.5;
|
| + rot("Global", "Alpha");
|
| + ctx.globalAlpha = 1.0;
|
| +}
|
| +
|
| +scale() {
|
| + rot("Scale", "Test", 0.8, 0.5);
|
| +}
|
| +
|
| +curves() {
|
| + // See http://www.html5canvastutorials.com/tutorials/html5-canvas-quadratic-curves/
|
| + ctx.beginPath();
|
| + ctx.moveTo(188, 150);
|
| + ctx.quadraticCurveTo(288, 0, 388, 150);
|
| + ctx.lineWidth = 2;
|
| + ctx.strokeStyle = 'red';
|
| + ctx.stroke();
|
| + // See http://www.html5canvastutorials.com/tutorials/html5-canvas-bezier-curves/
|
| + ctx.beginPath();
|
| + ctx.moveTo(188, 130);
|
| + ctx.bezierCurveTo(140, 10, 388, 10, 388, 170);
|
| + ctx.lineWidth = 5;
|
| + ctx.strokeStyle = 'blue';
|
| + ctx.stroke();
|
| + var x1, x2, y1, y2, ex, ey;
|
| + ctx.beginPath();
|
| + x1 = width / 4;
|
| + y1 = height / 2;
|
| + x2 = width / 2;
|
| + y2 = height / 4;
|
| + ex = 3 * width / 4;
|
| + ey = y1;
|
| + ctx.moveTo(x1, x2);
|
| + ctx.quadraticCurveTo(x2, y2, ex, ey);
|
| + ctx.lineWidth = 10;
|
| + ctx.strokeStyle = 'green';
|
| + ctx.stroke();
|
| +
|
| + ctx.beginPath();
|
| + ctx.moveTo(188, 130);
|
| + x1 = width / 8;
|
| + x2 = 7 * width / 8;
|
| + y1 = height / 50;
|
| + y2 = y1;
|
| + ex = x2;
|
| + ey = height / 2;
|
| + ctx.bezierCurveTo(x1, y1, x2, y2, ex, ey);
|
| + ctx.lineWidth = 7;
|
| + ctx.strokeStyle = 'black';
|
| + ctx.stroke();
|
| +}
|
| +
|
| +void shadows() {
|
| + ctx.shadowBlur=20;
|
| + ctx.shadowColor="black";
|
| + ctx.fillStyle="red";
|
| + var w = width / 2;
|
| + if (w > height / 2) w = height / 2;
|
| + ctx.fillRect(width / 2 - w / 2, height / 4 - w / 2, w, w);
|
| + ctx.shadowOffsetX = 10;
|
| + ctx.shadowOffsetY = 10;
|
| + ctx.shadowColor="green";
|
| + ctx.fillRect(width / 2 - w / 2, 3 * height / 4 - w / 2, w, w);
|
| +}
|
| +
|
| +void lineJoins() {
|
| + ctx.lineWidth=10;
|
| + ctx.lineJoin="miter";
|
| + ctx.moveTo(width / 2 - 25, height / 4 - 10);
|
| + ctx.lineTo(width /2 + 25, height / 4);
|
| + ctx.lineTo(width / 2 - 25, height / 4 + 10);
|
| + ctx.stroke();
|
| + ctx.lineJoin="round";
|
| + ctx.moveTo(width / 2 - 25, height / 2 - 10);
|
| + ctx.lineTo(width /2 + 25, height / 2);
|
| + ctx.lineTo(width / 2 - 25, height / 2 + 10);
|
| + ctx.stroke();
|
| + ctx.lineJoin="bevel";
|
| + ctx.moveTo(width / 2 - 25, 3 * height / 4 - 10);
|
| + ctx.lineTo(width /2 + 25, 3 * height / 4);
|
| + ctx.lineTo(width / 2 - 25, 3 * height / 4 + 10);
|
| + ctx.stroke();
|
| +}
|
| +
|
| +void saveRestore() {
|
| + ctx.font = "30px courier";
|
| + ctx.fillStyle = "red";
|
| + ctx.strokeStyle = "black";
|
| + ctx.shadowBlur = 5;
|
| + ctx.shadowColor = "green";
|
| + ctx.lineWidth = 1;
|
| + ctx.textAlign = "left";
|
| + ctx.rotate(Math.PI / 30);
|
| + ctx.fillText("State 1", width /2, height / 6);
|
| + ctx.strokeText("State 1", width /2, height / 6);
|
| + ctx.save();
|
| +
|
| + ctx.font = "40px sans serif";
|
| + ctx.fillStyle = "blue";
|
| + ctx.strokeStyle = "orange";
|
| + ctx.shadowBlur = 8;
|
| + ctx.shadowOffsetX = 5;
|
| + ctx.shadowColor = "black";
|
| + ctx.lineWidth = 2;
|
| + ctx.textAlign = "right";
|
| + ctx.rotate(Math.PI / 30);
|
| + ctx.fillText("State 2", width /2, 2 * height / 6);
|
| + ctx.strokeText("State 2", width /2, 2 * height / 6);
|
| + ctx.save();
|
| +
|
| + ctx.font = "50px times roman";
|
| + ctx.fillStyle = "yellow";
|
| + ctx.strokeStyle = "gray";
|
| + ctx.shadowBlur = 8;
|
| + ctx.shadowOffsetX = 5;
|
| + ctx.shadowColor = "red";
|
| + ctx.lineWidth = 3;
|
| + ctx.textAlign = "center";
|
| + ctx.rotate(-Math.PI / 15);
|
| + ctx.fillText("State 3", width /2, 3 * height / 6);
|
| + ctx.strokeText("State 3", width /2, 3 * height / 6);
|
| +
|
| + ctx.restore();
|
| + ctx.fillText("State 2", width /2, 4 * height / 6);
|
| + ctx.strokeText("State 2", width /2, 4 * height / 6);
|
| +
|
| + ctx.restore();
|
| + ctx.fillText("State 1", width /2, 5 * height / 6);
|
| + ctx.strokeText("State 1", width /2, 5 * height / 6);
|
| +}
|
| +
|
| +void mirror() {
|
| + // translate context to center of canvas
|
| + ctx.translate(width / 2, height / 2);
|
| +
|
| + // flip context horizontally
|
| + ctx.scale(-1, 1);
|
| +
|
| + ctx.font = '30pt Calibri';
|
| + ctx.textAlign = 'center';
|
| + ctx.fillStyle = 'blue';
|
| + ctx.fillText('Magic Mirror', 0, 0);
|
| +}
|
| +
|
| +void oval() {
|
| + var centerX = 0;
|
| + var centerY = 0;
|
| + var radius = 50;
|
| +
|
| + // save state
|
| + ctx.save();
|
| +
|
| + // translate context
|
| + ctx.translate(width / 2, height / 2);
|
| +
|
| + // scale context horizontally
|
| + ctx.scale(2, 1);
|
| +
|
| + // draw circle which will be stretched into an oval
|
| + ctx.beginPath();
|
| + ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
|
| +
|
| + // restore to original state
|
| + ctx.restore();
|
| +
|
| + // apply styling
|
| + ctx.fillStyle = '#8ED6FF';
|
| + ctx.fill();
|
| + ctx.lineWidth = 5;
|
| + ctx.strokeStyle = 'black';
|
| + ctx.stroke();
|
| +}
|
| +
|
| +void lineDash() {
|
| + ctx.setLineDash([ 5, 8, 3 ]);
|
| + ctx.strokeStyle = "#FF0000";
|
| + ctx.strokeRect(width / 10, height / 10, width / 2, height / 25);
|
| + ctx.lineDashOffset = 1;
|
| + ctx.strokeStyle = "#00FF00";
|
| + ctx.strokeRect(width / 4, height / 5, width / 20, height / 8);
|
| + ctx.setLineDash([]);
|
| + ctx.strokeStyle = "#0000FF";
|
| + ctx.strokeStyle = "rgba(128,128,128, 0.5)";
|
| + ctx.strokeRect(width / 5, height / 10, width / 2, height / 8);
|
| + log("Width = $width");
|
| +}
|
| +
|
| +// TODO(gram) - apparently a canvas can have only one op in its lifetime,
|
| +// so this test won't work until we can use off-screen canvases.
|
| +void compositeOp() {
|
| + var num = 0;
|
| + ctx.font = '10pt Verdana';
|
| + var numPerRow = width ~/ 95;
|
| + log("Width = $width, numPerRow = $numPerRow\n");
|
| +// For some bizarre reason, we get width = 0 above.
|
| +// Kludge this:
|
| + for (var mode in [ 'source-atop', 'source-in',
|
| + 'source-out', 'source-over',
|
| + 'destination-atop', 'destination-in',
|
| + 'destination-out', 'destination-over',
|
| + 'lighter', 'darker',
|
| + 'xor', 'copy']) {
|
| + var col = num % numPerRow;
|
| + var row = num ~/ numPerRow;
|
| + ctx.globalCompositeOperation = mode;
|
| + ctx.translate(95 * col, 100 * row);
|
| + log("Doing $mode at row $row, col $col\n");
|
| + ctx.beginPath();
|
| + ctx.rect(0, 0, 55, 55);
|
| + ctx.fillStyle = 'blue';
|
| + ctx.fill();
|
| + ctx.beginPath();
|
| + ctx.arc(50, 50, 35, 0, 2 * Math.PI, false);
|
| + ctx.fillStyle = 'red';
|
| + ctx.fill();
|
| + ctx.fillStyle = 'black';
|
| + ctx.fillText(mode, 0, 100);
|
| + ctx.setTransform(1, 0, 0, 1, 0, 0);
|
| + ++num;
|
| + }
|
| +}
|
| +
|
| +void loadImage() {
|
| + var imageObj = new ImageElement();
|
| + imageObj.on.load.add((e) {
|
| + ctx.drawImage(imageObj, 69, 50);
|
| + });
|
| + imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.bmp';
|
| +}
|
| +
|
| void update() {
|
| - drawScene();
|
| + if (is3d) {
|
| + drawScene();
|
| + } else {
|
| + if (!isDirty) return;
|
| + resetCanvas();
|
| + switch(testnum) {
|
| + case 0:
|
| + helloWorld();
|
| + break;
|
| + case 1:
|
| + smiley();
|
| + break;
|
| + case 2:
|
| + blocks();
|
| + break;
|
| + case 3:
|
| + squares();
|
| + break;
|
| + case 4:
|
| + grid();
|
| + break;
|
| + case 5:
|
| + strokeLines();
|
| + break;
|
| + case 6:
|
| + lineJoin();
|
| + break;
|
| + case 7:
|
| + colors();
|
| + break;
|
| + case 8:
|
| + rot("Dart");
|
| + break;
|
| + case 9:
|
| + alpha();
|
| + break;
|
| + case 10:
|
| + scale();
|
| + break;
|
| + case 11:
|
| + curves();
|
| + break;
|
| + case 12:
|
| + shadows();
|
| + break;
|
| + case 13:
|
| + lineJoins();
|
| + break;
|
| + case 14:
|
| + saveRestore();
|
| + break;
|
| + case 15:
|
| + mirror();
|
| + break;
|
| + case 16:
|
| + oval();
|
| + break;
|
| + case 17:
|
| + lineDash();
|
| + break;
|
| + case 18:
|
| + loadImage();
|
| +return; // keep dirty
|
| + //compositeOp();
|
| + break;
|
| + default:
|
| + testnum = 0;
|
| + update();
|
| + break;
|
| + }
|
| + isDirty = false;
|
| + }
|
| }
|
|
|
| /*
|
| TODO(gram): below are the current entry points for input events for the
|
| native code version. We need to integrate these somehow with the WebGL
|
| version:
|
| -
|
| -onMotionDown(num when, num x, num y) {}
|
| +*/
|
| +onMotionDown(num when, num x, num y) {
|
| + ++testnum;
|
| + isDirty = true;
|
| + log("Marking dirty");
|
| +}
|
| onMotionUp(num when, num x, num y) {}
|
| onMotionMove(num when, num x, num y) {}
|
| onMotionCancel(num when, num x, num y) {}
|
| onMotionOutside(num when, num x, num y) {}
|
| -onMotionPointerDown(num when, num x, num y) {}
|
| +onMotionPointerDown(num when, num x, num y) {
|
| + ++testnum;
|
| + isDirty = true;
|
| + log("Marking dirty");
|
| +}
|
| +
|
| onMotionPointerUp(num when, num x, num y) {}
|
| -onKeyDown(num when, int flags, int keycode, int metastate, int repeat) {}
|
| +
|
| +onKeyDown(num when, int flags, int keycode, int metastate, int repeat) {
|
| + ++testnum;
|
| + isDirty = true;
|
| + log("Marking dirty");
|
| +}
|
| +
|
| onKeyUp(num when, int flags, int keycode, int metastate, int repeat) {}
|
| +
|
| onKeyMultiple(num when, int flags, int keycode, int metastate, int repeat) {
|
| }
|
| -*/
|
|
|
| +
|
|
|