'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getPixelRatio = undefined;
exports.drawLayers = drawLayers;
exports.drawPickingBuffer = drawPickingBuffer;

var _luma = require('luma.gl');

var _log = require('../utils/log');

var _log2 = _interopRequireDefault(_log);

var _assert = require('../utils/assert');

var _assert2 = _interopRequireDefault(_assert);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var LOG_PRIORITY_DRAW = 2; // Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/* global window */


var renderCount = 0;

// TODO - Exported for pick-layers.js - Move to util?
var getPixelRatio = exports.getPixelRatio = function getPixelRatio(_ref) {
  var useDevicePixels = _ref.useDevicePixels;

  (0, _assert2.default)(typeof useDevicePixels === 'boolean', 'Invalid useDevicePixels');
  return useDevicePixels && typeof window !== 'undefined' ? window.devicePixelRatio : 1;
};

// Convert viewport top-left CSS coordinates to bottom up WebGL coordinates
var getGLViewport = function getGLViewport(gl, _ref2) {
  var viewport = _ref2.viewport,
      pixelRatio = _ref2.pixelRatio;

  // TODO - dummy default for node
  var height = gl.canvas ? gl.canvas.clientHeight : 100;
  // Convert viewport top-left CSS coordinates to bottom up WebGL coordinates
  var dimensions = viewport;
  return [dimensions.x * pixelRatio, (height - dimensions.y - dimensions.height) * pixelRatio, dimensions.width * pixelRatio, dimensions.height * pixelRatio];
};

// Helper functions

function clearCanvas(gl, _ref3) {
  var useDevicePixels = _ref3.useDevicePixels;

  // const pixelRatio = getPixelRatio({useDevicePixels});
  var width = gl.drawingBufferWidth;
  var height = gl.drawingBufferHeight;
  // clear depth and color buffers, restoring transparency
  (0, _luma.withParameters)(gl, { viewport: [0, 0, width, height] }, function () {
    gl.clear(_luma.GL.COLOR_BUFFER_BIT | _luma.GL.DEPTH_BUFFER_BIT);
  });
}

// Draw a list of layers in a list of viewports
function drawLayers(gl, _ref4) {
  var layers = _ref4.layers,
      viewports = _ref4.viewports,
      onViewportActive = _ref4.onViewportActive,
      useDevicePixels = _ref4.useDevicePixels,
      _ref4$drawPickingColo = _ref4.drawPickingColors,
      drawPickingColors = _ref4$drawPickingColo === undefined ? false : _ref4$drawPickingColo,
      _ref4$deviceRect = _ref4.deviceRect,
      deviceRect = _ref4$deviceRect === undefined ? null : _ref4$deviceRect,
      _ref4$parameters = _ref4.parameters,
      parameters = _ref4$parameters === undefined ? {} : _ref4$parameters,
      _ref4$layerFilter = _ref4.layerFilter,
      layerFilter = _ref4$layerFilter === undefined ? null : _ref4$layerFilter,
      _ref4$pass = _ref4.pass,
      pass = _ref4$pass === undefined ? 'draw' : _ref4$pass,
      _ref4$redrawReason = _ref4.redrawReason,
      redrawReason = _ref4$redrawReason === undefined ? '' : _ref4$redrawReason,
      stats = _ref4.stats;

  clearCanvas(gl, { useDevicePixels: useDevicePixels });

  // effectManager.preDraw();

  viewports.forEach(function (viewportOrDescriptor, i) {
    var viewport = getViewportFromDescriptor(viewportOrDescriptor);

    // Update context to point to this viewport
    onViewportActive(viewport);

    // render this viewport
    drawLayersInViewport(gl, {
      layers: layers,
      viewport: viewport,
      useDevicePixels: useDevicePixels,
      drawPickingColors: drawPickingColors,
      deviceRect: deviceRect,
      parameters: parameters,
      layerFilter: layerFilter,
      pass: pass,
      redrawReason: redrawReason,
      stats: stats
    });
  });

  // effectManager.draw();
}

