'use strict';

require('../core/settings.js');
require('../color.js');
var constants = require('../constants.js');
require('../extensions.js');
require('../math/const.js');
var Point = require('../math/Point.js');
var Polygon = require('../math/shapes/Polygon.js');
require('../math/groupD8.js');
require('../math/Transform.js');
require('../runner.js');
var settings = require('../settings/settings.js');
require('../ticker/settings.js');
require('../ticker/const.js');
require('../ticker/Ticker.js');
require('../ticker/TickerPlugin.js');
require('../utils/settings.js');
require('../utils/is_mobile/index.js');
require('../utils/color/premultiply.js');
require('../utils/media/BoundingBox.js');
require('../core/autoDetectRenderer.js');
require('../core/background/BackgroundSystem.js');
require('../core/batch/BatchRenderer.js');
require('../core/shader/Program.js');
require('../core/batch/BatchSystem.js');
require('../core/context/ContextSystem.js');
require('../core/filters/Filter.js');
require('../core/filters/FilterSystem.js');
require('../core/textures/BaseTexture.js');
require('../core/framebuffer/FramebufferSystem.js');
require('../core/framebuffer/MultisampleSystem.js');
require('../core/geometry/BufferSystem.js');
require('../core/geometry/GeometrySystem.js');
require('../core/mask/MaskSystem.js');
require('../core/mask/ScissorSystem.js');
require('../core/mask/StencilSystem.js');
require('../core/plugin/PluginSystem.js');
require('../core/projection/ProjectionSystem.js');
require('../core/render/ObjectRendererSystem.js');
require('../core/Renderer.js');
require('../core/renderTexture/GenerateTextureSystem.js');
require('../core/renderTexture/RenderTexturePool.js');
require('../core/renderTexture/RenderTextureSystem.js');
require('../core/shader/ShaderSystem.js');
require('../core/startup/StartupSystem.js');
var State = require('../core/state/State.js');
require('../core/state/StateSystem.js');
require('../core/textures/TextureGCSystem.js');
require('../core/textures/TextureSystem.js');
require('../core/transformFeedback/TransformFeedbackSystem.js');
require('../core/view/ViewSystem.js');
require('../core/textures/resources/index.js');
require('../display/settings.js');
var Container = require('../display/Container.js');
require('../display/DisplayObject.js');
var MeshBatchUvs = require('./MeshBatchUvs.js');

