Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restart the spiral iterator of the Multiply test when maxing out the grid size #53

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given all the comments you had to add above, maybe just do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried but the result was more involved. The problem are with add(), subtract() and multiply(). These methods expects Point, Size or just a Number. With Point act as Size, we have to deal with the Number as a special case.

So let's have this be fixed in a separate change.

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