Source: core/Render.js

/**
 * @author Inateno / http://inateno.com / http://dreamirl.com
 */

/**
 * @constructor Render
 * @class this create the canvas, buffers, and manage resizing
 * @example Game.render = new DE.Render( "render", { fullScreen: "ratioStretch" } );
 * Game.render.init();
 */
define( [ 'DE.CONFIG', 'DE.Sizes', 'DE.Time', 'DE.MainLoop', 'DE.CollisionSystem', 'DE.Inputs', 'DE.CanvasBuffer' ],
function( CONFIG, Sizes, Time, MainLoop, CollisionSystem, Inputs, CanvasBuffer )
{
  function Render( divId, params )
  {
    params      = params || {};
    this.id     = 0;
    this.divId  = divId || undefined;
    this.canvas = null;
    this.ctx    = null;
    
    this.sizes       = new Sizes( params.width || CONFIG.defaultRenderWidth || 100, params.height || CONFIG.defaultRenderHeight || 100, params.scaleX || 1, params.scaleY || 1 );
    this.savedSizes  = new Sizes( params.width || CONFIG.defaultRenderWidth || 100, params.height || CONFIG.defaultRenderHeight || 100, params.scaleX || 1, params.scaleY || 1 );
    
    var _drawRatio   = 1;
    this.physicRatio = 1;
    
    this.conserveSizes  = params.conserveSizes || false;
    this.fullScreenMode = params.fullScreen || null;
    this.cameras        = new Array();
    this.maxCameras     = 0;
    
    this.freeze = false;

    /****
     * init@void
      create canvas render, buffer, init ctx, and append in the dom
      bind Inputs, then call updateSizes
     */
    this.init = function()
    {
      if ( this.inited )
        return;
      MainLoop.addRender( this );
      
      if ( !this.divId )
      {
        this.div = window.document.body;
        CONFIG.debug.log( "%cWARN: you not specified a DOM Object where push the render, it will push in the body *hiiik*", 1, "color:orange" );
      }
      else
      {
        this.div = document.getElementById( this.divId );
        if ( !this.div )
        {
          throw new Error( "Can't found the div by the given id" );
          return false;
        }
      }
      
      this.canvas = document.createElement( "canvas" );
      this.div.appendChild( this.canvas );
      Inputs.addRender( this );
      
      this.ctx = this.canvas.getContext( '2d' );
      this.buffer = new CanvasBuffer( this.sizes.width, this.sizes.height );
      this.inited = true;
      this.updateSizes();
    }
    
    /****
     * updateSizes@void
      change size, used for init and when change quality
     */
    this.updateSizes = function()
    {
      if ( !this.inited )
        return;
      if ( this.conserveSizes )
      {
        this.sizes.width  = this.div.offsetWidth.valueOf();
        this.sizes.height = this.div.offsetHeight.valueOf();
      }
      else
      {
        this.div.style.width  = this.sizes.width + "px";
        this.div.style.height = this.sizes.height + "px";
      }
      
      this.canvas.width = this.sizes.width.valueOf();
      this.canvas.height= this.sizes.height.valueOf();
      this.canvas.id = this.id;
      
      if ( this.fullScreenMode )
      {
        this.fullScreen( this.fullScreenMode );
        this.resizeOnEventResize();      
      }
      this.buffer.resize( this.sizes.width, this.sizes.height );
    }
    
    /***
     * screenChangedSizeIndex@void
      when Screen class change index size, update sizes and ratios
     */
    this.screenChangedSizeIndex = function( physicRatio, newSizes )
    {
      this.savedSizes.width  = newSizes.w;
      this.savedSizes.height = newSizes.h;
      this.physicRatio = physicRatio;
      this.updateSizes();
      
      for ( var i = 0, c; c = this.cameras[ i ]; ++i )
      {
        c.screenChangedSizeIndex( physicRatio, newSizes );
      }
    }
    
    /****
     * resize@void
     */
    this.resize = function( w, h, stretch )
    {
      if ( this.div != window.document.body )
      {
        this.div.style.width  = w + "px";
        this.div.style.height = h + "px";
      }
      
      this.canvas.width  = w;
      this.canvas.height = h;
      this.sizes.width   = w;
      this.sizes.height  = h;
      
      /*if ( !stretch )
      {
      }*/
    }
    
    /****
     * resizeOnEventResize@void
      bind window resize event if wanted
     */
    this.resizeOnEventResize = function()
    {
      if ( !this.fullScreenMode )
        return;
      
      var o = this;
      var lastResize = undefined;
      var recallMethod = function()
      {
        o.fullScreenMethod.call( o );
      };
      if ( window.addEventListener )
      {
        window.addEventListener( "resize", function()
        {
          lastResize && window.clearTimeout( lastResize );
          lastResize = window.setTimeout( recallMethod, 200 );
        }, false ); 
      }
      else if ( window.attachEvent )
      {
        window.attachEvent( "onresize", function()
        {
          lastResize && window.clearTimeout( lastResize );
          lastResize = window.setTimeout( recallMethod, 200 ); 
        } );
      }
    }
    
    /***
     * resizeRatio@void
      resize with ratio, stretched or not
     */
    this.resizeRatio = function( w, h , stretch )
    {
      var baseW = this.savedSizes.width;
      var baseH = this.savedSizes.height;
      var calcRatio = w / baseW;
      
      if ( calcRatio * baseH > h )
      {
        calcRatio = h / baseH;
      }

      var newW = calcRatio * baseW >> 0;
      var newH = calcRatio * baseH >> 0;
      this.resize( newW, newH, stretch );
      
      this.div.style.marginLeft = ( ( w - newW ) / 2 ) + "px";
      this.div.style.marginTop = ( ( h - newH ) / 2 ) + "px";
      this.canvas.style.top = 0;
      
      _drawRatio = newW / this.savedSizes.width;
    }

    var _fullScreenMethod;
    /****
     * changeFullScreenMode@void
      change current resize
     */
    this.changeFullScreenMode = function( mode )
    {
      this.fullScreenMode = mode;
      switch( mode )
      {
        case "ratioStretch" : 
          _fullScreenMethod = function( screenW, screenH )
          {
            this.resizeRatio(screenW, screenH, true);
          };
        break;
        case "fullStretch" : 
          _fullScreenMethod = function( screenW, screenH )
          {
            this.resize(screenW, screenH, true);
          };
        break;
        case "ratio":
          _fullScreenMethod = function( screenW, screenH )
          {
            this.resizeRatio(screenW, screenH, false);
          };
        break;
        // default = nothing
        default:
          _fullScreenMethod = function( screenW, screenH )
          {
            //this.resize(screenW, screenH, false);
          };
        break;
      }
    }
    
    /****
     * fullScreenMethod@void
     */
    this.fullScreenMethod = function()
    {
      var screenW = ( window.innerWidth || document.documentElement.clientWidth );
      var screenH = ( window.innerHeight || document.documentElement.clientHeight );
      
      var divParentH = window.getComputedStyle( this.div.parentElement, null ).getPropertyValue( 'height' );
      if ( this.div.parentElement != null
          && divParentH && screenH < document.body.clientHeight )
      {
        var divW = this.div.parentElement.innerWidth || this.div.parentElement.clientWidth;
        var divH = this.div.parentElement.innerHeight || this.div.parentElement.clientHeight;
        
        if ( divH < screenH )
          screenH = divH;
        if ( divW < screenW )
          screenW = divW;
      }
      
      if ( !_fullScreenMethod )
      {
        throw ("Render.js : fullScreenMethod need a fullScreenMode, maybe you never used changeFullScreenMode")
      }
      
      _fullScreenMethod.call( this, screenW, screenH );
    }
    
    /****
     * fullScreen@void
      TODO - WIP
     */
    this.fullScreen = function( mode, automatism )
    {
      if ( mode )
      {
        this.changeFullScreenMode( mode );
      }

      if ( automatism )
      {
        // add on listener Resize
      }

      this.fullScreenMethod();
    }

    /****
     * render@void
      renderise all cameras binded on this Render
     */
    this.render = function()
    {
      if ( this.freeze )
      {
        return;
      }
      
      this.ctx.fillStyle = "black";
      this.ctx.fillRect( 0, 0, this.sizes.width, this.sizes.height );
      
      for ( var i = 0, camera; camera = this.cameras[ i ]; ++i )
      {
        camera.render( this.ctx, _drawRatio, this.physicRatio );
      }
      
      if ( CONFIG.DEBUG_LEVEL > 0 )
      {
        this.ctx.font = "24px Arial";
        this.ctx.fillStyle = "white";
        this.ctx.fillText( "DeltaTime: " + Time.deltaTime
                          , ( this.sizes.width >> 0 ) - 220
                          , 30 );
        this.ctx.fillText( "MissedFrame: " + Time.missedFrame
                          , ( this.sizes.width >> 0 ) - 220
                          , 60 );
        this.ctx.fillText( "FPS: " + Time.fps
                          , ( this.sizes.width >> 0 ) - 220
                          , 90 );
      }
    }
    
    /****
     * add@void( camera@Camera )
      add a camera on this render
     */
    this.add = function( camera )
    {
      this.cameras.push( camera );
      this.maxScenes++;
      camera.screenChangedSizeIndex( this.physicRatio, this.savedSizes );
    }
    
    /****
     * remove@void( camera@Camera )
      remove a camera on this render ( not deleted ! )
     */
    this.remove = function( camera )
    {
      var pos = this.cameras.indexOf( camera );
      if ( pos == -1 )
      {
        CONFIG.debug.log( "Remove camera not found ", 1, camera );
        return;
      }
      
      this.cameras.splice( pos, 1 );
      this.maxScenes--;
    }
    
    /****
     * camerasMousCollide@void( eventName@string, x@Int, y@Int, index@Int )
      trigger mouses/touches events in cameras
     */
    this.camerasMouseCollide = function( eventName, x, y, index )
    {
      var mouse = _getMouseCoords.call( this, x, y, index );
      
      // custom events ? if return true stop propagation now
      if ( this[ 'on' + eventName ]( mouse ) || mouse.stopPropagation )
        return mouse;
      for ( var i = 0, cam, camPos; i < this.cameras.length; i++ )
      {
        cam = this.cameras[ i ];
        if ( cam.sleep )
          continue;
        
        camPos = {
          'x'      : cam.renderPosition.x - ( cam.renderSizes.width * 0.5 * cam.renderSizes.scaleX )
          ,'y'     : cam.renderPosition.y - ( cam.renderSizes.height * 0.5 * cam.renderSizes.scaleY )
          ,'width' : cam.renderSizes.width * cam.renderSizes.scaleX
          ,'height': cam.renderSizes.height * cam.renderSizes.scaleY
        };
        
        // console.log( 'camPos', mouse );
        if ( CollisionSystem.pointFixedBoxCollision( mouse, camPos ) )
        {
          if ( !cam.indexMouseOver[ index ] && cam.oOnMouseEnter( mouse, this.physicRatio ) )
            break;
          if ( cam[ 'oOn' + eventName ]( mouse, this.physicRatio ) )
            break;
        }
        else if ( cam.indexMouseOver[ index ] && cam.oOnMouseLeave( mouse, this.physicRatio ) )
        {
          break;
        }
      }
      
      if ( !mouse.stopPropagation )
        this[ 'lastOn' + eventName ]( mouse );
      return mouse;
    }
    
    /* Custom Events
      return true to stop current event */
    this.onMouseMove = function(){};
    this.onMouseDown = function(){};
    this.onMouseUp = function(){};
    
    /* last event, called after all 
      if no stopPropagation */
    this.lastOnMouseMove = function(){};
    this.lastOnMouseDown = function(){};
    this.lastOnMouseUp = function(){};
    
    this.oOnMouseDown = function( mouse )
    {
      this.camerasMouseCollide( "MouseDown", mouse.x, mouse.y, mouse.index );
    }
    this.oOnMouseUp = function( mouse )
    {
      this.camerasMouseCollide( "MouseUp", mouse.x, mouse.y, mouse.index );
    }
    this.oOnMouseMove = function( mouse )
    {
      this.camerasMouseCollide( "MouseMove", mouse.x, mouse.y, mouse.index );
    }
    
    /****
     * @private
     */
      /****
       * _scrollPosition@Vector2
        return the scollPostion of the window
       **/
      function _scrollPosition()
      {
        return {
          x: document.scrollLeft || window.pageXOffset,
          y: document.scrollTop || window.pageYOffset
        };
      }
      
      /****
       * _getMouseCoords@Mouse
       */
      function _getMouseCoords( x, y, index )
      {
        var pos = { "x": x, "y": y };
        var elem = this.canvas;
        var offsetLeft = 0, offsetTop = 0;
        while( elem )
        {
          offsetLeft += elem.offsetLeft;
          offsetTop += elem.offsetTop;
          elem = elem.parentElement;
        }
        pos.x -= offsetLeft;
        pos.y -= offsetTop;
        return {
            'x': pos.x / _drawRatio + _scrollPosition().x >> 0
          , 'y': pos.y / _drawRatio + _scrollPosition().y >> 0
          , 'index': index
        };
      }
    /*** -private- ***/
  }
  Render.prototype.DEName = "Render";
  
  CONFIG.debug.log( "Render loaded", 3 );
  return Render;
} );
Dreamirl Copyright © 2014 And the contributors
Documentation generated by JSDoc 3.2.2 on Thu Apr 24 2014 11:56:40 GMT+0200 (CEST) using the DocStrap template.