// Draws list of layers and viewports into the picking buffer
// Note: does not sample the buffer, that has to be done by the caller
function drawPickingBuffer(gl, _ref5) {
  var layers = _ref5.layers,
      viewports = _ref5.viewports,
      onViewportActive = _ref5.onViewportActive,
      useDevicePixels = _ref5.useDevicePixels,
      pickingFBO = _ref5.pickingFBO,
      _ref5$deviceRect = _ref5.deviceRect,
      x = _ref5$deviceRect.x,
      y = _ref5$deviceRect.y,
      width = _ref5$deviceRect.width,
      height = _ref5$deviceRect.height,
      _ref5$layerFilter = _ref5.layerFilter,
      layerFilter = _ref5$layerFilter === undefined ? null : _ref5$layerFilter,
      _ref5$redrawReason = _ref5.redrawReason,
      redrawReason = _ref5$redrawReason === undefined ? '' : _ref5$redrawReason;

  // Make sure we clear scissor test and fbo bindings in case of exceptions
  // We are only interested in one pixel, no need to render anything else
  // Note that the callback here is called synchronously.
  // Set blend mode for picking
  // always overwrite existing pixel with [r,g,b,layerIndex]
  return (0, _luma.withParameters)(gl, {
    framebuffer: pickingFBO,
    scissorTest: true,
    scissor: [x, y, width, height],
    clearColor: [0, 0, 0, 0]
  }, function () {
    drawLayers(gl, {
      layers: layers,
      viewports: viewports,
      onViewportActive: onViewportActive,
      useDevicePixels: useDevicePixels,
      drawPickingColors: true,
      layerFilter: layerFilter,
      pass: 'picking',
      redrawReason: redrawReason,
      parameters: {
        blend: true,
        blendFunc: [gl.ONE, gl.ZERO, gl.CONSTANT_ALPHA, gl.ZERO],
        blendEquation: gl.FUNC_ADD,
        blendColor: [0, 0, 0, 0]
      }
    });
  });
}

// Draws a list of layers in one viewport
// TODO - when picking we could completely skip rendering viewports that dont
// intersect with the picking rect
function drawLayersInViewport(gl, _ref6) {
  var layers = _ref6.layers,
      viewport = _ref6.viewport,
      useDevicePixels = _ref6.useDevicePixels,
      _ref6$drawPickingColo = _ref6.drawPickingColors,
      drawPickingColors = _ref6$drawPickingColo === undefined ? false : _ref6$drawPickingColo,
      _ref6$deviceRect = _ref6.deviceRect,
      deviceRect = _ref6$deviceRect === undefined ? null : _ref6$deviceRect,
      _ref6$parameters = _ref6.parameters,
      parameters = _ref6$parameters === undefined ? {} : _ref6$parameters,
      layerFilter = _ref6.layerFilter,
      _ref6$pass = _ref6.pass,
      pass = _ref6$pass === undefined ? 'draw' : _ref6$pass,
      _ref6$redrawReason = _ref6.redrawReason,
      redrawReason = _ref6$redrawReason === undefined ? '' : _ref6$redrawReason,
      stats = _ref6.stats;

  var pixelRatio = getPixelRatio({ useDevicePixels: useDevicePixels });
  var glViewport = getGLViewport(gl, { viewport: viewport, pixelRatio: pixelRatio });

  // render layers in normal colors
  var renderStats = {
    totalCount: layers.length,
    visibleCount: 0,
    compositeCount: 0,
    pickableCount: 0
  };

  // const {x, y, width, height} = deviceRect || [];

  (0, _luma.setParameters)(gl, parameters || {});

  // render layers in normal colors
  layers.forEach(function (layer, layerIndex) {
    // Check if we should draw layer
    var shouldDrawLayer = layer.props.visible;
    if (drawPickingColors) {
      shouldDrawLayer = shouldDrawLayer && layer.props.pickable;
    }
    if (shouldDrawLayer && layerFilter) {
      shouldDrawLayer = layerFilter({ layer: layer, viewport: viewport, isPicking: drawPickingColors });
    }

    // Calculate stats
    if (shouldDrawLayer && layer.props.pickable) {
      renderStats.pickableCount++;
    }
    if (layer.isComposite) {
      renderStats.compositeCount++;
    }

    // Draw the layer
    if (shouldDrawLayer) {
      if (!layer.isComposite) {
        renderStats.visibleCount++;
      }

      drawLayerInViewport({
        gl: gl,
        layer: layer,
        layerIndex: layerIndex,
        drawPickingColors: drawPickingColors,
        pixelRatio: pixelRatio,
        glViewport: glViewport,
        parameters: parameters
      });
    }
  });

  renderCount++;

  logRenderStats({ renderStats: renderStats, pass: pass, redrawReason: redrawReason, stats: stats });
}

