Refactor batching system

This commit is contained in:
Tom Payne
2013-11-08 23:09:01 +01:00
parent 507662af0b
commit fef9ec155b
3 changed files with 235 additions and 159 deletions

View File

@@ -38,7 +38,7 @@ ol.renderer.vector.renderLineStringGeometry_ =
goog.asserts.assert(geometry instanceof ol.geom.LineString);
var lineStringGeometry = /** @type {ol.geom.LineString} */ (geometry);
var batch = batchGroup.getBatch(
style.zIndex, ol.replay.BatchType.STROKE_LINE);
style.zIndex, ol.replay.BatchType.LINE_STRING);
batch.setFillStrokeStyle(null, style.stroke);
batch.drawLineStringGeometry(lineStringGeometry);
};
@@ -59,7 +59,7 @@ ol.renderer.vector.renderMultiLineStringGeometry_ =
var multiLineStringGeometry = /** @type {ol.geom.MultiLineString} */
(geometry);
var batch = batchGroup.getBatch(
style.zIndex, ol.replay.BatchType.STROKE_LINE);
style.zIndex, ol.replay.BatchType.LINE_STRING);
batch.setFillStrokeStyle(null, style.stroke);
batch.drawMultiLineStringGeometry(multiLineStringGeometry);
};
@@ -80,8 +80,8 @@ ol.renderer.vector.renderMultiPolygonGeometry_ =
var multiPolygonGeometry = /** @type {ol.geom.MultiPolygon} */
(geometry);
var batch = batchGroup.getBatch(
style.zIndex, ol.replay.BatchType.STROKE_LINE);
batch.setFillStrokeStyle(null, style.stroke);
style.zIndex, ol.replay.BatchType.POLYGON);
batch.setFillStrokeStyle(style.fill, style.stroke);
batch.drawMultiPolygonGeometry(multiPolygonGeometry);
};
@@ -108,23 +108,12 @@ ol.renderer.vector.renderPointGeometry_ =
*/
ol.renderer.vector.renderPolygonGeometry_ =
function(batchGroup, geometry, style) {
var batchType;
if (goog.isNull(style.fill)) {
if (goog.isNull(style.stroke)) {
return;
} else {
batchType = ol.replay.BatchType.STROKE_RING;
}
} else {
if (goog.isNull(style.stroke)) {
batchType = ol.replay.BatchType.FILL_RING;
} else {
batchType = ol.replay.BatchType.FILL_STROKE_RING;
}
if (goog.isNull(style.fill) && goog.isNull(style.stroke)) {
return;
}
goog.asserts.assert(geometry instanceof ol.geom.Polygon);
var polygonGeometry = /** @type {ol.geom.Polygon} */ (geometry);
var batch = batchGroup.getBatch(style.zIndex, batchType);
var batch = batchGroup.getBatch(style.zIndex, ol.replay.BatchType.POLYGON);
batch.setFillStrokeStyle(style.fill, style.stroke);
batch.drawPolygonGeometry(polygonGeometry);
};

View File

@@ -28,34 +28,25 @@ ol.replay.canvas.Instruction = {
};
/**
* @typedef {{beginPath: boolean,
* fillPending: boolean,
* fillStyle: ?ol.style.Fill,
* strokePending: boolean,
* strokeStyle: ?ol.style.Stroke}}
*/
ol.replay.canvas.State;
/**
* @constructor
* @implements {ol.replay.IBatch}
* @protected
*/
ol.replay.canvas.Batch = function() {
/**
* @private
* @protected
* @type {Array}
*/
this.instructions_ = [];
this.instructions = [];
/**
* @private
* @protected
* @type {Array.<number>}
*/
this.coordinates_ = [];
this.coordinates = [];
/**
* @private
@@ -63,66 +54,40 @@ ol.replay.canvas.Batch = function() {
*/
this.pixelCoordinates_ = [];
/**
* @private
* @type {?ol.replay.canvas.State}
*/
this.state_ = {
beginPath: true,
fillPending: false,
fillStyle: null,
strokePending: false,
strokeStyle: null
};
};
/**
* @param {Array.<Array.<number>>} coordinates Coordinates.
* @param {boolean} close Close.
* @private
* @protected
* @return {number} End.
*/
ol.replay.canvas.Batch.prototype.appendCoordinates_ =
ol.replay.canvas.Batch.prototype.appendCoordinates =
function(coordinates, close) {
goog.asserts.assert(!goog.isNull(this.state_));
var end = this.coordinates_.length;
var end = this.coordinates.length;
var i, ii;
for (i = 0, ii = coordinates.length; i < ii; ++i) {
this.coordinates_[end++] = coordinates[i][0];
this.coordinates_[end++] = coordinates[i][1];
this.coordinates[end++] = coordinates[i][0];
this.coordinates[end++] = coordinates[i][1];
}
if (close) {
this.coordinates_[end++] = coordinates[0][0];
this.coordinates_[end++] = coordinates[0][1];
this.coordinates[end++] = coordinates[0][0];
this.coordinates[end++] = coordinates[0][1];
}
return end;
};
/**
* @private
*/
ol.replay.canvas.Batch.prototype.beginPath_ = function() {
goog.asserts.assert(!goog.isNull(this.state_));
if (this.state_.beginPath) {
this.instructions_.push([ol.replay.canvas.Instruction.BEGIN_PATH]);
this.state_.beginPath = false;
}
};
/**
* @param {CanvasRenderingContext2D} context Context.
* @param {goog.vec.Mat4.AnyType} transform Transform.
*/
ol.replay.canvas.Batch.prototype.draw = function(context, transform) {
goog.asserts.assert(goog.isNull(this.state_));
var pixelCoordinates = ol.replay.transformCoordinates(
this.coordinates_, transform, this.pixelCoordinates_);
this.coordinates, transform, this.pixelCoordinates_);
this.pixelCoordinates_ = pixelCoordinates; // FIXME ?
var instructions = this.instructions_;
var instructions = this.instructions;
var i = 0;
var j, jj;
for (j = 0, jj = instructions.length; j < jj; ++j) {
@@ -161,104 +126,107 @@ ol.replay.canvas.Batch.prototype.draw = function(context, transform) {
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.drawLineStringGeometry =
function(lineStringGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
this.beginPath_();
var end = this.appendCoordinates_(lineStringGeometry.getCoordinates(), false);
this.instructions_.push([ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end]);
this.state_.strokePending = true;
};
ol.replay.canvas.Batch.prototype.drawLineStringGeometry = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.drawMultiLineStringGeometry =
function(multiLineStringGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
var coordinatess = multiLineStringGeometry.getCoordinatess();
var i, ii;
for (i = 0, ii = coordinatess.length; i < ii; ++i) {
this.beginPath_();
var end = this.appendCoordinates_(coordinatess[i], false);
this.instructions_.push(
[ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end]);
}
this.state_.strokePending = true;
};
goog.abstractMethod;
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.drawMultiPolygonGeometry =
function(multiPolygonGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
var ringss = multiPolygonGeometry.getRingss();
var i, ii;
for (i = 0, ii = ringss.length; i < ii; ++i) {
var rings = ringss[i];
var j, jj;
for (j = 0, jj = rings.length; j < jj; ++j) {
this.beginPath_();
var end = this.appendCoordinates_(rings[j], true);
this.instructions_.push(
[ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end],
[ol.replay.canvas.Instruction.CLOSE_PATH]);
}
}
this.state_.fillPending = true;
this.state_.strokePending = true;
};
ol.replay.canvas.Batch.prototype.drawPolygonGeometry = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.drawPolygonGeometry =
function(polygonGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
var rings = polygonGeometry.getRings();
var i, ii;
for (i = 0, ii = rings.length; i < ii; ++i) {
this.beginPath_();
var end = this.appendCoordinates_(rings[i], true);
this.instructions_.push(
[ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end],
[ol.replay.canvas.Instruction.CLOSE_PATH]);
}
this.state_.fillPending = true;
this.state_.strokePending = true;
};
ol.replay.canvas.Batch.prototype.drawMultiPolygonGeometry = goog.abstractMethod;
/**
* FIXME empty description for jsdoc
*/
ol.replay.canvas.Batch.prototype.finish = function() {
goog.asserts.assert(!goog.isNull(this.state_));
this.flush_(true);
this.state_ = null;
ol.replay.canvas.Batch.prototype.finish = goog.nullFunction;
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.setFillStrokeStyle = goog.abstractMethod;
/**
* @constructor
* @extends {ol.replay.canvas.Batch}
* @protected
*/
ol.replay.canvas.LineStringBatch = function() {
goog.base(this);
/**
* @private
* @type {{currentStrokeStyle: ?ol.style.Stroke,
* lastDraw: number,
* strokeStyle: ?ol.style.Stroke}|null}
*/
this.state_ = {
currentStrokeStyle: null,
lastDraw: 0,
strokeStyle: null
};
};
goog.inherits(ol.replay.canvas.LineStringBatch, ol.replay.canvas.Batch);
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @private
*/
ol.replay.canvas.LineStringBatch.prototype.drawCoordinates_ =
function(coordinates) {
var state = this.state_;
if (!ol.style.stroke.equals(state.currentStrokeStyle, state.strokeStyle)) {
if (state.lastDraw != this.coordinates.length) {
this.instructions.push([ol.replay.canvas.Instruction.STROKE]);
}
this.instructions.push(
[ol.replay.canvas.Instruction.SET_STROKE_STYLE, state.strokeStyle],
[ol.replay.canvas.Instruction.BEGIN_PATH]);
state.currentStrokeStyle = state.strokeStyle;
}
var end = this.appendCoordinates(coordinates, false);
this.instructions.push([ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end]);
};
/**
* @param {boolean} finish Finish.
* @private
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.flush_ = function(finish) {
ol.replay.canvas.LineStringBatch.prototype.drawLineStringGeometry =
function(lineStringGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
if (this.state_.fillPending || this.state_.strokePending) {
if (this.state_.fillPending) {
this.instructions_.push([ol.replay.canvas.Instruction.FILL]);
this.state_.fillPending = false;
}
if (this.state_.strokePending) {
this.instructions_.push([ol.replay.canvas.Instruction.STROKE]);
this.state_.strokePending = false;
}
this.state_.beginPath = true;
this.drawCoordinates_(lineStringGeometry.getCoordinates());
};
/**
* @inheritDoc
*/
ol.replay.canvas.LineStringBatch.prototype.drawMultiLineStringGeometry =
function(multiLineStringGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
var coordinatess = multiLineStringGeometry.getCoordinatess();
var i, ii;
for (i = 0, ii = coordinatess.length; i < ii; ++i) {
this.drawCoordinates_(coordinatess[i]);
}
};
@@ -266,21 +234,144 @@ ol.replay.canvas.Batch.prototype.flush_ = function(finish) {
/**
* @inheritDoc
*/
ol.replay.canvas.Batch.prototype.setFillStrokeStyle =
ol.replay.canvas.LineStringBatch.prototype.finish = function() {
var state = this.state_;
goog.asserts.assert(!goog.isNull(state));
if (state.lastDraw != this.coordinates.length) {
this.instructions.push([ol.replay.canvas.Instruction.STROKE]);
}
this.state_ = null;
};
/**
* @inheritDoc
*/
ol.replay.canvas.LineStringBatch.prototype.setFillStrokeStyle =
function(fillStyle, strokeStyle) {
goog.asserts.assert(!goog.isNull(this.state_));
// FIXME should only change styles before draws
if (!ol.style.fill.equals(this.state_.fillStyle, fillStyle)) {
this.flush_(false);
this.instructions_.push(
[ol.replay.canvas.Instruction.SET_FILL_STYLE, fillStyle]);
this.state_.fillStyle = fillStyle;
goog.asserts.assert(goog.isNull(fillStyle));
goog.asserts.assert(!goog.isNull(strokeStyle));
this.state_.strokeStyle = strokeStyle;
};
/**
* @constructor
* @extends {ol.replay.canvas.Batch}
* @protected
*/
ol.replay.canvas.PolygonBatch = function() {
goog.base(this);
/**
* @private
* @type {{currentFillStyle: ?ol.style.Fill,
* currentStrokeStyle: ?ol.style.Stroke,
* fillStyle: ?ol.style.Fill,
* strokeStyle: ?ol.style.Stroke}|null}
*/
this.state_ = {
currentFillStyle: null,
currentStrokeStyle: null,
fillStyle: null,
strokeStyle: null
};
};
goog.inherits(ol.replay.canvas.PolygonBatch, ol.replay.canvas.Batch);
/**
* @param {Array.<Array.<ol.Coordinate>>} rings Rings.
* @private
*/
ol.replay.canvas.PolygonBatch.prototype.drawRings_ = function(rings) {
var state = this.state_;
this.instructions.push([ol.replay.canvas.Instruction.BEGIN_PATH]);
var i, ii;
for (i = 0, ii = rings.length; i < ii; ++i) {
var end = this.appendCoordinates(rings[i], true);
this.instructions.push(
[ol.replay.canvas.Instruction.MOVE_TO_LINE_TO, end],
[ol.replay.canvas.Instruction.CLOSE_PATH]);
}
if (!ol.style.stroke.equals(this.state_.strokeStyle, strokeStyle)) {
this.flush_(false);
this.instructions_.push(
[ol.replay.canvas.Instruction.SET_STROKE_STYLE, strokeStyle]);
this.state_.strokeStyle = strokeStyle;
// FIXME is it quicker to fill and stroke each polygon individually,
// FIXME or all polygons together?
if (!goog.isNull(state.fillStyle)) {
this.instructions.push([ol.replay.canvas.Instruction.FILL]);
}
if (!goog.isNull(state.strokeStyle)) {
this.instructions.push([ol.replay.canvas.Instruction.STROKE]);
}
};
/**
* @inheritDoc
*/
ol.replay.canvas.PolygonBatch.prototype.drawPolygonGeometry =
function(polygonGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
this.setFillStrokeStyles_();
this.drawRings_(polygonGeometry.getRings());
};
/**
* @inheritDoc
*/
ol.replay.canvas.PolygonBatch.prototype.drawMultiPolygonGeometry =
function(multiPolygonGeometry) {
goog.asserts.assert(!goog.isNull(this.state_));
this.setFillStrokeStyles_();
var ringss = multiPolygonGeometry.getRingss();
var i, ii;
for (i = 0, ii = ringss.length; i < ii; ++i) {
this.drawRings_(ringss[i]);
}
};
/**
* @inheritDoc
*/
ol.replay.canvas.PolygonBatch.prototype.finish = function() {
goog.asserts.assert(!goog.isNull(this.state_));
this.state_ = null;
};
/**
* @inheritDoc
*/
ol.replay.canvas.PolygonBatch.prototype.setFillStrokeStyle =
function(fillStyle, strokeStyle) {
goog.asserts.assert(!goog.isNull(this.state_));
goog.asserts.assert(!goog.isNull(fillStyle) || !goog.isNull(strokeStyle));
this.state_.fillStyle = fillStyle;
this.state_.strokeStyle = strokeStyle;
};
/**
* @private
*/
ol.replay.canvas.PolygonBatch.prototype.setFillStrokeStyles_ = function() {
var state = this.state_;
if (!goog.isNull(state.fillStyle) &&
!ol.style.fill.equals(state.currentFillStyle, state.fillStyle)) {
this.instructions.push(
[ol.replay.canvas.Instruction.SET_FILL_STYLE, state.fillStyle]);
state.currentFillStyle = state.fillStyle;
}
if (!goog.isNull(state.strokeStyle) &&
!ol.style.stroke.equals(state.currentStrokeStyle, state.strokeStyle)) {
this.instructions.push(
[ol.replay.canvas.Instruction.SET_STROKE_STYLE, state.strokeStyle]);
state.currentStrokeStyle = state.strokeStyle;
}
};
@@ -372,8 +463,6 @@ ol.replay.canvas.BatchGroup.prototype.isEmpty = function() {
* @type {Object.<ol.replay.BatchType, function(new: ol.replay.canvas.Batch)>}
*/
ol.replay.canvas.BATCH_CONSTRUCTORS_ = {
'fillRing': ol.replay.canvas.Batch,
'fillStrokeRing': ol.replay.canvas.Batch,
'strokeLine': ol.replay.canvas.Batch,
'strokeRing': ol.replay.canvas.Batch
'LineString': ol.replay.canvas.LineStringBatch,
'Polygon': ol.replay.canvas.PolygonBatch
};

View File

@@ -8,11 +8,9 @@ goog.require('goog.functions');
* @enum {string}
*/
ol.replay.BatchType = {
FILL_RING: 'fillRing',
FILL_STROKE_RING: 'fillStrokeRing',
POINT: 'point',
STROKE_LINE: 'strokeLine',
STROKE_RING: 'strokeRing'
IMAGE: 'Image',
LINE_STRING: 'LineString',
POLYGON: 'Polygon'
};