NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/buffer/ribbon-buffer.js

/**
 * @file Ribbon Buffer
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

import '../shader/Ribbon.vert'

import { getUintArray } from '../utils.js'
import { serialArray } from '../math/array-utils.js'
import MeshBuffer from './mesh-buffer.js'

const quadIndices = new Uint16Array([
  0, 1, 2,
  1, 3, 2
])

/**
 * Ribbon buffer. Draws a thin ribbon.
 */
class RibbonBuffer extends MeshBuffer {
    /**
     * @param  {Object} data - attribute object
     * @param  {Float32Array} data.position - positions
     * @param  {Float32Array} data.normal - normals
     * @param  {Float32Array} data.dir - binormals
     * @param  {Float32Array} data.color - colors
     * @param  {Float32Array} data.size - sizes
     * @param  {Picker} data.picking - picking ids
     * @param  {BufferParameters} params - parameter object
     */
  constructor (data, params) {
    var d = data || {}

    var n = (d.position.length / 3) - 1
    var n4 = n * 4
    var x = n4 * 3

    var meshPosition = new Float32Array(x)
    var meshColor = new Float32Array(x)
    var meshNormal = new Float32Array(x)
    var meshIndex = getUintArray(x, x / 3)

    super({
      position: meshPosition,
      color: meshColor,
      index: meshIndex,
      normal: meshNormal,
      picking: d.picking
    }, params)

    this.addAttributes({
      'dir': { type: 'v3', value: new Float32Array(x) }
    })
    this.addAttributes({
      'size': { type: 'f', value: new Float32Array(n4) }
    })

    d.primitiveId = serialArray(n)
    this.setAttributes(d)

    this.meshIndex = meshIndex
    this.makeIndex()
  }

  setAttributes (data) {
    var n4 = this.size
    var n = n4 / 4

    var attributes = this.geometry.attributes

    var position, normal, size, dir, color, primitiveId
    var aPosition, aNormal, aSize, aDir, aColor, aPrimitiveId

    if (data.position) {
      position = data.position
      aPosition = attributes.position.array
      attributes.position.needsUpdate = true
    }

    if (data.normal) {
      normal = data.normal
      aNormal = attributes.normal.array
      attributes.normal.needsUpdate = true
    }

    if (data.size) {
      size = data.size
      aSize = attributes.size.array
      attributes.size.needsUpdate = true
    }

    if (data.dir) {
      dir = data.dir
      aDir = attributes.dir.array
      attributes.dir.needsUpdate = true
    }

    if (data.color) {
      color = data.color
      aColor = attributes.color.array
      attributes.color.needsUpdate = true
    }

    if (data.primitiveId) {
      primitiveId = data.primitiveId
      aPrimitiveId = attributes.primitiveId.array
      attributes.primitiveId.needsUpdate = true
    }

    var v, i, k, p, l, v3
    var currSize
    var prevSize = size ? size[ 0 ] : null

    for (v = 0; v < n; ++v) {
      v3 = v * 3
      k = v * 3 * 4
      l = v * 4

      if (position) {
        aPosition[ k ] = aPosition[ k + 3 ] = position[ v3 ]
        aPosition[ k + 1 ] = aPosition[ k + 4 ] = position[ v3 + 1 ]
        aPosition[ k + 2 ] = aPosition[ k + 5 ] = position[ v3 + 2 ]

        aPosition[ k + 6 ] = aPosition[ k + 9 ] = position[ v3 + 3 ]
        aPosition[ k + 7 ] = aPosition[ k + 10 ] = position[ v3 + 4 ]
        aPosition[ k + 8 ] = aPosition[ k + 11 ] = position[ v3 + 5 ]
      }

      if (normal) {
        aNormal[ k ] = aNormal[ k + 3 ] = -normal[ v3 ]
        aNormal[ k + 1 ] = aNormal[ k + 4 ] = -normal[ v3 + 1 ]
        aNormal[ k + 2 ] = aNormal[ k + 5 ] = -normal[ v3 + 2 ]

        aNormal[ k + 6 ] = aNormal[ k + 9 ] = -normal[ v3 + 3 ]
        aNormal[ k + 7 ] = aNormal[ k + 10 ] = -normal[ v3 + 4 ]
        aNormal[ k + 8 ] = aNormal[ k + 11 ] = -normal[ v3 + 5 ]
      }

      for (i = 0; i < 4; ++i) {
        p = k + 3 * i

        if (color) {
          aColor[ p ] = color[ v3 ]
          aColor[ p + 1 ] = color[ v3 + 1 ]
          aColor[ p + 2 ] = color[ v3 + 2 ]
        }

        if (primitiveId) {
          aPrimitiveId[ l + i ] = primitiveId[ v ]
        }
      }

      if (size) {
        currSize = size[ v ]

        if (prevSize !== size[ v ]) {
          aSize[ l ] = prevSize
          aSize[ l + 1 ] = prevSize
          aSize[ l + 2 ] = currSize
          aSize[ l + 3 ] = currSize
        } else {
          aSize[ l ] = currSize
          aSize[ l + 1 ] = currSize
          aSize[ l + 2 ] = currSize
          aSize[ l + 3 ] = currSize
        }

        prevSize = currSize
      }

      if (dir) {
        aDir[ k ] = dir[ v3 ]
        aDir[ k + 1 ] = dir[ v3 + 1 ]
        aDir[ k + 2 ] = dir[ v3 + 2 ]

        aDir[ k + 3 ] = -dir[ v3 ]
        aDir[ k + 4 ] = -dir[ v3 + 1 ]
        aDir[ k + 5 ] = -dir[ v3 + 2 ]

        aDir[ k + 6 ] = dir[ v3 + 3 ]
        aDir[ k + 7 ] = dir[ v3 + 4 ]
        aDir[ k + 8 ] = dir[ v3 + 5 ]

        aDir[ k + 9 ] = -dir[ v3 + 3 ]
        aDir[ k + 10 ] = -dir[ v3 + 4 ]
        aDir[ k + 11 ] = -dir[ v3 + 5 ]
      }
    }
  }

  makeIndex () {
    var meshIndex = this.meshIndex
    var n = meshIndex.length / 4 / 3

    var s, v, ix, it

    for (v = 0; v < n; ++v) {
      ix = v * 6
      it = v * 4

      meshIndex.set(quadIndices, ix)
      for (s = 0; s < 6; ++s) {
        meshIndex[ ix + s ] += it
      }
    }
  }

  get vertexShader () { return 'Ribbon.vert' }
}

export default RibbonBuffer