import { RenderArgs , DefaultKernelExport , RenderResponse , createUnhealthyResponse , createHealthyResponse , } from '../common' ; import { MeshPhongMaterial , LineBasicMaterial , BufferGeometry , BufferAttribute , Line , LineSegments , Color , Mesh , } from 'three' ; import { jsCadToCadhubParams } from './jscadParams' ; import TheWorker from 'worker-loader!./jscadWorker' ; const materials = { mesh : { def : new MeshPhongMaterial ( { color : 0x13579d , flatShading : true } ) , material : ( params ) => new MeshPhongMaterial ( params ) , } , line : { def : new LineBasicMaterial ( { color : 0x0000ff } ) , material : ( { color , opacity , transparent } ) => new LineBasicMaterial ( { color , opacity , transparent } ) , } , lines : null , } ; materials . lines = materials . line ; interface CsgObj { vertices : Float32Array ; indices : Uint16Array ; color ? : [ number , number , number , number ] ; transforms : number [ ] ; type : 'mesh' | 'line' | 'lines' ; } function CSGArray2R3fComponent ( Csgs ) { return Csgs . map ( ( { vertices , indices , color , transforms , type } ) => { const materialDef = materials [ type ] ; if ( ! materialDef ) { console . error ( 'Can not hangle object type: ' + type , { vertices , indices , color , transforms , type , } ) ; return null ; } let material = materialDef . def ; if ( color ) { const [ r , g , b , opacity ] = color ; material = materialDef . material ( { color : new Color ( r , g , b ) , flatShading : true , opacity : opacity === void 0 ? 1 : opacity , transparent : opacity != 1 && opacity !== void 0 , } ) ; } const geo = new BufferGeometry ( ) ; geo . setAttribute ( 'position' , new BufferAttribute ( vertices , 3 ) ) ; let mesh ; switch ( type ) { case 'mesh' : geo . setIndex ( new BufferAttribute ( indices , 1 ) ) ; mesh = new Mesh ( geo , material ) ; break ; case 'line' : mesh = new Line ( geo , material ) ; break ; case 'lines' : mesh = new LineSegments ( geo , material ) ; break ; } if ( transforms ) mesh . applyMatrix4 ( { elements : transforms } ) ; return mesh ; } ) ; } let scriptWorker ; type ResolveFn = ( RenderResponse ) => void ; class WorkerHelper { callResolve : null | ResolveFn = null ; previousCode = '' ; resolver = ( response ) => { this . callResolve && this . callResolve ( response ) ; this . callResolve = null ; } ; render = ( code , parameters ) : Promise < RenderResponse > => { const response = new Promise ( ( resolve ) => { this . callResolve = resolve ; } ) ; if ( ! ( code && this . previousCode !== code ) ) { scriptWorker . postMessage ( { action : 'updateParams' , worker : 'script' , params : parameters , } ) ; } else { scriptWorker . postMessage ( { action : 'runScript' , worker : 'script' , script : code , params : parameters || { } , url : 'jscad_script' , } ) ; } this . previousCode = code ; return response ; } ; } const workerHelper = new WorkerHelper ( ) ; export const render = async ( { code , settings , } ) => { if ( ! scriptWorker ) { const baseURI = document . baseURI . toString ( ) ; scriptWorker = new TheWorker ( ) ; let parameterDefinitions = [ ] ; scriptWorker . addEventListener ( 'message' , ( { data } ) => { if ( data . action == 'parameterDefinitions' ) { parameterDefinitions = data . data ; } else if ( data . action == 'entities' ) { if ( data . error ) { workerHelper . resolver ( createUnhealthyResponse ( new Date ( ) , data . error ) ) ; } else { workerHelper . resolver ( createHealthyResponse ( { type : 'primitive-array' , data : CSGArray2R3fComponent ( data . entities ) , consoleMessage : data . scriptStats , date : new Date ( ) , customizerParams : jsCadToCadhubParams ( parameterDefinitions || [ ] ) , } ) ) ; } } } ) ; workerHelper . resolver ( null ) ; scriptWorker . postMessage ( { action : 'init' , baseURI , alias : [ ] } ) ; } return workerHelper . render ( code , settings . parameters ) ; } ; const jsCadController = { render , } ; export default jsCadController ;