const tempPoint = new Point.Point();
const tempPolygon = new Polygon.Polygon();
class Mesh extends Container.Container {
  /**
   * @param geometry - The geometry the mesh will use.
   * @param {PIXI.MeshMaterial} shader - The shader the mesh will use.
   * @param state - The state that the WebGL context is required to be in to render the mesh
   *        if no state is provided, uses {@link PIXI.State.for2d} to create a 2D state for PixiJS.
   * @param drawMode - The drawMode, can be any of the {@link PIXI.DRAW_MODES} constants.
   */
  constructor(geometry, shader, state, drawMode = constants.DRAW_MODES.TRIANGLES) {
    super();
    this.geometry = geometry;
    this.shader = shader;
    this.state = state || State.State.for2d();
    this.drawMode = drawMode;
    this.start = 0;
    this.size = 0;
    this.uvs = null;
    this.indices = null;
    this.vertexData = new Float32Array(1);
    this.vertexDirty = -1;
    this._transformID = -1;
    this._roundPixels = settings.settings.ROUND_PIXELS;
    this.batchUvs = null;
  }
  /**
   * Includes vertex positions, face indices, normals, colors, UVs, and
   * custom attributes within buffers, reducing the cost of passing all
   * this data to the GPU. Can be shared between multiple Mesh objects.
   */
  get geometry() {
    return this._geometry;
  }
  set geometry(value) {
    if (this._geometry === value) {
      return;
    }
    if (this._geometry) {
      this._geometry.refCount--;
      if (this._geometry.refCount === 0) {
        this._geometry.dispose();
      }
    }
    this._geometry = value;
    if (this._geometry) {
      this._geometry.refCount++;
    }
    this.vertexDirty = -1;
  }
  /**
   * To change mesh uv's, change its uvBuffer data and increment its _updateID.
   * @readonly
   */
  get uvBuffer() {
    return this.geometry.buffers[1];
  }
  /**
   * To change mesh vertices, change its uvBuffer data and increment its _updateID.
   * Incrementing _updateID is optional because most of Mesh objects do it anyway.
   * @readonly
   */
  get verticesBuffer() {
    return this.geometry.buffers[0];
  }
  /** Alias for {@link PIXI.Mesh#shader}. */
  set material(value) {
    this.shader = value;
  }
  get material() {
    return this.shader;
  }
  /**
   * The blend mode to be applied to the Mesh. Apply a value of
   * `PIXI.BLEND_MODES.NORMAL` to reset the blend mode.
   * @default PIXI.BLEND_MODES.NORMAL;
   */
  set blendMode(value) {
    this.state.blendMode = value;
  }
  get blendMode() {
    return this.state.blendMode;
  }
  /**
   * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.
   * Advantages can include sharper image quality (like text) and faster rendering on canvas.
   * The main disadvantage is movement of objects may appear less smooth.
   * To set the global default, change {@link PIXI.settings.ROUND_PIXELS}
   * @default false
   */
  set roundPixels(value) {
    if (this._roundPixels !== value) {
      this._transformID = -1;
    }
    this._roundPixels = value;
  }
  get roundPixels() {
    return this._roundPixels;
  }
  /**
   * The multiply tint applied to the Mesh. This is a hex value. A value of
   * `0xFFFFFF` will remove any tint effect.
   *
   * Null for non-MeshMaterial shaders
   * @default 0xFFFFFF
   */
  get tint() {
    return "tint" in this.shader ? this.shader.tint : null;
  }
  set tint(value) {
    this.shader.tint = value;
  }
  /**
   * The tint color as a RGB integer
   * @ignore
   */
  get tintValue() {
    return this.shader.tintValue;
  }
  /** The texture that the Mesh uses. Null for non-MeshMaterial shaders */
  get texture() {
    return "texture" in this.shader ? this.shader.texture : null;
  }
  set texture(value) {
    this.shader.texture = value;
  }
  /**
   * Standard renderer draw.
   * @param renderer - Instance to renderer.
   */
  _render(renderer) {
    const vertices = this.geometry.buffers[0].data;
    const shader = this.shader;
    if (shader.batchable && this.drawMode === constants.DRAW_MODES.TRIANGLES && vertices.length < Mesh.BATCHABLE_SIZE * 2) {
      this._renderToBatch(renderer);
    } else {
      this._renderDefault(renderer);
    }
  }
  /**
   * Standard non-batching way of rendering.
   * @param renderer - Instance to renderer.
   */
  _renderDefault(renderer) {
    const shader = this.shader;
    shader.alpha = this.worldAlpha;
    if (shader.update) {
      shader.update();
    }
    renderer.batch.flush();
    shader.uniforms.translationMatrix = this.transform.worldTransform.toArray(true);
    renderer.shader.bind(shader);
    renderer.state.set(this.state);
    renderer.geometry.bind(this.geometry, shader);
    renderer.geometry.draw(this.drawMode, this.size, this.start, this.geometry.instanceCount);
  }
  /**
   * Rendering by using the Batch system.
   * @param renderer - Instance to renderer.
   */
  _renderToBatch(renderer) {
    const geometry = this.geometry;
    const shader = this.shader;
    if (shader.uvMatrix) {
      shader.uvMatrix.update();
      this.calculateUvs();
    }
    this.calculateVertices();
    this.indices = geometry.indexBuffer.data;
    this._tintRGB = shader._tintRGB;
    this._texture = shader.texture;
    const pluginName = this.material.pluginName;
    renderer.batch.setObjectRenderer(renderer.plugins[pluginName]);
    renderer.plugins[pluginName].render(this);
  }
  /** Updates vertexData field based on transform and vertices. */
  calculateVertices() {
    const geometry = this.geometry;
    const verticesBuffer = geometry.buffers[0];
    const vertices = verticesBuffer.data;
    const vertexDirtyId = verticesBuffer._updateID;
    if (vertexDirtyId === this.vertexDirty && this._transformID === this.transform._worldID) {
      return;
    }
    this._transformID = this.transform._worldID;
    if (this.vertexData.length !== vertices.length) {
      this.vertexData = new Float32Array(vertices.length);
    }
    const wt = this.transform.worldTransform;
    const a = wt.a;
    const b = wt.b;
    const c = wt.c;
    const d = wt.d;
    const tx = wt.tx;
    const ty = wt.ty;
    const vertexData = this.vertexData;
    for (let i = 0; i < vertexData.length / 2; i++) {
      const x = vertices[i * 2];
      const y = vertices[i * 2 + 1];
      vertexData[i * 2] = a * x + c * y + tx;
      vertexData[i * 2 + 1] = b * x + d * y + ty;
    }
    if (this._roundPixels) {
      const resolution = settings.settings.RESOLUTION;
      for (let i = 0; i < vertexData.length; ++i) {
        vertexData[i] = Math.round(vertexData[i] * resolution) / resolution;
      }
    }
    this.vertexDirty = vertexDirtyId;
  }
  /** Updates uv field based on from geometry uv's or batchUvs. */
  calculateUvs() {
    const geomUvs = this.geometry.buffers[1];
    const shader = this.shader;
    if (!shader.uvMatrix.isSimple) {
      if (!this.batchUvs) {
        this.batchUvs = new MeshBatchUvs.MeshBatchUvs(geomUvs, shader.uvMatrix);
      }
      this.batchUvs.update();
      this.uvs = this.batchUvs.data;
    } else {
      this.uvs = geomUvs.data;
    }
  }
  /**
   * Updates the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account.
   * there must be a aVertexPosition attribute present in the geometry for bounds to be calculated correctly.
   */
  _calculateBounds() {
    this.calculateVertices();
    this._bounds.addVertexData(this.vertexData, 0, this.vertexData.length);
  }
  /**
   * Tests if a point is inside this mesh. Works only for PIXI.DRAW_MODES.TRIANGLES.
   * @param point - The point to test.
   * @returns - The result of the test.
   */
  containsPoint(point) {
    if (!this.getBounds().contains(point.x, point.y)) {
      return false;
    }
    this.worldTransform.applyInverse(point, tempPoint);
    const vertices = this.geometry.getBuffer("aVertexPosition").data;
    const points = tempPolygon.points;
    const indices = this.geometry.getIndex().data;
    const len = indices.length;
    const step = this.drawMode === 4 ? 3 : 1;
    for (let i = 0; i + 2 < len; i += step) {
      const ind0 = indices[i] * 2;
      const ind1 = indices[i + 1] * 2;
      const ind2 = indices[i + 2] * 2;
      points[0] = vertices[ind0];
      points[1] = vertices[ind0 + 1];
      points[2] = vertices[ind1];
      points[3] = vertices[ind1 + 1];
      points[4] = vertices[ind2];
      points[5] = vertices[ind2 + 1];
      if (tempPolygon.contains(tempPoint.x, tempPoint.y)) {
        return true;
      }
    }
    return false;
  }
  destroy(options) {
    super.destroy(options);
    this.geometry = null;
    this.shader = null;
    this.state = null;
    this.uvs = null;
    this.indices = null;
    this.vertexData = null;
  }
}
Mesh.BATCHABLE_SIZE = 100;

exports.Mesh = Mesh;
//# sourceMappingURL=Mesh.js.map
