text: Object.assign(pc, function () {
      /**
       * @constant
       * @type {string}
       * @name pc.SCALEMODE_NONE
       * @description Always use the application's resolution as the resolution for the {@link pc.ScreenComponent}.
       */
      pc.SCALEMODE_NONE = "none";
      /**
       * @constant
       * @type {string}
       * @name pc.SCALEMODE_BLEND
       * @description Scale the {@link pc.ScreenComponent} when the application's resolution is different than the ScreenComponent's referenceResolution.
       */
      pc.SCALEMODE_BLEND = "blend";
  
      // var counter = 1;
      /**
       * @component
       * @class
       * @name pc.ScreenComponent
       * @augments pc.Component
       * @classdesc A ScreenComponent enables the Entity to render child {@link pc.ElementComponent}s using anchors and positions in the ScreenComponent's space.
       * @description Create a new ScreenComponent.
       * @param {pc.ScreenComponentSystem} system - The ComponentSystem that created this Component.
       * @param {pc.Entity} entity - The Entity that this Component is attached to.
       * @property {boolean} screenSpace If true then the ScreenComponent will render its child {@link pc.ElementComponent}s in screen space instead of world space. Enable this to create 2D user interfaces.
       * @property {boolean} cull If true then elements inside this screen will be not be rendered when outside of the screen (only valid when screenSpace is true).
       * @property {string} scaleMode Can either be {@link pc.SCALEMODE_NONE} or {@link pc.SCALEMODE_BLEND}. See the description of referenceResolution for more information.
       * @property {number} scaleBlend A value between 0 and 1 that is used when scaleMode is equal to {@link pc.SCALEMODE_BLEND}. Scales the ScreenComponent with width as a reference (when value is 0), the height as a reference (when value is 1) or anything in between.
       * @property {pc.Vec2} resolution The width and height of the ScreenComponent. When screenSpace is true the resolution will always be equal to {@link pc.GraphicsDevice#width} x {@link pc.GraphicsDevice#height}.
       * @property {pc.Vec2} referenceResolution The resolution that the ScreenComponent is designed for. This is only taken into account when screenSpace is true and scaleMode is {@link pc.SCALEMODE_BLEND}. If the actual resolution is different then the ScreenComponent will be scaled according to the scaleBlend value.
       */
      var ScreenComponent = function ScreenComponent(system, entity) {
          pc.Component.call(this, system, entity);
  
          this._resolution = new pc.Vec2(640, 320);
          this._referenceResolution = new pc.Vec2(640, 320);
          this._scaleMode = pc.SCALEMODE_NONE;
          this.scale = 1;
          this._scaleBlend = 0.5;
  
          // priority determines the order in which screens components are rendered
          // priority is set into the top 8 bits of the drawOrder property in an element
          this._priority = 0;
  
          this._screenSpace = false;
          this.cull = this._screenSpace;
          this._screenMatrix = new pc.Mat4();
  
          system.app.graphicsDevice.on("resizecanvas", this._onResize, this);
      };
      ScreenComponent.prototype = Object.create(pc.Component.prototype);
      ScreenComponent.prototype.constructor = ScreenComponent;
  
      var _transform = new pc.Mat4();
  
      Object.assign(ScreenComponent.prototype, {
          /**
           * @function
           * @name pc.ScreenComponent#syncDrawOrder
           * @description Set the drawOrder of each child {@link pc.ElementComponent}
           * so that ElementComponents which are last in the hierarchy are rendered on top.
           * Draw Order sync is queued and will be updated by the next update loop.
           */
          syncDrawOrder: function () {
              this.system.queueDrawOrderSync(this.entity.getGuid(), this._processDrawOrderSync, this);
          },
  
          _recurseDrawOrderSync: function (e, i) {
              if (!(e instanceof pc.Entity)) {
                  return i;
              }
  
              if (e.element) {
                  var prevDrawOrder = e.element.drawOrder;
                  e.element.drawOrder = i++;
  
                  if (e.element._batchGroupId >= 0 && prevDrawOrder != e.element.drawOrder) {
                      this.system.app.batcher.markGroupDirty(e.element._batchGroupId);
                  }
              }
  
              var children = e.children;
              for (var j = 0; j < children.length; j++) {
                  i = this._recurseDrawOrderSync(children[j], i);
              }
  
              return i;
          },
  
          _processDrawOrderSync: function () {
              var i = 1;
  
              this._recurseDrawOrderSync(this.entity, i);
  
              // fire internal event after all screen hierarchy is synced
              this.fire('syncdraworder');
          },
  
          _calcProjectionMatrix: function () {
              var left;
              var right;
              var bottom;
              var top;
              var near = 1;
              var far = -1;
  
              var w = this._resolution.x / this.scale;
              var h = this._resolution.y / this.scale;
  
              left = 0;
              right = w;
              bottom = -h;
              top = 0;
  
              this._screenMatrix.setOrtho(left, right, bottom, top, near, far);
  
              if (!this._screenSpace) {
                  _transform.setScale(0.5 * w, 0.5 * h, 1);
                  this._screenMatrix.mul2(_transform, this._screenMatrix);
              }
          },
  
          _updateScale: function () {
              this.scale = this._calcScale(this._resolution, this.referenceResolution);
          },
  
          _calcScale: function (resolution, referenceResolution) {
              // Using log of scale values
              // This produces a nicer outcome where if you have a xscale = 2 and yscale = 0.5
              // the combined scale is 1 for an even blend
              var lx = Math.log2(resolution.x / referenceResolution.x);
              var ly = Math.log2(resolution.y / referenceResolution.y);
              return Math.pow(2, (lx * (1 - this._scaleBlend) + ly * this._scaleBlend));
          },
  
          _onResize: function (width, height) {
              if (this._screenSpace) {
                  this._resolution.set(width, height);
                  this.resolution = this._resolution; // force update
              }
          },
  
          onRemove: function () {
              this.system.app.graphicsDevice.off("resizecanvas", this._onResize, this);
              this.fire('remove');
  
              // remove all events used by elements
              this.off();
          }
      });
  
      Object.defineProperty(ScreenComponent.prototype, "resolution", {
          set: function (value) {
              if (!this._screenSpace) {
                  this._resolution.set(value.x, value.y);
              } else {
                  // ignore input when using screenspace.
                  this._resolution.set(this.system.app.graphicsDevice.width, this.system.app.graphicsDevice.height);
              }
  
              this._updateScale();
  
              this._calcProjectionMatrix();
  
              if (!this.entity._dirtyLocal)
                  this.entity._dirtifyLocal();
  
              this.fire("set:resolution", this._resolution);
          },
          get: function () {
              return this._resolution;
          }
      });
  
      Object.defineProperty(ScreenComponent.prototype, "referenceResolution", {
          set: function (value) {
              this._referenceResolution.set(value.x, value.y);
              this._updateScale();
              this._calcProjectionMatrix();
  
              if (!this.entity._dirtyLocal)
                  this.entity._dirtifyLocal();
  
              this.fire("set:referenceresolution", this._resolution);
          },
          get: function () {
              if (this._scaleMode === pc.SCALEMODE_NONE) {
                  return this._resolution;
              }
              return this._referenceResolution;
  
          }
      });
  
      Object.defineProperty(ScreenComponent.prototype, "screenSpace", {
          set: function (value) {
              this._screenSpace = value;
              if (this._screenSpace) {
                  this._resolution.set(this.system.app.graphicsDevice.width, this.system.app.graphicsDevice.height);
              }
              this.resolution = this._resolution; // force update either way
  
              if (!this.entity._dirtyLocal)
                  this.entity._dirtifyLocal();
  
              this.fire('set:screenspace', this._screenSpace);
          },
          get: function () {
              return this._screenSpace;
          }
      });
  
  
      Object.defineProperty(ScreenComponent.prototype, "scaleMode", {
          set: function (value) {
              if (value !== pc.SCALEMODE_NONE && value !== pc.SCALEMODE_BLEND) {
                  value = pc.SCALEMODE_NONE;
              }
  
              // world space screens do not support scale modes
              if (!this._screenSpace && value !== pc.SCALEMODE_NONE) {
                  value = pc.SCALEMODE_NONE;
              }
  
              this._scaleMode = value;
              this.resolution = this._resolution; // force update
              this.fire("set:scalemode", this._scaleMode);
          },
          get: function () {
              return this._scaleMode;
          }
      });
  
      Object.defineProperty(ScreenComponent.prototype, "scaleBlend", {
          set: function (value) {
              this._scaleBlend = value;
              this._updateScale();
              this._calcProjectionMatrix();
  
              if (!this.entity._dirtyLocal)
                  this.entity._dirtifyLocal();
  
              this.fire("set:scaleblend", this._scaleBlend);
          },
          get: function () {
              return this._scaleBlend;
          }
      });
  
      Object.defineProperty(ScreenComponent.prototype, "priority", {
          get: function () {
              return this._priority;
          },
  
          set: function (value) {
              if (value > 0xFF) {
                  // #ifdef DEBUG
                  console.warn('Clamping screen priority from ' + value + ' to 255');
                  // #endif
                  value = 0xFF;
              }
  
              this._priority = value;
          }
      });
      return {
          ScreenComponent: ScreenComponent
      };
  }());
  