Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Unified Diff: third_party/WebKit/ManualTests/compositor-worker/physics/physics.js

Issue 1547893003: WIP - compositor worker mega patch. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/ManualTests/compositor-worker/physics/physics.js
diff --git a/third_party/WebKit/ManualTests/compositor-worker/physics/physics.js b/third_party/WebKit/ManualTests/compositor-worker/physics/physics.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b0b1e625ef1f36dffdc1190e228cca8db6fede5
--- /dev/null
+++ b/third_party/WebKit/ManualTests/compositor-worker/physics/physics.js
@@ -0,0 +1,489 @@
+(function(scope) {
+ "use strict";
+
+ scope.isMain = function() {
+ return scope.window;
+ };
+
+ var spheres = [];
+ var foils = [];
+ var gravity = 0.022;
+ var numBlurElements = 1;
+ var epsilon = 0.01;
+ var viewportHeight = 0;
+ var logo = null;
+ var janking = false;
+ var logoAngle = 0;
+ var logoSpeed = 5;
+
+ function lerp(a, b, t) {
+ return (1 - t) * a + t * b;
+ }
+
+ function setPosition(sphere, dt) {
+ var dx = sphere.dx + (sphere.vx * dt);
+ var dy = sphere.dy + (sphere.vy * dt);
+ for (var i = 0; i < numBlurElements; ++i) {
+ var t = i / (numBlurElements - 1 || 1);
+ var lx = lerp(sphere.dx, dx, 1 - t);
+ var ly = lerp(sphere.dy, dy, 1 - t);
+ if (isMain()) {
+ sphere.blurElements[i].style.transform =
+ "translate3d(" + lx + "px, " + ly + "px, 0px)";
+ } else {
+ var transform = sphere.blurElements[i].transform;
+ transform.m41 = lx;
+ transform.m42 = ly;
+ sphere.blurElements[i].transform = transform;
+ }
+ }
+ sphere.dx = dx;
+ sphere.dy = dy;
+ }
+
+ function updatePositions(dt) {
+ for (var i = 0; i < spheres.length; ++i)
+ setPosition(spheres[i], dt);
+ }
+
+ function applyGravity(dt) {
+ for (var i = 0; i < spheres.length; ++i)
+ spheres[i].vy += gravity * dt;
+ }
+
+ var re = /matrix\(.*, ([0-9\.]+)\)/;
+ function getAnimatedPosition(foil) {
+ if (isMain()) {
+ var match = window.getComputedStyle(foil.actor, null).webkitTransform.match(re);
+ return match ? parseFloat(match[1]) : 0;
+ } else {
+ return foil.actor.transform.m42;
+ }
+ }
+
+ function signedDistanceToLine(x1, y1, nx, ny, cx, cy) {
+ return (cx - x1) * nx + (cy - y1) * ny;
+ }
+
+ function normalizeBinormalComponent(component) {
+ if (component < epsilon && component > -epsilon)
+ return 0;
+ if (component < 0)
+ return -1;
+ return 1;
+ }
+
+ function doAABBoxesIntersect(x1, y1, w1, h1, x2, y2, w2, h2) {
+ if (x1 > x2 + w2)
+ return false;
+
+ if (x2 > x1 + w1)
+ return false;
+
+ if (y1 > y2 + h2)
+ return false;
+
+ if (y2 > y1 + h1)
+ return false;
+
+ return true;
+ }
+
+ function collideWithLine(x1, y1, x2, y2, nx, ny, vx, vy, sphere) {
+ var cx = sphere.dx + sphere.radius;
+ var cy = sphere.dy + sphere.radius;
+
+ var normalDotVelocity = nx * sphere.vx + ny * sphere.vy;
+ if (normalDotVelocity > 0)
+ return false;
+
+ var distanceToLine = signedDistanceToLine(x1, y1, nx, ny, cx, cy);
+ if (Math.abs(distanceToLine) > sphere.radius)
+ return false;
+
+ var binormX = normalizeBinormalComponent(x2 - x1);
+ var binormY = normalizeBinormalComponent(y2 - y1);
+
+ var distanceToBoundary1 = signedDistanceToLine(x1, y1, binormX, binormY, cx, cy);
+ if (distanceToBoundary1 < 0)
+ return false;
+
+ var distanceToBoundary2 = signedDistanceToLine(x2, y2, -binormX, -binormY, cx, cy);
+ if (distanceToBoundary2 < 0)
+ return false;
+
+ // We may have passed through the line. Let's fix that now.
+ var correction = sphere.radius - distanceToLine;
+ sphere.dx += correction * nx;
+ sphere.dy += correction * ny;
+
+ // Update velocity.
+ if (Math.abs(nx) > epsilon)
+ sphere.vx = vx - sphere.vx;
+
+ if (Math.abs(ny) > epsilon)
+ sphere.vy = vy - sphere.vy;
+
+ return true;
+ }
+
+ function collideWithSphere(a, b) {
+ if (!doAABBoxesIntersect(
+ a.dx, a.dy, a.radius * 2, a.radius * 2,
+ b.dx, b.dy, b.radius * 2, b.radius * 2))
+ return false;
+
+ var cax = a.dx + a.radius;
+ var cay = a.dy + a.radius;
+ var cbx = b.dx + b.radius;
+ var cby = b.dy + b.radius;
+
+ var deltaX = cax - cbx;
+ var deltaY = cay - cby;
+ var distance2 = deltaX * deltaX + deltaY * deltaY;
+
+ var minDistance2 = a.radius + b.radius;
+ minDistance2 = minDistance2 * minDistance2;
+ if (distance2 > minDistance2)
+ return false;
+
+ var futureDeltaX = (cax + a.vx * epsilon) - (cbx + b.vx * epsilon);
+ var futureDeltaY = (cay + a.vy * epsilon) - (cby + b.vy * epsilon);
+ var futureDistance2 = futureDeltaX * futureDeltaX + futureDeltaY * futureDeltaY;
+
+ // If we're not getting closer, bail.
+ if (futureDistance2 > distance2)
+ return false;
+
+ var distance = Math.sqrt(distance2);
+ deltaX /= distance;
+ deltaY /= distance;
+
+ var p = 2 * (a.vx * deltaX + a.vy * deltaY - b.vx * deltaX - b.vy * deltaY);
+ p /= (a.mass + b.mass);
+
+ a.vx = a.vx - p * b.mass * deltaX;
+ a.vy = a.vy - p * b.mass * deltaY;
+ b.vx = b.vx + p * a.mass * deltaX;
+ b.vy = b.vy + p * a.mass * deltaY;
+
+ // Now we may be intersecting. Let's fix that.
+ var deltaDistance = Math.sqrt(minDistance2) - distance;
+ var correction = deltaDistance * 0.5;
+ a.dx += correction * deltaX;
+ a.dy += correction * deltaY;
+ b.dx -= correction * deltaX;
+ b.dy -= correction * deltaY;
+
+ return true;
+ }
+
+ function collideWithFoil(sphere, foil) {
+ if (!doAABBoxesIntersect(
+ sphere.dx, sphere.dy, sphere.radius * 2, sphere.radius * 2,
+ foil.dx, foil.dy, foil.width, foil.height))
+ return;
+
+ var corners = [
+ [ foil.dx, foil.dy ],
+ [ foil.dx + foil.width, foil.dy ],
+ [ foil.dx + foil.width, foil.dy + foil.height ],
+ [ foil.dx, foil.dy + foil.height ]
+ ];
+
+ for (var i = 0; i < corners.length; ++i) {
+ var corner0 = corners[i];
+ var corner1 = corners[(i + 1) % corners.length];
+ var corner2 = corners[(i + 2) % corners.length];
+
+ var nx = normalizeBinormalComponent(corner1[0] - corner2[0]);
+ var ny = normalizeBinormalComponent(corner1[1] - corner2[1]);
+
+ if (collideWithLine(corner0[0], corner0[1], corner1[0], corner1[1], nx, ny, foil.vx, foil.vy, sphere))
+ return;
+ }
+
+ var corner = Object();
+ corner.radius = 0.1;
+ corner.mass = 50000; // really big.
+
+ for (var i = 0; i < corners.length; ++i) {
+ corner.dx = corners[i][0];
+ corner.dy = corners[i][1];
+ corner.vx = foil.vx;
+ corner.vy = foil.vy;
+ if (collideWithSphere(sphere, corner))
+ return;
+ }
+ }
+
+ function updateFoilProperties(foil) {
+ var dy = getAnimatedPosition(foil) + foil.top;
+ foil.vy = dy - foil.dy;
+ foil.dy = dy;
+ }
+
+ function processCollisions() {
+ for (var i = 0; i < foils.length; ++i)
+ updateFoilProperties(foils[i]);
+ for (var i = 0; i < spheres.length; ++i) {
+ for (var j = 0; j < foils.length; ++j)
+ collideWithFoil(spheres[i], foils[j]);
+ for (var j = i + 1; j < spheres.length; ++j)
+ collideWithSphere(spheres[i], spheres[j]);
+ }
+ }
+
+ function resetSpheres() {
+ for (var i = 0; i < spheres.length; ++i) {
+ var sphere = spheres[i];
+ var padding = 400;
+ if (sphere.dy > viewportHeight + padding) {
+ sphere.dx = sphere.initialX;
+ sphere.dy = sphere.initialY - 0.5 * viewportHeight;
+ sphere.vy = 0;
+ sphere.vx *= epsilon;
+ if (Math.abs(sphere.vx) > 100)
+ sphere.vx = 0;
+ }
+ }
+ }
+
+ function updateLogo() {
+ logoAngle += logoSpeed;
+ while (logoAngle > 360)
+ logoAngle -= 360;
+
+ logo.style.webkitTransform = "translateZ(0) rotate(" + logoAngle + "deg)";
+ }
+
+ scope.tick = function(timestamp) {
+ var dt = 1.0;
+ console.log("tick: " + timestamp);
+ if (scope.lastTimestamp) {
+ dt = (timestamp - scope.lastTimestamp) * 60;
+ }
+ scope.lastTimestamp = timestamp;
+
+ if (isMain()) {
+ updateLogo();
+ } else {
+ updatePositions(dt);
+ processCollisions();
+ updatePositions(dt);
+ applyGravity(dt);
+ resetSpheres();
+ }
+ scope.requestAnimationFrame(tick);
+ }
+
+ function createFoil(dx, dy, width, height, delay) {
+ var foilActor = document.createElement("div");
+ foilActor.className = "foil";
+ foilActor.style.left = dx + "px";
+ foilActor.style.top = dy + "px";
+ foilActor.style.width = width;
+ foilActor.style.height = height;
+ foilActor.style.webkitAnimation = "foil-motion 1s " + delay + "ms infinite alternate";
+ document.body.appendChild(foilActor);
+
+ var foil = new Object();
+ foil.actor = foilActor;
+ foil.left = dx;
+ foil.top = dy;
+ foil.width = width;
+ foil.height = height;
+ foil.dx = foil.left;
+ foil.dy = foil.top;
+ foil.vx = 0;
+ foil.vy = 0;
+
+ return foil;
+ }
+
+ function busySleep(duration) {
+ var start = new Date();
+ while ((new Date()).getTime() - start.getTime() < duration);
+ }
+
+ function doJank() {
+ busySleep(500);
+ if (janking)
+ window.setTimeout(doJank, 500);
+ }
+
+ function startJank() {
+ var startButton = document.getElementById("startJank");
+ startButton.style.webkitAnimation = "flip-hide 1s 1 forwards";
+
+ var stopButton = document.getElementById("stopJank");
+ stopButton.style.webkitAnimation = "flip-show 1s 1 forwards";
+
+ janking = true;
+
+ window.setTimeout(doJank, 16);
+ }
+
+ function stopJank() {
+ var startButton = document.getElementById("startJank");
+ startButton.style.webkitAnimation = "flip-show 1s 1 forwards";
+
+ var stopButton = document.getElementById("stopJank");
+ stopButton.style.webkitAnimation = "flip-hide 1s 1 forwards";
+
+ janking = false;
+ }
+
+ function toggle() {
+ if (janking)
+ stopJank();
+ else
+ startJank();
+ }
+
+ function createSphere(radius, topColor, bottomColor, dx, dy) {
+ var blurElements = [];
+ for (var i = 0; i < numBlurElements; ++i) {
+ var blurElement = document.createElement("div");
+ blurElement.className = "actor";
+ blurElement.style.background = "-webkit-gradient(linear, left top,"
+ + "left bottom, color-stop(0%," + topColor + "), color-stop(100%,"
+ + bottomColor + "))";
+ blurElement.style.width = (radius * 2) + "px";
+ blurElement.style.height = (radius * 2) + "px";
+ blurElement.style.borderRadius = radius + "px";
+ document.body.appendChild(blurElement);
+ var t = i / (numBlurElements - 1 || 1);
+ blurElement.style.opacity = lerp(0.4, 0.1, t);
+ blurElements.push(blurElement);
+ }
+
+ var sphere = new Object();
+ sphere.blurElements = blurElements;
+ sphere.radius = radius;
+ sphere.vx = 0;
+ sphere.vy = 0;
+ sphere.dx = sphere.initialX = dx;
+ sphere.dy = sphere.initialY = dy;
+ sphere.mass = radius * radius * Math.PI;
+
+ setPosition(sphere, dx, dy);
+
+ spheres.push(sphere);
+ }
+
+ function setupSpheres() {
+ var widths = [ 50, 10, 12, 30, 25, 10, 40, 10, 15, 10 ];
+ var colors = [
+ [ "rgba(53,53,255,1)", "rgba(28,41,127,1)" ],
+ [ "rgba(255,53,53,1)", "rgba(181,41,41,1)" ],
+ [ "rgba(8,160,0,1)", "rgba(24,102,23,1)" ],
+ [ "rgba(219,219,0,1)", "rgba(178,173,41,1)" ]
+ ];
+ var top = 100;
+ var left = 200;
+
+ var numSpheres = 80;
+ for (var i = 0; i < numSpheres; ++i) {
+ var radius = widths[i % widths.length];
+ var colorPair = colors[i % colors.length];
+ var noise = i % 2 == 0 ? -5 : 5;
+ var dx = left - radius + noise;
+ var dy = top - radius * 2;
+
+ createSphere(radius, colorPair[0], colorPair[1], dx, dy);
+
+ top -= (widths[i % widths.length] * 2) + 30;
+ if (i == Math.floor(numSpheres/3)) {
+ top = 500;
+ left = 650;
+ } else if (i == Math.floor((numSpheres*2)/3)) {
+ top = 200;
+ left = 950;
+ }
+ }
+ }
+
+ function setupFoils() {
+ var dxs = [ 50, 500, 700 ];
+ var dys = [ 150, 600, 300 ];
+ var delays = [ 0, 500, 250 ];
+ for (var i = 0; i < 3; ++i)
+ foils.push(createFoil(dxs[i], dys[i], 300, 30, delays[i]));
+ }
+
+ function setupScene() {
+ logo = document.getElementById("logo");
+ viewportHeight = document.documentElement.clientHeight;
+
+ var container = document.querySelector(".container");
+ container.addEventListener("mousedown", function(e) { e.preventDefault(); });
+ container.addEventListener("click", toggle);
+
+ setupFoils();
+ setupSpheres();
+ }
+
+ scope.initWorker = function() {
+ self.onmessage = function(e) {
+ spheres = e.data.spheres;
+ foils = e.data.foils;
+ viewportHeight = e.data.viewportHeight;
+ requestAnimationFrame(tick);
+ }
+ };
+
+ scope.initMain = function() {
+ setupScene();
+ scope.worker = new CompositorWorker("physics.js");
+
+ var message = {
+ 'spheres': [],
+ 'foils': [],
+ 'viewportHeight': viewportHeight
+ };
+
+ for (var i = 0; i < spheres.length; ++i) {
+ var sphere = spheres[i];
+ var sphereProxy = {
+ radius: sphere.radius,
+ vx: sphere.vx,
+ vy: sphere.vy,
+ dx: sphere.dx,
+ dy: sphere.dy,
+ initialX: sphere.initialX,
+ initialY: sphere.initialY,
+ mass:sphere.mass,
+ blurElements: []
+ };
+ for (var j = 0; j < sphere.blurElements.length; ++j)
+ sphereProxy.blurElements.push(new CompositorProxy(sphere.blurElements[j], ['transform']));
+ message.spheres.push(sphereProxy);
+ }
+
+ for (var i = 0; i < foils.length; ++i) {
+ var foil = foils[i];
+ var foilProxy = {
+ left: foil.left,
+ top: foil.top,
+ width:foil.width,
+ height:foil.height,
+ dx:foil.dx,
+ dy:foil.dy,
+ vx:foil.vx,
+ vy:foil.vy,
+ actor:new CompositorProxy(foil.actor, ['transform'])
+ }
+ message.foils.push(foilProxy);
+ }
+
+ worker.postMessage(message);
+ requestAnimationFrame(tick);
+ };
+
+ if (isMain())
+ initMain();
+ else
+ initWorker();
+})(self);
+

Powered by Google App Engine
This is Rietveld 408576698