js/SceneKit/SCNGeometryElement.js
'use strict'
import NSObject from '../ObjectiveC/NSObject'
import SCNGeometryPrimitiveType from './SCNGeometryPrimitiveType'
/*global Buffer*/
/**
* A container for index data describing how vertices connect to define a three-dimensional object, or geometry.
* @access public
* @extends {NSObject}
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement
*/
export default class SCNGeometryElement extends NSObject {
static get _propTypes() {
return {
$constructor: (propNames, propValues) => {
const element = new SCNGeometryElement(
propValues.elementData,
propValues.primitiveType,
propValues.primitiveCount,
propValues.bytesPerIndex
)
if(typeof propValues.maximumPointScreenSpaceRadius !== 'undefined'){
element.maximumPointScreenSpaceRadius = propValues.maximumPointScreenSpaceRadius
}
if(typeof propValues.minimumPointScreenSpaceRadius !== 'undefined'){
element.minimumPointScreenSpaceRadius = propValues.minimumPointScreenSpaceRadius
}
if(typeof propValues.ptSize !== 'undefined'){
element.pointSize = propValues.ptSize
}
return element
},
primitiveType: ['integer', null],
primitiveCount: ['integer', null],
elementData: ['NSMutableData', null],
bytesPerIndex: ['integer', null],
primitiveRangeLocation: ['integer', null],
primitiveRangeLength: ['integer', null],
ptSize: ['float', null],
indicesChannelCount: ['integer', null],
interleavedIndicesChannels: ['integer', null],
minimumPointScreenSpaceRadius: ['float', null],
maximumPointScreenSpaceRadius: ['float', null]
}
}
// Creating a Geometry Element
/**
* Creates a geometry element from the specified array of index values.
* @access public
* @constructor
* @param {number[]|Buffer} indices - An array of index values, each of which identifies a vertex in a geometry source.
* @param {SCNGeometryPrimitiveType} primitiveType - The drawing primitive that connects vertices when rendering the geometry element. For possible values, see SCNGeometryPrimitiveType.
* @param {?number} primitiveCount -
* @param {number} [bytesPerIndex = 2] -
* @desc SceneKit connects the vertices in the order specified by the indices array, arranged according to the primitiveType parameter.This initializer is equivalent to the init(data:primitiveType:primitiveCount:bytesPerIndex:) initializer, but does not require an intermediary Data object; instead, it automatically infers the necessary allocation size and bytesPerIndex values based on the contents of the indices array. To create a custom SCNGeometry object from the geometry element, use the init(sources:elements:) initializer.
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1523191-init
*/
constructor(indices, primitiveType, primitiveCount = null, bytesPerIndex = 2) {
super()
// Inspecting a Geometry Element
this._data = indices
if(indices instanceof Buffer){
const _data = []
const count = indices.length / bytesPerIndex
let _offset = 0
for(let i=0; i<count; i++){
_data.push(indices.readUIntLE(_offset, bytesPerIndex))
_offset += bytesPerIndex
}
this._data = _data
}
this._primitiveType = primitiveType
if(primitiveCount !== null){
this._primitiveCount = primitiveCount
}else{
switch(primitiveType){
case SCNGeometryPrimitiveType.triangles:
this._primitiveCount = this._data.length / 3
break
case SCNGeometryPrimitiveType.triangleStrip:
this._primitiveCount = this._data.length - 2
break
case SCNGeometryPrimitiveType.line:
this._primitiveCount = this._data.length / 2
break
case SCNGeometryPrimitiveType.point:
this._primitiveCount = this._data.length
break
case SCNGeometryPrimitiveType.polygon:
this._primitiveCount = this._data.length / 2
break
default:
throw new Error('unknown primitive type: ' + primitiveType)
}
}
this._bytesPerIndex = bytesPerIndex
/**
* @type {TypedArray}
* @access private
*/
this._glData = null
//console.log(`SCNGeometryElement: bytesPerIndex: ${bytesPerIndex}`)
if(bytesPerIndex === 1){
this._glData = new Uint8Array(this._data)
}else if(bytesPerIndex === 2){
this._glData = new Uint16Array(this._data)
}else if(bytesPerIndex === 4){
this._glData = new Uint32Array(this._data)
}else{
throw new Error(`unknown data size: ${bytesPerIndex}`)
}
/**
* @type {number}
*/
this.maximumPointScreenSpaceRadius = 0.0 // TODO: check the default value
/**
* @type {number}
*/
this.minimumPointScreenSpaceRadius = 0.0 // TODO: check the default value
/**
* @type {number}
*/
this.pointSize = 0.0 // TODO: check the default value
/**
* @type {NSRange}
*/
this.primitiveRange = null // TODO: check the default value
}
/**
* Creates a geometry element from the specified Model I/O submesh object.
* @access public
* @param {MDLSubmesh} mdlSubMesh -
* @returns {void}
* @desc The Model I/O framework provides universal support for import, export, description, and processing of several 3D asset file formats and related resources. (For details, see Model I/O.) The MDLSubmesh class is a generic description of an index buffer to be used in rendering a 3D object, along with an assigned material. In SceneKit, materials are assigned to a geometry rather than to its elements, so importing a submesh as a geometry element does not import its material assignment. To import a Model I/O mesh along with its materials, use the SCNGeometry init(mdlMesh:) method.
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1419843-init
*/
initMdlSubmesh(mdlSubMesh) {
}
// Inspecting a Geometry Element
/**
* The drawing primitive that connects vertices when rendering the geometry element.
* @type {SCNGeometryPrimitiveType}
* @desc For possible values, see SCNGeometryPrimitiveType.
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1522917-primitivetype
*/
get primitiveType() {
return this._primitiveType
}
/**
* The number of primitives in the element.
* @type {number}
* @desc
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1523404-primitivecount
*/
get primitiveCount() {
return this._primitiveCount
}
/**
* The data describing the geometry element.
* @type {Data}
* @desc An element’s data is an array of index values identifying vertices in a geometry source. SceneKit interprets the data as an array of unsigned integers, whose size is specified by the bytesPerIndex property.
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1523367-data
*/
get data() {
return this._data
}
/**
* The number of bytes that represent each index value in the element’s data.
* @type {number}
* @desc An element’s data property holds an array of index values identifying vertices in a geometry source. SceneKit interprets the data as an array of unsigned integers, whose size is specified by the bytesPerIndex property.
* @see https://developer.apple.com/documentation/scenekit/scngeometryelement/1522720-bytesperindex
*/
get bytesPerIndex() {
return this._bytesPerIndex
}
_createBuffer(context) {
const gl = context
this._buffer = gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._glData, gl.STATIC_DRAW)
return this._buffer
}
copy() {
const element = new SCNGeometryElement(
this._data.slice(0),
this._primitiveType,
this._primitiveCount,
this._bytesPerIndex
)
return element
}
/**
* @access private
* @param {number} index -
* @returns {number[]} -
*/
_indexAt(index) {
if(index < 0 || index >= this.primitiveCount){
throw new Error(`index out of range: ${index} (0 - ${this.primitiveCount - 1})`)
}
const arr = []
const len = this._primitiveCount
if(this._primitiveType === SCNGeometryPrimitiveType.triangles){
const i = index * 3
return [
this._data[i+0],
this._data[i+1],
this._data[i+2]
]
}else if(this._primitiveType === SCNGeometryPrimitiveType.triangleStrip){
return [
this._data[index+0],
this._data[index+1],
this._data[index+2]
]
}else if(this._primitiveType === SCNGeometryPrimitiveType.line){
const i = index * 2
return [
this._data[i+0],
this._data[i+1]
]
}else if(this._primitiveType === SCNGeometryPrimitiveType.point){
return [this._data[index]]
}else if(this._primitiveType === SCNGeometryPrimitiveType.polygon){
return [
this._data[0],
this._data[index+1],
this._data[index+2]
]
}
throw new Error(`unknown primitive type: ${this._primitiveType}`)
}
}