Home Reference Source Repository

js/SceneKit/_SCNMtlLoader.js

'use strict'

import TGAImage from 'tgaimage'
import SCNMaterial from './SCNMaterial'
import SKColor from '../SpriteKit/SKColor'
import _File from '../util/_File'
import _FileReader from '../util/_FileReader'
import _TextReader from '../util/_TextReader'

/*global Buffer*/

export default class _SCNMtlLoader {

  constructor(data = null, url = null) {
    /**
     * @access private
     * @type {?string}
     */
    this._filePath = url

    /**
     * @access private
     * @type {?_TextReader}
     */
    this._reader = null

    if(data !== null){
      this._reader = new _TextReader(data, 'utf-8')
    }

    this._node = null

    const funcs = {
      '#': this._Comment,
      'newmtl': this._Material,
      
      'Ka': this._Ambient,
      'Kd': this._Diffuse,
      'Ks': this._Specular,
      'Tf': this._TransmissionFilter,
      'illum': this._Illumination,
      'd': this._Dissolve,
      'Ns': this._Exponent,
      'sharpness': this._Sharpness,
      'Ni': this._Density,

      'map_Ka': this._AmbientTexture,
      'map_Kd': this._DiffuseTexture,
      'map_Ks': this._SpecularTexture,
      'map_Ns': this._ExponentTexture,
      'map_d': this._DissolveTexture,
      'map_aat': this._AntiAliasingTexture,
      'decal': this._Decal,
      'disp': this._Roughness,
      'bump': this._Bump,

      'refl': this._Reflection,

      'Ke': this._Emission,
      'map_Ke': this._EmissionTexture
    }
    this._funcs = {}
    Object.keys(funcs).forEach((key) => {
      this._funcs[key] = funcs[key].bind(this)
    })
  }

  static unarchiveObjectWithData(data, path = null) {
    const unarchiver = new _SCNMtlLoader(data)
    unarchiver._filePath = path
    return unarchiver._loadMtlFile()
  }

  static unarchiveObjectWithFile(path) {
    const promise = _SCNMtlLoader._getBufferOfFile(path)
      .then((data) => {
        return _SCNMtlLoader.unarchiveObjectWithData(data, path)
      })

    return promise
  }

  static _getBufferOfFile(path) {
    const promise = new Promise((resolve, reject) => {
      const file = new _File([], path)
      const reader = new _FileReader()
      reader.onload = () => {
        const data = reader.result
        resolve(data)
      }
      reader.onerror = () => {
        reject(reader.error)
      }
      reader.readAsText(file)
    })
    return promise
  }

  /**
   * @access private
   * @param {string} line -
   * @returns {string[]) -
   */
  _getTokens(line) {
    return line.split(' ').filter((str) => (str !== '')).map((str) => str.trim())
  }

  /**
   * @access private
   * @param {string} path -
   * @returns {Promise} -
   */
  _loadTexture(path) {
    const promise = new Promise((resolve, reject) => {
      const fileName = this._filePath + path
      console.log('obj texture path: ' + fileName)
      if(fileName.endsWith('tga')){
        const tga = TGAImage.imageWithURL(fileName)
        tga.didLoad.then(() => {
          resolve(tga.image)
        })
      }else{
        const image = new Image()
        // TODO: check option if it allows cross-domain.
        image.crossOrigin = 'anonymous'
        image.onload = () => {
          resolve(image)
        }
        image.onerror = () => {
          reject(new Error(`image ${fileName} load error`))
        }
        image.src = fileName
      }
    })

    return promise
  }


  _loadMtlFile() {
    console.warn('_loadMtlFile')

    this._materials = {}
    this._workingMaterial = null
    this._promises = []

    let line = this._reader.readLine()
    this._break = false
    while(!this._break && line !== null){
      const tokens = this._getTokens(line)

      if(tokens.lengt === 0){
        line = this._reader.readLine()
        continue
      }

      const func = this._funcs[tokens[0]]
      if(typeof func === 'undefined'){
        throw new Error('_SCNMtlLoader unknown type: ' + tokens[0])
      }
      func(tokens)

      line = this._reader.readLine()
    }

    return this._materials
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Material(tokens) {
    tokens.shift()
    const materialName = tokens.join(' ')
    const material = new SCNMaterial()
    this._materials[materialName] = material
    this._workingMaterial = material
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Comment(tokens) {
    return
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Comment(tokens) {
    return
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Ambient(tokens) {
    if(tokens[1] === 'spectral'){
      // TODO: implement
    }else if(tokens[1] === 'xyz'){
      // TODO: implement
    }else{
      const r = parseFloat(tokens[1])
      const g = parseFloat(tokens[2])
      const b = parseFloat(tokens[3])
      const a = 1.0
      this._workingMaterial.ambient.contents = new SKColor(r, g, b, a)
    }
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Diffuse(tokens) {
    const r = parseFloat(tokens[1])
    const g = parseFloat(tokens[2])
    const b = parseFloat(tokens[3])
    const a = 1.0
    this._workingMaterial.diffuse.contents = new SKColor(r, g, b, a)
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Specular(tokens) {
    const r = parseFloat(tokens[1])
    const g = parseFloat(tokens[2])
    const b = parseFloat(tokens[3])
    const a = 1.0
    this._workingMaterial.specular.contents = new SKColor(r, g, b, a)
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _TransmissionFilter(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Illumination(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Dissolve(tokens) {
    const d = parseFloat(tokens[1])
    this._workingMaterial.multiply.contents = new SKColor(d, d, d, 1.0)
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Exponent(tokens) {
    this._workingMaterial.shininess = parseFloat(tokens[1])
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Sharpness(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Density(tokens) {
    // opacity
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _AmbientTexture(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _DiffuseTexture(tokens) {
    const material = this._workingMaterial
    this._loadTexture(tokens[1]).then((image) => {
      material.diffuse.contents = image
    })
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _SpecularTexture(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _ExponentTexture(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _DissolveTexture(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _AntiAliasingTexture(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Decal(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Roughness(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Bump(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Reflection(tokens) {
    
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _Emission(tokens) {
    const r = parseFloat(tokens[1])
    const g = parseFloat(tokens[2])
    const b = parseFloat(tokens[3])
    const a = 1.0
    this._workingMaterial.emission.contents = new SKColor(r, g, b, a)
  }

  /**
   * @access private
   * @param {string[]} tokens - 
   * @returns {void}
   */
  _EmissionTexture(tokens) {
    
  }
}