Skip to content

Commit

Permalink
Restart the spiral iterator of the Multiply test when maxing out the …
Browse files Browse the repository at this point in the history
…grid size

WebKit#52

Refactor the spiral iterator into a separate class. Keep calling its next() method
to get the coordinates ofthe next cell. When its isDone() returns true create a
new iterator and make the tiles of upper layers have less lightness than the ones
on the lower layers.

Add a new class for the roundedRect tile called "Tile". This class can handle the
location, size and animation of the Tile.
  • Loading branch information
shallawa committed Apr 26, 2024
1 parent f1c7edb commit 9307820
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 93 deletions.
26 changes: 26 additions & 0 deletions MotionMark/resources/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,18 +265,41 @@ Point = Utilities.createClass(
return this.x;
},

// Used when the point object is used as a size object.
set width(w)
{
this.x = w;
},

// Used when the point object is used as a size object.
get height()
{
return this.y;
},

// Used when the point object is used as a size object.
set height(h)
{
this.y = h;
},

// Used when the point object is used as a size object.
get center()
{
return new Point(this.x / 2, this.y / 2);
},

// Used when the point object is used as a size object.
area: function() {
return this.x * this.y;
},

// Used when the point object is used as a size object.
expand(width, height) {
this.x += width;
this.y += height;
},

str: function()
{
return "x = " + this.x + ", y = " + this.y;
Expand Down Expand Up @@ -320,6 +343,9 @@ Point = Utilities.createClass(
}
});

// FIXME: Add a seprate class for Size.
let Size = Point;

