123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /**
- * BRFExporter.js
- *
- * @author realor
- */
- import { Solid } from '../core/Solid.js'
- import { Profile } from '../core/Profile.js'
- import { Cord } from '../core/Cord.js'
- import { SolidGeometry } from '../core/SolidGeometry.js'
- import { ProfileGeometry } from '../core/ProfileGeometry.js'
- import { CordGeometry } from '../core/CordGeometry.js'
- import { Formula } from '../formula/Formula.js'
- import { ObjectUtils } from '../utils/ObjectUtils.js'
- import * as THREE from '../lib/three.module.js'
- class BRFExporter {
- static VERSION = 4
- constructor() {
- this.options = {}
- }
- parse(object) {
- const dateString = new Date().toISOString()
- let model = {
- metadata: {
- format: '4DAGE FILE (brf)',
- version: BRFExporter.VERSION,
- creation: dateString,
- agent: navigator.userAgent
- },
- geometries: {},
- materials: {},
- objects: {},
- root: { type: '#object', id: String(object.id) }
- }
- this.export(object, model)
- return JSON.stringify(model)
- }
- export(object, model) {
- const id = String(object.id)
- let entry = {
- id: id,
- type: object.type,
- name: object.name,
- visible: object.visible,
- castShadow: object.castShadow,
- receiveShadow: object.receiveShadow
- }
- model.objects[id] = entry
- let position = object.position
- if (position.x !== 0 || position.y !== 0 || position.z !== 0) {
- entry.position = this.exportVector(position)
- }
- let rotation = object.rotation
- if (rotation.x !== 0 || rotation.y !== 0 || rotation.z !== 0) {
- entry.rotation = this.exportEuler(rotation)
- }
- let scale = object.scale
- if (scale.x !== 1.0 || scale.y !== 1.0 || scale.z !== 1.0) {
- entry.scale = this.exportVector(scale)
- }
- if (Object.keys(object.userData).length > 0) {
- entry.userData = object.userData
- }
- if (object instanceof Solid) {
- entry.edgesVisible = object.edgesVisible
- entry.facesVisible = object.facesVisible
- }
- let exportGeometry = !(object instanceof THREE.Sprite)
- let exportChildren = ObjectUtils.isExportableChildren(object)
- if (object.builder) {
- entry.builder = this.exportBuilder(object.builder)
- exportGeometry = exportGeometry && !object.builder.isGeometryBuilder(object)
- exportChildren = exportChildren && !object.builder.isChildrenBuilder(object)
- }
- let controllers = object.controllers
- if (controllers) {
- entry.controllers = {}
- for (let key in controllers) {
- let controller = controllers[key]
- entry.controllers[key] = this.exportController(controller)
- }
- }
- let geometry = object.geometry
- if (geometry && exportGeometry) {
- this.exportGeometry(geometry, model)
- entry.geometry = { type: '#geometry', id: String(geometry.id) }
- }
- let material = object.material
- if (material) {
- this.exportMaterial(material, model)
- entry.material = { type: '#material', id: String(material.id) }
- }
- const formulas = Formula.getAll(object)
- if (formulas) {
- entry.formulas = {}
- for (let path in formulas) {
- let formula = formulas[path]
- entry.formulas[formula.path] = formula.expression
- }
- }
- if (exportChildren) {
- for (let child of object.children) {
- if (ObjectUtils.isExportable(child)) {
- this.export(child, model)
- if (entry.children === undefined) {
- entry.children = []
- }
- entry.children.push({ type: '#object', id: String(child.id) })
- }
- }
- }
- }
- exportGeometry(geometry, model) {
- const id = String(geometry.id)
- if (typeof model.geometries[id] === 'undefined') {
- let entry = {
- id: id
- }
- if (geometry instanceof SolidGeometry) {
- entry.type = 'SolidGeometry'
- entry.vertices = []
- for (let vertex of geometry.vertices) {
- entry.vertices.push(this.exportVector(vertex))
- }
- entry.faces = []
- entry.isManifold = geometry.isManifold
- entry.smoothAngle = geometry.smoothAngle
- for (let face of geometry.faces) {
- if (face.holes.length === 0) {
- entry.faces.push(face.indices)
- } else {
- let loops = [face.indices]
- for (let hole of face.holes) {
- loops.push(hole.indices)
- }
- entry.faces.push(loops)
- }
- }
- } else if (geometry instanceof ProfileGeometry) {
- const path = geometry.path
- entry.type = 'ProfileGeometry'
- entry.isClosed = geometry.isClosed()
- const points = path.getPoints()
- entry.points = []
- for (let point of points) {
- entry.points.push(this.exportVector(point))
- }
- if (path instanceof THREE.Shape) {
- entry.holes = []
- const holes = path.getPointsHoles()
- for (let hole of holes) {
- const holePoints = []
- entry.holes.push(holePoints)
- for (let point of hole) {
- holePoints.push(this.exportVector(point))
- }
- }
- }
- } else if (geometry instanceof CordGeometry) {
- entry.type = 'CordGeometry'
- entry.points = []
- for (let point of geometry.points) {
- entry.points.push({ x: point.x, y: point.y, z: point.z })
- }
- } else if (geometry instanceof THREE.BufferGeometry) {
- entry.type = 'BufferGeometry'
- entry.attributes = {}
- const attributes = geometry.attributes
- for (let name in attributes) {
- let attribute = attributes[name]
- entry.attributes[name] = {
- type: attribute.constructor.name,
- arrayType: attribute.array.constructor.name,
- itemSize: attribute.itemSize,
- normalized: attribute.normalized,
- array: this.exportBufferAttributeArray(attribute)
- }
- }
- }
- model.geometries[id] = entry
- }
- }
- exportMaterial(material, model) {
- const id = String(material.id)
- if (typeof model.materials[id] === 'undefined') {
- let entry = {
- id: id,
- type: material.type,
- name: material.name,
- opacity: material.opacity,
- transparent: material.transparent,
- side: material.side,
- depthTest: material.depthTest,
- depthWrite: material.depthWrite,
- polygonOffset: material.polygonOffset,
- polygonOffsetFactor: material.polygonOffsetFactor,
- polygonOffsetUnits: material.polygonOffsetUnits
- }
- if (material.color) {
- entry.color = '#' + material.color.getHexString()
- }
- if (material instanceof THREE.MeshPhongMaterial) {
- entry.specular = '#' + material.specular.getHexString()
- entry.emissive = '#' + material.emissive.getHexString()
- entry.shininess = material.shininess
- entry.reflectivity = material.reflectivity
- }
- if (material instanceof THREE.SpriteMaterial) {
- entry.sizeAttenuation = material.sizeAttenuation
- }
- if (material.map) {
- entry.map = { type: 'Texture', image: material.map.name }
- }
- model.materials[id] = entry
- }
- }
- exportBuilder(builder) {
- const builderEntry = {}
- builderEntry.type = builder.constructor.name
- this.exportProperties(builder, builderEntry)
- return builderEntry
- }
- exportController(controller) {
- const controllerEntry = {}
- controllerEntry.type = controller.constructor.name
- this.exportProperties(controller, controllerEntry, 'name', 'object')
- return controllerEntry
- }
- exportProperties(element, entry, ...exclude) {
- const properties = Object.keys(element)
- for (let property of properties) {
- if (!property.startsWith('_') && !exclude.includes(property)) {
- let value = element[property]
- let type = typeof value
- if (type === 'number' || type === 'string' || type === 'boolean') {
- entry[property] = value
- } else if (value instanceof THREE.Vector3 || value instanceof THREE.Vector2) {
- entry[property] = this.exportVector(value)
- } else if (value instanceof THREE.Euler) {
- entry[property] = this.exportEuler(value)
- } else if (value instanceof THREE.Color) {
- entry[property] = this.exportColor(value)
- } else if (value instanceof THREE.Object3D) {
- entry[property] = { type: '#object', id: String(value.id) }
- }
- }
- }
- return entry
- }
- exportVector(vector) {
- const v = { x: vector.x, y: vector.y }
- if (vector instanceof THREE.Vector3) {
- v.z = vector.z
- }
- return v
- }
- exportEuler(euler) {
- return { type: 'Euler', x: euler.x, y: euler.y, z: euler.z }
- }
- exportColor(color) {
- return '#' + color.getHexString()
- }
- exportBufferAttributeArray(attribute) {
- const compress = attribute.name !== 'index' && (this.options.enableBufferGeometryCompression === undefined || this.options.enableBufferGeometryCompression === true)
- const array = attribute.array
- const precision7 = array instanceof Float32Array
- if (compress) {
- const compressedArray = []
- const itemSize = attribute.itemSize
- const map = new Map()
- for (let i = 0; i < array.length; i += itemSize) {
- let vector = []
- for (let k = 0; k < itemSize; k++) {
- if (precision7) {
- vector.push(parseFloat(array[i + k].toPrecision(7)))
- } else {
- vector.push(array[i + k])
- }
- }
- let key = vector.join(',')
- let itemIndex = map.get(key)
- if (itemIndex === undefined) {
- itemIndex = i / itemSize
- map.set(key, itemIndex)
- compressedArray.push(vector)
- } else {
- compressedArray.push(itemIndex)
- }
- }
- return compressedArray
- } else {
- if (precision7) {
- const directArray = []
- for (let i = 0; i < array.length; i++) {
- directArray.push(parseFloat(array[i].toPrecision(7)))
- }
- return directArray
- } else {
- return Array.from(array)
- }
- }
- }
- }
- export { BRFExporter }
|