Skip to content

Commit

Permalink
TexShader checks image sizes and creates power of 2 texture
Browse files Browse the repository at this point in the history
2d doesn't render to webgl (not worth the matrix math)
  • Loading branch information
schell committed Jul 5, 2012
1 parent d9f0f16 commit 6014382
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 26 deletions.
219 changes: 206 additions & 13 deletions src/View/Stage.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ mod({
function Stage(width, height) {
View.call(this, 0, 0, width, height);

/** * *
* A flattened version of the display list at its last
* clean state. Compiled after the last draw. Mostly used
* to map children to their previous boundaries.
* @type {Array.<View>}
* * **/
this.cleanViews = [];
/** * *
* A list of objects that store the clean state of a view.
* @type {Array.<Object>}
* * **/
this.viewPackages = [];
/** * *
* A list of rectangular areas that were redrawn during the last redraw.
* @type {Array.<Rectangle>}
* * **/
this.redraws = [];
/** * *
* Whether or not this Stage should redraw itself.
* Subviews set this variable in markAsDirty() when changes are made to them.
* @type {boolean}
* * **/
this.shouldRedraw = false;
/** * *
* An animation timer for scheduling redraws.
* @type {Animation}
Expand All @@ -50,11 +73,6 @@ mod({
* @type {boolean}
* * **/
this.showRedrawRegions = false;
/** * *
* Whether or not to use WebGL for rendering.
* @type {boolean}
* * **/
this.useWebGL = true;
}

Stage.prototype = new View();
Expand All @@ -81,23 +99,198 @@ mod({
return children;
};
/** * *
* Draws this view and its display hierarchy into the given context.
* @param {HTMLCanvasRenderingContext2D}
* A list of View properties that affect its boundaries.
* @type {Array.<string>}
* * **/
Stage.prototype.draw = function Stage_draw(context) {
if (!context) {
return;
var boundaryProperties = [
'x',
'y',
'scaleX',
'scaleY',
'rotation',
'alpha'
];
/** * *
* Packages a view and its current (hopefully clean) state.
* @param view {View}
* @return {Object}
* * **/
function packageView(view) {
var pkg = {};
// Copy all those properties that may affect the views
// boundaries, so we can check them at the next redraw...
for (var i=0; i < boundaryProperties.length; i++) {
var property = boundaryProperties[i];
pkg[property] = view[property];
}
pkg.transform = view.globalTransform();

// Get the containing boundary of this view...
// The view may be rotated, and we want a rectangle
// that contains the transformed boundary...
var polygon = pkg.transform.transformPolygon(view.localBoundary());
var r = new Rectangle(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY);
r.right(Number.NEGATIVE_INFINITY);
r.bottom(Number.NEGATIVE_INFINITY);
for (var j=0; j < polygon.length; j+=2) {
var x = polygon[j];
var y = polygon[j+1];
if (x < r.left()) {
r.left(x);
}
if (x > r.right()) {
r.right(x);
}
if (y < r.top()) {
r.top(y);
}
if (y > r.bottom()) {
r.bottom(y);
}
}
// Clear the stage...
pkg.boundary = r;
pkg.view = view;

return pkg;
}
/** * *
* Draws this stage and its subviews into the given context.
* @param context {CanvasRenderingContext2D}
* * **/
Stage.prototype.draw = function Stage_draw(context) {
context = context || this.compositeCanvas.getContext('2d');

context.save();
// Clear the entire stage...
context.clearRect(0, 0, this.width, this.height);
// Get the flattened list of children (which includes this stage)
var children = this.children();
var viewPackages = [];
for (var i=0; i < children.length; i++) {
var viewPackage = packageView(children[i]);
var view = viewPackage.view;
var transform = viewPackage.transform;
// Update the context's transformation...
context.setTransform.apply(context, transform.abdegh());
// Draw dem pixels!
context.drawImage(view.canvas, 0, 0);
// These pipes......are CLEEAAAN!!!
view.isDirty = false;
viewPackages.push(viewPackage);
}
context.restore();
// Update our drawing properties...
this.cleanViews = children;
this.viewPackages = viewPackages;
this.isDirty = false;
};
/** * *
* Redraws portions of this view and its subviews that have changed
* since the last draw or redraw into the given context.
* @param context {CanvasRenderingContext2D}
* * **/
Stage.prototype.redraw = function Stage_redraw(context) {
context = context || this.compositeCanvas.getContext('2d');

if (this.isDirty || this.viewPackages.length <= 1) {
// Just draw the whole thing over again...
return this.draw(context);
}

// Get our new flattened display list...
var children = this.children();
var redraws = [];
var viewPackages = [];
var i,j,view;
for (i=0; i < children.length; i++) {
view = children[i];
var pkg = packageView(view);
// Get the ndx of the view in the display list from the last clean state...
var ndx = this.cleanViews.indexOf(view);
if (ndx === -1 || view.isDirty) {
// This is either a new view that has just been added
// or the view's context was drawn into using an aliased function...
redraws.push(pkg.boundary);
} else if (!view.isDirty) {
var lastPkg = this.viewPackages[ndx];
// Check to see if any view properties have changed...
for (j=0; j < boundaryProperties.length; j++) {
var property = boundaryProperties[j];
if (view[property] !== lastPkg[property]) {
// Push the old boundary and the new boundary up...
redraws.push(lastPkg.boundary);
redraws.push(pkg.boundary);
}
}
}
// Now that we've collected our dirty rectangles, let's update the view
// and store our new package...
view.isDirty = false;
viewPackages.push(pkg);
}

// Update the stage's draw properties...
this.viewPackages = viewPackages;
this.redraws =Rectangle.reduceRectangles(redraws);

// Now go through and actually do some drawing!
for (i=0; i < this.redraws.length; i++) {
var r = this.redraws[i];
// Clear the draw area...
context.clearRect(r.x(),r.y(),r.width(),r.height());
// This can be greatly improved by storing
// views in a quadtree and doing a query for a list
// of views affected by each redraw rectangle, but
// for now we're just brute forcing and running through
// the entire list...
for (j=0; j < this.viewPackages.length; j++) {
var viewPkg = this.viewPackages[j];
view = viewPkg.view;
if (viewPkg.boundary.intersectsRectangle(r)) {
// A portion of this rectangle needs to be redrawn...
// Get the redraw rectangle in the view's local coords...
var lr = view.vectorToLocal(r);
// Clip the redraw polygon (cuz it could be a rotated rectangle)...
var redrawPoly = view.localBoundary().clipPolygon(lr);
if (redrawPoly.length <= 2) {
// This is not a polygon...
continue;
}
context.save();
// Apply the global transform to the drawing context, so now
// we're in this view's local coordinates, which match our
// redraw polygon...
context.setTransform.apply(context, viewPkg.transform.abdegh());
// Create a pattern for this view so we can draw the polygon path...
var pattern = this.context.createPattern(view.canvas, 'no-repeat');
// Draw the polygon!
context.fillStyle = pattern;
context.beginPath();
context.moveTo(redrawPoly[0], redrawPoly[1]);
for (var k=2; k < redrawPoly.length; k+=2) {
context.lineTo(redrawPoly[k], redrawPoly[k+1]);
}
context.closePath();
context.fill();
context.restore();
}
}
if (this.showRedrawRegions) {
context.save();
context.strokeStyle = 'limegreen';
context.strokeRect(r.x(),r.y(),r.width(),r.height());
context.restore();
}
}

View.prototype.draw.call(this, context);
this.isDirty = false;
this.shouldRedraw = false;
};
/** * *
* This is the main step of the display list.
* * **/
Stage.prototype.step = function Stage_step(time) {
this.draw(this.compositeCanvas.getContext('2d'));
View.prototype.draw.call(this, this.compositeCanvas.getContext('2d'));
};

return Stage;
Expand Down
26 changes: 13 additions & 13 deletions src/View/View.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/
mod({
name : 'View',
dependencies : [ 'bang::Geometry/Rectangle.js', 'bang::Geometry/Transform2d.js' ],
dependencies : [ 'bang::Geometry/Rectangle.js', 'bang::Geometry/Matrix.js' ],
/** * *
* Initializes the View type.
* @param {Object}
Expand Down Expand Up @@ -156,11 +156,10 @@ mod({
* If invert is true, will return the inverse of the
* local tranformation matrix.
* @param {boolean=}
* @return {Transform2d}
* @nosideeffects
* * **/
View.prototype.localTransform = function View_localTransform(invert) {
var matrix = new Transform2d();
var matrix = new Matrix();

if (invert) {
// Let's just provide them with an inverse instead of
Expand Down Expand Up @@ -241,10 +240,20 @@ mod({
context.globalAlpha *= this.alpha;
};
/** * *
* Sets this view as being dirty.
* Sets this view as being dirty. Causes the stage to redraw.
* * **/
View.prototype.markAsDirty = function View_markAsDirty() {
this.isDirty = true;
var parent = this;
// Traverse up the display list and tell the root it should redraw.
while (parent) {
if (!parent.parent) {
parent.shouldRedraw = true;
parent = false;
} else {
parent = parent.parent;
}
}
};
/** * *
* Adds a subview to this view.
Expand Down Expand Up @@ -303,15 +312,6 @@ mod({
}
context.restore();
};
/** * *
* Draws this view and its subviews into the given WebGLRendering context.
* @param {WebGLRenderingContext} context
* @param {Transform3d} transform The parent transformation matrix.
* * **/
View.prototype.drawWebGL = function View_drawWebGL(context, transform) {

};

return View;
}
});

0 comments on commit 6014382

Please sign in to comment.