Utilities.extendObject(Point, {
zero: new Point(0, 0),

Expand Down
296 changes: 203 additions & 93 deletions MotionMark/tests/core/resources/multiply.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2017 Apple Inc. All rights reserved.
* Copyright (C) 2015-2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand All @@ -24,120 +24,230 @@
*/
(function() {

var SpiralIterator = Utilities.createClass(
function(gridSize)
{
this.gridSize = gridSize;
this.current = Point.zero;
this.direction = this.directions.right;
this.size = new Size(1, 1);
this.count = 0;
}, {

directions: {
top: 0,
left: 1,
bottom: 2,
right: 3
},

moves: [
new Size(0, -1), // top
new Size(-1, 0), // left
new Size(0, +1), // bottom
new Size(+1, 0) // right
],

isDone: function() {
return this.count >= this.gridSize.area();
},

next: function() {
++this.count;

if (this.isDone())
return;

let direction = this.direction;
let move = this.moves[direction];

if (Math.abs(this.current.x) == Math.abs(this.current.y)) {
// Turn left.
direction = (direction + 1) % 4;

if (this.current.x >= 0 && this.current.y >= 0) {
if (this.size.width < Math.min(this.gridSize.width, this.gridSize.height))
this.size.expand(2, 2);
else if (this.size.width < this.gridSize.width)
++this.size.width;

move = this.moves[this.directions.right];
} else
move = this.moves[direction];
}

if (this.count < this.size.area()) {
this.current = this.current.add(move);
this.direction = direction;
return;
}

// Make a U-turn.
this.direction = (this.direction + 1) % 4;

if (this.direction == this.directions.left || this.direction == this.directions.right)
this.current = this.current.add(this.moves[this.direction].multiply(this.size.width++));
else
this.current = this.current.add(this.moves[this.direction].multiply(this.size.height++));

this.direction = (this.direction + 1) % 4;
}
});

var Tile = Utilities.createClass(
function(stage, coordinate, iteratorIndex)
{
this.stage = stage;
this.coordinate = coordinate;
this.iteratorIndex = iteratorIndex;

this.roundedRect = Utilities.createElement('div', {
class: "div-" + Stage.randomInt(0, 5)
}, stage.element);

this.distance = this.coordinate.length();
this.step = Math.max(3, this.distance / 1.5);
this.rotate = Stage.randomInt(0, 359);

this.move();
this.resize();
this.hide();
}, {

move: function() {
let tileSize = this.stage.tileSize;

let location = this.stage.size.center;
location = location.add(this.coordinate.multiply(tileSize));
location = location.subtract(tileSize.multiply(0.5));

this.roundedRect.style.left = location.x + 'px';
this.roundedRect.style.top = location.y + 'px';
},

resize: function() {
let tileSize = this.stage.tileSize;

this.roundedRect.style.width = tileSize.width + 'px';
this.roundedRect.style.height = tileSize.height + 'px';
},

show: function() {
this.roundedRect.style.display = "block";
},

hide: function() {
this.roundedRect.style.display = "none";
},

backgroundColor: function() {
let influence = Math.max(.01, 1 - (this.distance * this.stage.distanceFactor * (1 + this.iteratorIndex)));
let l = this.stage.l * Math.tan(influence);
return this.stage.hslPrefix + l + "%," + influence + ")";
},

animate: function() {
this.rotate += this.step;
this.roundedRect.style.transform = "rotate(" + this.rotate + "deg)";
this.roundedRect.style.backgroundColor = this.backgroundColor();
}
});

var MultiplyStage = Utilities.createSubclass(Stage,
function()
{
Stage.call(this);
this.tiles = [];
this._offsetIndex = 0;
this.activeLength = 0;
this.iteratorIndex = 0;
}, {

visibleCSS: [
["display", "none", "block"]
],
totalRows: 68,
rowsCount: 59,

initialize: function(benchmark, options)
{
initialize: function(benchmark, options) {
Stage.prototype.initialize.call(this, benchmark, options);
var tileSize = Math.round(this.size.height / this.totalRows);
if (options.visibleCSS)
this.visibleCSS = options.visibleCSS;

// Fill the scene with elements
var x = Math.round((this.size.width - tileSize) / 2);
var y = Math.round((this.size.height - tileSize) / 2);
var tileStride = tileSize;
var direction = 0;
var spiralCounter = 2;
var nextIndex = 1;
var maxSide = Math.floor(y / tileStride) * 2 + 1;
this._centerSpiralCount = maxSide * maxSide;
for (var i = 0; i < this._centerSpiralCount; ++i) {
this._addTile(x, y, tileSize, Stage.randomInt(0, 359));

if (i == nextIndex) {
direction = (direction + 1) % 4;
spiralCounter++;
nextIndex += spiralCounter >> 1;
}
if (direction == 0)
x += tileStride;
else if (direction == 1)
y -= tileStride;
else if (direction == 2)
x -= tileStride;
else
y += tileStride;
}

this._sidePanelCount = maxSide * Math.floor((this.size.width - x) / tileStride) * 2;
for (var i = 0; i < this._sidePanelCount; ++i) {
var sideX = x + Math.floor(Math.floor(i / maxSide) / 2) * tileStride;
var sideY = y - tileStride * (i % maxSide);
this.rowsCount = this.rowsCount;

let tileSide = Math.round(this.size.height / this.rowsCount);
let columnsCount = Math.floor(this.size.width / tileSide);
if (columnsCount % 2 == 0)
--columnsCount;

this.tileSize = new Size(tileSide, tileSide);
this.tileGrid = new Size(columnsCount, this.rowsCount);
this.iterator = new SpiralIterator(this.tileGrid);

while (!this.iterator.isDone())
this.tiles.push(this.createTile());
},

if (Math.floor(i / maxSide) % 2 == 1)
sideX = this.size.width - sideX - tileSize + 1;
this._addTile(sideX, sideY, tileSize, Stage.randomInt(0, 359));
createTile: function() {
if (this.iterator.isDone()) {
this.iterator = new SpiralIterator(this.tileGrid);
this.iteratorIndex++;
}
let tile = new Tile(this, this.iterator.current, this.iteratorIndex);
this.iterator.next();
return tile;
},

_addTile: function(x, y, tileSize, rotateDeg)
{
var tile = Utilities.createElement("div", { class: "div-" + Stage.randomInt(0,6) }, this.element);
var halfTileSize = tileSize / 2;
tile.style.left = x + 'px';
tile.style.top = y + 'px';
tile.style.width = tileSize + 'px';
tile.style.height = tileSize + 'px';
var visibleCSS = this.visibleCSS[this.tiles.length % this.visibleCSS.length];
tile.style[visibleCSS[0]] = visibleCSS[1];

var distance = 1 / tileSize * this.size.multiply(0.5).subtract(new Point(x + halfTileSize, y + halfTileSize)).length();
this.tiles.push({
element: tile,
rotate: rotateDeg,
step: Math.max(3, distance / 1.5),
distance: distance,
active: false,
visibleCSS: visibleCSS,
});
complexity: function() {
return this.activeLength;
},

complexity: function()
{
return this._offsetIndex;
activeTiles: function() {
return this.tiles.slice(0, this.activeLength);
},

tune: function(count)
{
this._offsetIndex = Math.max(0, Math.min(this._offsetIndex + count, this.tiles.length));
this._distanceFactor = 1.5 * (1 - 0.5 * Math.max(this._offsetIndex - this._centerSpiralCount, 0) / this._sidePanelCount) / Math.sqrt(this._offsetIndex);
inactiveTiles: function(end) {
return this.tiles.slice(this.activeLength, end);
},

animate: function()
{
var progress = this._benchmark.timestamp % 10000 / 10000;
var bounceProgress = Math.sin(2 * Math.abs( 0.5 - progress));
var l = Utilities.lerp(bounceProgress, 20, 50);
var hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,";

for (var i = 0; i < this._offsetIndex; ++i) {
var tile = this.tiles[i];
tile.active = true;
tile.element.style[tile.visibleCSS[0]] = tile.visibleCSS[2];
tile.rotate += tile.step;
tile.element.style.transform = "rotate(" + tile.rotate + "deg)";

var influence = Math.max(.01, 1 - (tile.distance * this._distanceFactor));
tile.element.style.backgroundColor = hslPrefix + l * Math.tan(influence / 1.25) + "%," + influence + ")";
}
reusableTune: function(count) {
if (count == 0)
return;

for (var i = this._offsetIndex; i < this.tiles.length && this.tiles[i].active; ++i) {
var tile = this.tiles[i];
tile.active = false;
tile.element.style[tile.visibleCSS[0]] = tile.visibleCSS[1];
if (count < 0) {
this.activeLength = Math.max(this.activeLength + count, 0);
for (var i = this.activeLength; i < this.tiles.length; ++i)
this.tiles[i].hide();
return;
}

let inactiveTiles = this.inactiveTiles(this.activeLength + count);
for (let tile of inactiveTiles)
tile.show();

for (let i = inactiveTiles.length; i < count; ++i)
this.tiles.push(this.createTile());

this.activeLength += count;
},

reusableAnimate: function() {
for (let tile of this.activeTiles())
tile.animate();
},

tune: function(count) {
this.reusableTune(count);

let totalSpiralCount = this.tileGrid.area();
let centerSpiralCount = this.tileGrid.height * this.tileGrid.height;
let sideSpiralCount = totalSpiralCount - centerSpiralCount;
let activeSideSpiralCount = Math.min(Math.max(this.activeLength - centerSpiralCount, 0), sideSpiralCount);
let activeTotalSpiralCount = Math.min(this.activeLength, totalSpiralCount);
this.distanceFactor = 1.5 * (1 - 0.5 * activeSideSpiralCount / sideSpiralCount) / Math.sqrt(activeTotalSpiralCount);
},

animate: function() {
let progress = this._benchmark.timestamp % 10000 / 10000;
let bounceProgress = Math.sin(2 * Math.abs(0.5 - progress));
this.l = Utilities.lerp(bounceProgress, 20, 50);
this.hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,";

this.reusableAnimate();
}
});

Expand Down

0 comments on commit 9307820

Please sign in to comment.