function drawLayerInViewport(_ref7) {
  var gl = _ref7.gl,
      layer = _ref7.layer,
      layerIndex = _ref7.layerIndex,
      drawPickingColors = _ref7.drawPickingColors,
      pixelRatio = _ref7.pixelRatio,
      glViewport = _ref7.glViewport,
      parameters = _ref7.parameters;

  var moduleParameters = Object.assign({}, layer.props, {
    viewport: layer.context.viewport,
    pickingActive: drawPickingColors ? 1 : 0,
    devicePixelRatio: pixelRatio
  });

  var uniforms = Object.assign({}, layer.context.uniforms, { layerIndex: layerIndex });

  // All parameter resolving is done here instead of the layer
  // Blend parameters must not be overriden
  var layerParameters = Object.assign({}, layer.props.parameters || {}, parameters);

  Object.assign(layerParameters, {
    viewport: glViewport
  });

  if (drawPickingColors) {
    Object.assign(layerParameters, {
      blendColor: [0, 0, 0, (layerIndex + 1) / 255]
    });
  } else {
    Object.assign(moduleParameters, getObjectHighlightParameters(layer));
  }

  layer.drawLayer({
    moduleParameters: moduleParameters,
    uniforms: uniforms,
    parameters: layerParameters
  });
}

function logRenderStats(_ref8) {
  var renderStats = _ref8.renderStats,
      pass = _ref8.pass,
      redrawReason = _ref8.redrawReason,
      stats = _ref8.stats;

  if (_log2.default.priority >= LOG_PRIORITY_DRAW) {
    var totalCount = renderStats.totalCount,
        visibleCount = renderStats.visibleCount,
        compositeCount = renderStats.compositeCount,
        pickableCount = renderStats.pickableCount;

    var primitiveCount = totalCount - compositeCount;
    var hiddenCount = primitiveCount - visibleCount;

    var message = '';
    message += 'RENDER #' + renderCount + ' ' + visibleCount + ' (of ' + totalCount + ' layers) to ' + pass + ' because ' + redrawReason + ' ';
    if (_log2.default.priority > LOG_PRIORITY_DRAW) {
      message += '(' + hiddenCount + ' hidden, ' + compositeCount + ' composite ' + pickableCount + ' pickable)';
    }

    _log2.default.log(LOG_PRIORITY_DRAW, message)();

    stats.increment('redraw layers', visibleCount);
  }
}

// Get a viewport from a viewport descriptor (which can be a plain viewport)
function getViewportFromDescriptor(viewportOrDescriptor) {
  return viewportOrDescriptor.viewport ? viewportOrDescriptor.viewport : viewportOrDescriptor;
}

/**
 * Returns the picking color of currenlty selected object of the given 'layer'.
 * @return {Array} - the picking color or null if layers selected object is invalid.
 */
function getObjectHighlightParameters(layer) {
  // TODO - inefficient to update settings every render?
  // TODO: Add warning if 'highlightedObjectIndex' is > numberOfInstances of the model.

  // Update picking module settings if highlightedObjectIndex is set.
  // This will overwrite any settings from auto highlighting.
  if (Number.isInteger(layer.props.highlightedObjectIndex)) {
    var pickingSelectedColor = layer.props.highlightedObjectIndex >= 0 ? layer.encodePickingColor(layer.props.highlightedObjectIndex) : null;

    return {
      pickingSelectedColor: pickingSelectedColor
    };
  }
  return null;
}
//# sourceMappingURL=draw-layers.js.map