Home Reference Source Repository

js/base/ModelBank.js

'use strict'

/**
 * ModelBank class
 * @access public
 */
export class ModelBank {
  /**
   * constructor
   * @access public
   * @constructor
   */
  constructor() {
    /** @type {Map} */
    //this._models = new Map()
    /** @type {Map} */
    this._loadingModels = new Map()
    /** @type {Map} */
    this._promises = new Map()
    /** @type {Map} */
    this._modelsOfContext = new Map()
    /** @type {Array<ModelReader>} */
    this._modelReaders = []
  }

  addModelReader(modelReader) {
    this._modelReaders.push(modelReader)
  }

  getFileID(file) {
    if(!(file instanceof File)){
      return ''
    }
    return `FILE:${file.name}_${file.size}_${file.lastModifiedDate}`
  }

  getModel(modelFile, options) {
    if(modelFile instanceof File){
      return this.getModelFromFile(modelFile, options)
    }

    let promise = this._promises.get(modelFile)
    if(promise){
      return promise.then((loadedModel) => {
        loadedModel.hashName = modelFile
        return loadedModel.clone()
      })
    }

    let reader = null
    this._modelReaders.some((readerClass) => {
      if(readerClass.canRead(modelFile)){
        reader = new readerClass()
        return true
      }
      return false
    })

    if(!reader){
      return Promise.reject(`can't read file: ${modelFile}`)
    }

    promise = reader.readModel(modelFile)
    this._promises.set(modelFile, promise)

    return promise.then((loadedModel) => {
      loadedModel.hashName = modelFile
      return loadedModel.clone()
    })
  }

  getModelFromFile(modelFile, options) {
    const id = this.getFileID(modelFile)
    const model = this._models.get(id)

    if(model){
      const m = model.clone()
      return Promise.resolve(m)
    }

    let promise = null
    this._modelReaders.some((readerClass) => {
      if(readerClass.canRead(modelFile)){
        const reader = new readerClass()
        promise = reader.readModelFromFile(modelFile)
        return true
      }
      return false
    })
    
    if(promise){
      return promise.then((loadedModel) => {
        // FIXME: don't use model.hashName
        loadedModel.hashName = id

        this._models.set(id, loadedModel)

        const newModel = loadedModel.clone()

        return newModel
      })
    }

    return Promise.reject(`can't read file: ${modelFile}`)
  }

  getModelForRenderer(modelFile, renderer) {
    let models = this._modelsOfContext.get(modelFile)
    if(!models){
      models = new Map()
      this._modelsOfContext.set(modelFile, models)
    }

    const gl = renderer.getContext()
    const model = models.get(gl)
    if(model){
      return Promise.resolve(model)
    }

    const promise = this.getModel(modelFile).then((orgModel) => {
      // vertex buffer
      orgModel.vertexBuffer = gl.createBuffer()
      gl.bindBuffer(gl.ARRAY_BUFFER, orgModel.vertexBuffer)
      gl.bufferData(gl.ARRAY_BUFFER, renderer.getVertexData(orgModel), gl.DYNAMIC_DRAW)

      // index buffer
      orgModel.renderGroupArray.forEach( (group) => {
        group.indexBuffer = gl.createBuffer()
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, group.indexBuffer)
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, group.getIndexData(), gl.STATIC_DRAW)
      })

      orgModel.renderer = renderer
      models.set(gl, orgModel)

      return orgModel.clone()
    })

    return promise
  }
}

// for singleton
export default new ModelBank()