UNPKG

lettuce

Version:

Lettuce JS, Mini Mobile Framework for Romantic with DSL.

545 lines (502 loc) 19.6 kB
/* * MelonJS Game Engine * Copyright (C) 2011 - 2014 Olivier Biot, Jason Oster, Aaron McLeod * http://www.melonjs.org * */ (function () { /** * a canvas renderer object * @class * @extends me.Renderer * @memberOf me * @constructor * @param {Canvas} canvas - the html canvas tag to draw to on screen. * @param {Number} game_width - the width of the canvas without scaling * @param {Number} game_height - the height of the canvas without scaling * @param {Object} [options] The renderer parameters * @param {Boolean} [options.doubleBuffering] - whether to enable double buffering. * @param {Number} [options.zoomX] - The actual width of the canvas with scaling applied * @param {Number} [options.zoomY] - The actual height of the canvas with scaling applied */ me.CanvasRenderer = me.Renderer.extend( /** @scope me.CanvasRenderer.prototype */ { /** * @ignore */ init : function (c, width, height, options) { // parent constructor this._super(me.Renderer, "init", [c, width, height, options]); // defined the 2d context this.context = this.getContext2d(this.canvas, !this.transparent); // create the back buffer if we use double buffering if (this.doubleBuffering) { this.backBufferCanvas = me.video.createCanvas(width, height, false); this.backBufferContext2D = this.getContext2d(this.backBufferCanvas); if (this.transparent) { // Clears the front buffer for each frame blit this.context.globalCompositeOperation = "copy"; } } else { this.backBufferCanvas = this.canvas; this.backBufferContext2D = this.context; } // apply the default color to the 2d context this.setColor(this.globalColor); return this; }, /** * prepare the framebuffer for drawing a new frame * @name prepareSurface * @memberOf me.CanvasRenderer * @function */ prepareSurface : function () { if (this.transparent) { this.clearSurface(null, "rgba(0,0,0,0)", true); } }, /** * render the main framebuffer on screen * @name blitSurface * @memberOf me.CanvasRenderer * @function */ blitSurface : function () { if (this.doubleBuffering) { this.context.drawImage( this.backBufferCanvas, 0, 0, this.backBufferCanvas.width, this.backBufferCanvas.height, 0, 0, this.gameWidthZoom, this.gameHeightZoom ); } }, /** * Clear the specified context with the given color * @name clearSurface * @memberOf me.CanvasRenderer * @function * @param {Context2d} [ctx=null] canvas context, defaults to system context. * @param {me.Color|String} color CSS color. * @param {Boolean} [opaque=false] Allow transparency [default] or clear the surface completely [true] */ clearSurface : function (ctx, col, opaque) { if (!ctx) { ctx = this.backBufferContext2D; } var _canvas = ctx.canvas; ctx.save(); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.globalCompositeOperation = opaque ? "copy" : "source-over"; ctx.fillStyle = (col instanceof me.Color) ? col.toRGBA() : col; ctx.fillRect(0, 0, _canvas.width, _canvas.height); ctx.restore(); }, /** * Quick helper method to draw the font on the backbuffer context. Useful for when using webgl with canvas fallback * for different platforms. * @name drawFont * @memberOf me.CanvasRenderer * @function * @param {me.Font} fontObject an instance of me.Font * @param {String} text the string of text to draw * @param {Number} x the x position to draw at * @param {Number} y the y position to draw at */ drawFont : function (fontObject, text, x, y) { fontObject.draw(this.backBufferContext2D, text, x, y); }, /** * Draw a line from the given point to the destination point. * @name drawLine * @memberOf me.CanvasRenderer * @function * @param {Number} startX start x position * @param {Number} startY start y position * @param {Number} endX end x position * @param {Number} endY end y position */ drawLine : function (startX, startY, endX, endY) { this.backBufferContext2D.translate(startX, startY); this.backBufferContext2D.beginPath(); this.backBufferContext2D.moveTo(0, 0); this.backBufferContext2D.lineTo(endX, endY); this.backBufferContext2D.stroke(); this.backBufferContext2D.closePath(); this.backBufferContext2D.translate(-startX, -startY); }, /** * Draw an image using the canvas api * @name drawImage * @memberOf me.CanvasRenderer * @function * @param {image} image html image element * @param {Number} sx sx value, from the source image. * @param {Number} sy sy value, from the source image. * @param {Number} sw sw the width of the image to be drawn * @param {Number} sh sh the height of the image to be drawn * @param {Number} dx dx the x position to draw the image at on the screen * @param {Number} dy dy the y position to draw the image at on the screen * @param {Number} dw dw the width value to draw the image at on the screen * @param {Number} dh dh the height value to draw the image at on the screen * @example * Can be used in three ways: * me.CanvasRenderer.drawImage(image, dx, dy); * me.CanvasRenderer.drawImage(image, dx, dy, dw, dh); * me.CanvasRenderer.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh); * dx, dy, dw, dh being the destination target & dimensions. sx, sy, sw, sh being the position & dimensions to take from the image */ drawImage : function () { this.backBufferContext2D.drawImage.apply(this.backBufferContext2D, arguments); }, /** * Fill an arc at the specified coordinates with given radius, start and end points * @name fillArc * @memberOf me.CanvasRenderer * @function * @param {Number} x arc center point x-axis * @param {Number} y arc center point y-axis * @param {Number} radius * @param {Number} start start angle in radians * @param {Number} end end angle in radians * @param {Boolean} [antiClockwise=false] draw arc anti-clockwise */ fillArc : function (x, y, radius, start, end, antiClockwise) { this.backBufferContext2D.save(); this.backBufferContext2D.beginPath(); this.backBufferContext2D.translate(x + radius, y + radius); this.backBufferContext2D.arc(0, 0, radius, start, end, antiClockwise || false); this.backBufferContext2D.fill(); this.backBufferContext2D.closePath(); this.backBufferContext2D.restore(); }, /** * Draw a filled rectangle at the specified coordinates * @name fillRect * @memberOf me.CanvasRenderer * @function * @param {Number} x * @param {Number} y * @param {Number} width * @param {Number} height */ fillRect : function (x, y, width, height) { this.backBufferContext2D.fillRect(x, y, width, height); }, /** * return a reference to the system canvas * @name getCanvas * @memberOf me.CanvasRenderer * @function * @return {Canvas} */ getCanvas : function () { return this.backBufferCanvas; }, /** * return a reference to the system 2d Context * @name getContext * @memberOf me.CanvasRenderer * @function * @return {Context2d} */ getContext : function () { return this.backBufferContext2D; }, /** * returns the text size based on dimensions from the font. Uses the backbuffer context * @name measureText * @memberOf me.CanvasRenderer * @function * @param {me.Font} the instance of the font object * @param {String} text * @return {Object} */ measureText : function (fontObject, text) { return fontObject.measureText(this.backBufferContext2D, text); }, /** * resets the canvas transform to identity * @name resetTransform * @memberOf me.CanvasRenderer * @function */ resetTransform : function () { this.backBufferContext2D.setTransform(1, 0, 0, 1, 0, 0); }, /** * resizes the canvas & 2d Context * @name resize * @memberOf me.CanvasRenderer * @function */ resize : function (scaleX, scaleY) { this.canvas.width = this.gameWidthZoom = this.backBufferCanvas.width * scaleX; this.canvas.height = this.gameHeightZoom = this.backBufferCanvas.height * scaleY; // adjust CSS style for High-DPI devices if (me.device.getPixelRatio() > 1) { this.canvas.style.width = (this.canvas.width / me.device.getPixelRatio()) + "px"; this.canvas.style.height = (this.canvas.height / me.device.getPixelRatio()) + "px"; } if (this.doubleBuffering && this.transparent) { // Clears the front buffer for each frame blit this.context.globalCompositeOperation = "copy"; } this.setImageSmoothing(this.context, this.antiAlias); this.blitSurface(); }, /** * save the canvas context * @name save * @memberOf me.CanvasRenderer * @function */ save : function () { this.colorStack.push(this.getColor(true)); this.backBufferContext2D.save(); }, /** * restores the canvas context * @name restore * @memberOf me.CanvasRenderer * @function */ restore : function () { var color = this.colorStack.pop(); this.setColor(color); me.pool.push(color); this.backBufferContext2D.restore(); }, /** * rotates the canvas context * @name rotate * @memberOf me.CanvasRenderer * @function * @param {Number} angle in radians */ rotate : function (angle) { this.backBufferContext2D.rotate(angle); }, /** * scales the canvas context * @name scale * @memberOf me.CanvasRenderer * @function * @param {Number} x * @param {Number} y */ scale : function (x, y) { this.backBufferContext2D.scale(x, y); }, /** * Sets the fill & stroke style colors for the context. * @name setColor * @memberOf me.CanvasRenderer * @function * @param {me.Color|String} color css color value */ setColor : function (color) { this.globalColor.copy(color); this.backBufferContext2D.strokeStyle = this.backBufferContext2D.fillStyle = this.globalColor.toRGBA(); }, /** * Sets the global alpha on the canvas context * @name setGlobalAlpha * @memberOf me.CanvasRenderer * @function * @param {Number} alpha 0.0 to 1.0 values accepted. */ setGlobalAlpha : function (a) { this.globalColor.setColor( this.globalColor.r, this.globalColor.g, this.globalColor.b, a ); this.backBufferContext2D.globalAlpha = a; }, /** * sets the line width on the context * @name setLineWidth * @memberOf me.CanvasRenderer * @function * @param {Number} width the width to set; */ setLineWidth : function (width) { this.backBufferContext2D.lineWidth = width; }, /** * Stroke an arc at the specified coordinates with given radius, start and end points * @name strokeArc * @memberOf me.CanvasRenderer * @function * @param {Number} x arc center point x-axis * @param {Number} y arc center point y-axis * @param {Number} radius * @param {Number} start start angle in radians * @param {Number} end end angle in radians * @param {Boolean} [antiClockwise=false] draw arc anti-clockwise */ strokeArc : function (x, y, radius, start, end, antiClockwise) { this.backBufferContext2D.beginPath(); this.backBufferContext2D.translate(x + radius, y + radius); this.backBufferContext2D.arc(0, 0, radius, start, end, antiClockwise || false); this.backBufferContext2D.stroke(); this.backBufferContext2D.closePath(); }, /** * Stroke an ellipse at the specified coordinates with given radius, start and end points * @name strokeEllipse * @memberOf me.CanvasRenderer * @function * @param {Number} x arc center point x-axis * @param {Number} y arc center point y-axis * @param {Number} w horizontal radius of the ellipse * @param {Number} h vertical radius of the ellipse */ strokeEllipse : function (x, y, w, h) { this.context.beginPath(); var hw = w, hh = h, lx = x - hw, rx = x + hw, ty = y - hh, by = y + hh; var xmagic = hw * 0.551784, ymagic = hh * 0.551784, xmin = x - xmagic, xmax = x + xmagic, ymin = y - ymagic, ymax = y + ymagic; this.backBufferContext2D.moveTo(x, ty); this.backBufferContext2D.bezierCurveTo(xmax, ty, rx, ymin, rx, y); this.backBufferContext2D.bezierCurveTo(rx, ymax, xmax, by, x, by); this.backBufferContext2D.bezierCurveTo(xmin, by, lx, ymax, lx, y); this.backBufferContext2D.bezierCurveTo(lx, ymin, xmin, ty, x, ty); this.backBufferContext2D.stroke(); }, /** * Stroke a line of the given two points * @name strokeLine * @memberOf me.CanvasRenderer * @function * @param {Number} startX the start x coordinate * @param {Number} startY the start y coordinate * @param {Number} endX the end x coordinate * @param {Number} endY the end y coordinate */ strokeLine : function (startX, startY, endX, endY) { this.context.beginPath(); this.context.moveTo(startX, startY); this.context.lineTo(endX, endY); this.context.stroke(); }, /** * Strokes a me.Polygon on the screen with a specified color * @name strokePolygon * @memberOf me.CanvasRenderer * @function * @param {me.Polygon} poly the shape to draw */ strokePolygon : function (poly) { this.backBufferContext2D.translate(poly.pos.x, poly.pos.y); this.backBufferContext2D.beginPath(); this.backBufferContext2D.moveTo(poly.points[0].x, poly.points[0].y); var point; for (var i = 1; i < poly.points.length; i++) { point = poly.points[i]; this.backBufferContext2D.lineTo(point.x, point.y); } this.backBufferContext2D.lineTo(poly.points[0].x, poly.points[0].y); this.backBufferContext2D.stroke(); this.backBufferContext2D.closePath(); this.backBufferContext2D.translate(-poly.pos.x, -poly.pos.y); }, /** * Stroke a rectangle at the specified coordinates with a given color * @name strokeRect * @memberOf me.CanvasRenderer * @function * @param {Number} x * @param {Number} y * @param {Number} width * @param {Number} height */ strokeRect : function (x, y, width, height) { this.backBufferContext2D.strokeRect(x, y, width, height); }, /** * draw the given shape * @name drawShape * @memberOf me.CanvasRenderer * @function * @param {me.Rect|me.Polygon|me.Line|me.Ellipse} shape a shape object */ drawShape : function (shape) { if (shape instanceof me.Rect) { this.strokeRect(shape.left, shape.top, shape.width, shape.height); } else if (shape instanceof me.Line || shape instanceof me.Polygon) { this.save(); this.strokePolygon(shape); this.restore(); } else if (shape instanceof me.Ellipse) { this.save(); if (shape.radiusV.x === shape.radiusV.y) { // it's a circle this.strokeArc( shape.pos.x - shape.radius, shape.pos.y - shape.radius, shape.radius, 0, 2 * Math.PI ); } else { // it's an ellipse this.strokeEllipse( shape.pos.x, shape.pos.y, shape.radiusV.x, shape.radiusV.y ); } this.restore(); } }, /** * transforms the context. Accepts any number of integer arguments * @name transform * @memberOf me.CanvasRenderer * @function * @param {Number} m11 * @param {Number} m12 * @param {Number} m21 * @param {Number} m22 * @param {Number} dx * @param {Number} dy */ transform : function () { this.backBufferContext2D.transform( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5] ); }, /** * Translates the context to the given position * @name translate * @memberOf me.CanvasRenderer * @function * @param {Number} x * @param {Number} y */ translate : function (x, y) { this.backBufferContext2D.translate(x, y); } }); })();