From eea328822681a43ae06263399281c388237af832 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Thu, 26 Oct 2023 09:20:14 +0200 Subject: [PATCH] WIP: throttle attempt (has console.log for inspection) (#65) I have implemented throttling of parameter change execution. communication with worker was also changed so entites are not sent as event, but as a response ro runMain and runScript. This allows to wrap those calls to Promise neatly, and also use await. it is supposed to skip param changes that arrive during worker execution but make sure last state of params is rendered reliably ![image](https://github.com/hrgdavor/jscadui/assets/2480762/7842c965-3293-4817-9ad0-7cd5e04877ca) I loaded the script http://3d.hrg.hr/jscad/three/examples/parametric_butt_hinge_3.7.js and changed `view options->throw angle` rapidly --- apps/engine-test/main.js | 7 ++-- ...{bundle.jscad.io.js => bundle.jscad_io.js} | 0 apps/engine-test/src_bundle/bundle.threejs.js | 32 ++++++++++++++++++- apps/jscad-web/README.md | 18 +++++++++++ apps/jscad-web/main.js | 22 +++++++++++-- packages/postmessage/index.js | 2 +- packages/themes/tsconfig.json | 2 +- packages/worker/worker.js | 20 ++++++------ 8 files changed, 86 insertions(+), 17 deletions(-) rename apps/engine-test/src_bundle/{bundle.jscad.io.js => bundle.jscad_io.js} (100%) diff --git a/apps/engine-test/main.js b/apps/engine-test/main.js index ab54fa3..ad1e47d 100644 --- a/apps/engine-test/main.js +++ b/apps/engine-test/main.js @@ -223,14 +223,17 @@ sendCmdAndSpin('init', { }) }) -const paramChangeCallback = params => { +const paramChangeCallback = async params => { console.log('params changed', params) - sendCmdAndSpin('runMain', { params }) + let result = await sendCmdAndSpin('runMain', { params }) + handlers.entities(result) } const runScript = async ({script, url = './index.js', base, root}) => { const result = await sendCmdAndSpin('runScript', { script, url, base, root }) + console.log('result', result) genParams({ target: byId('paramsDiv'), params: result.def || {}, callback: paramChangeCallback }) + handlers.entities(result) } let sw diff --git a/apps/engine-test/src_bundle/bundle.jscad.io.js b/apps/engine-test/src_bundle/bundle.jscad_io.js similarity index 100% rename from apps/engine-test/src_bundle/bundle.jscad.io.js rename to apps/engine-test/src_bundle/bundle.jscad_io.js diff --git a/apps/engine-test/src_bundle/bundle.threejs.js b/apps/engine-test/src_bundle/bundle.threejs.js index 00f04b2..4c98737 100644 --- a/apps/engine-test/src_bundle/bundle.threejs.js +++ b/apps/engine-test/src_bundle/bundle.threejs.js @@ -1 +1,31 @@ -export * from '@jscadui/render-threejs/bundle.example.js' +// based on '@jscadui/render-threejs/bundle.example.js' + +// export { StereoCamera } from 'three/src/cameras/StereoCamera.js'; +export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js'; +export { Scene } from 'three/src/scenes/Scene.js'; +export { Color } from 'three/src/math/Color.js'; +export { AmbientLight } from 'three/src/lights/AmbientLight.js'; +export { HemisphereLight } from 'three/src/lights/HemisphereLight.js'; +export { DirectionalLight } from 'three/src/lights/DirectionalLight.js'; +// export { PlaneGeometry } from 'three/src/geometries/PlaneGeometry'; +export { EdgesGeometry } from 'three/src/geometries/EdgesGeometry.js'; +export { MeshPhongMaterial } from 'three/src/materials/MeshPhongMaterial.js'; +export { LineBasicMaterial } from 'three/src/materials/LineBasicMaterial.js'; +// export { MeshBasicMaterial } from 'three/src/materials/MeshBasicMaterial.js'; +export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js'; +export { Mesh } from 'three/src/objects/Mesh.js'; +export { Object3D } from 'three/src/core/Object3D.js'; +export { Raycaster } from 'three/src/core/Raycaster.js'; +export { InstancedBufferGeometry } from 'three/src/core/InstancedBufferGeometry.js'; +export { BufferGeometry } from 'three/src/core/BufferGeometry.js'; +export * from 'three/src/core/BufferAttribute.js'; +export { InstancedMesh } from 'three/src/objects/InstancedMesh.js'; +export { LineSegments } from 'three/src/objects/LineSegments.js'; +export { Group } from 'three/src/objects/Group.js'; +export { Line } from 'three/src/objects/Line.js'; +export { Matrix4 } from 'three/src/math/Matrix4.js'; +export { Vector3 } from 'three/src/math/Vector3.js'; +// export { Euler } from 'three/src/math/Euler.js'; +// export { Texture } from 'three/src/textures/Texture.js'; +// export * from 'three/src/constants.js'; + diff --git a/apps/jscad-web/README.md b/apps/jscad-web/README.md index 17c7efd..25b5550 100644 --- a/apps/jscad-web/README.md +++ b/apps/jscad-web/README.md @@ -27,3 +27,21 @@ To start the production server run: ``` npm run serve ``` + +# using url to load external script and CORS + +If you want to share a script from your website you should setup CORS, and make sure to use HTTPS! + +if you do not setup CORS [jscad.app](https://jscad.app) can fallback to `/remote` to download the script, but this workaround may not be available forever (such enpoint could be abused to hide IP for attacks). + + +For hostings (that are uaually cheap and abundant) on CPanel adding .htaccess to your folder should work. +``` + +Header set Access-Control-Allow-Origin "*" +Header set Access-Control-Allow-Headers "origin, x-requested-with, content-type" +Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS" + +``` + +If you are using github you should be fine, as gists and github pages have those CORS headers. diff --git a/apps/jscad-web/main.js b/apps/jscad-web/main.js index 7023180..b968f4f 100644 --- a/apps/jscad-web/main.js +++ b/apps/jscad-web/main.js @@ -175,15 +175,31 @@ sendCmdAndSpin('init', { } }) -const paramChangeCallback = params => { - console.log('params changed', params) - sendCmdAndSpin('runMain', { params }) +let working +let lastParams +const paramChangeCallback = async params => { + if(!working){ + lastParams = null + }else{ + lastParams = params + return + } + working = true + let result + try{ + result = await sendCmdAndSpin('runMain', { params }) + } finally{ + working = false + } + handlers.entities(result) + if(lastParams && lastParams != params) paramChangeCallback(lastParams) } const runScript = async ({ script, url = './index.js', base, root }) => { loadDefault = false // don't load default model if something else was loaded const result = await sendCmdAndSpin('runScript', { script, url, base, root }) genParams({ target: byId('paramsDiv'), params: result.def || {}, callback: paramChangeCallback }) + handlers.entities(result) } const loadExample = source => { diff --git a/packages/postmessage/index.js b/packages/postmessage/index.js index ed8f0c8..757ad59 100644 --- a/packages/postmessage/index.js +++ b/packages/postmessage/index.js @@ -1,7 +1,7 @@ let seq = 1 let reqMap = new Map() const RESPONSE = '__RESPONSE__' -const TRANSFERABLE = '__transferable' +const TRANSFERABLE = Symbol.for('__transferable__') export const withTransferable = (params,trans)=>{ params[TRANSFERABLE] = trans diff --git a/packages/themes/tsconfig.json b/packages/themes/tsconfig.json index babe925..81628c4 100644 --- a/packages/themes/tsconfig.json +++ b/packages/themes/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "tsconfig/themes.json", + "extends": "../tsconfig/themes.json", "include": ["."], "exclude": ["dist", "build", "node_modules"] } diff --git a/packages/worker/worker.js b/packages/worker/worker.js index 108679e..ce035f0 100644 --- a/packages/worker/worker.js +++ b/packages/worker/worker.js @@ -39,9 +39,10 @@ export const init = params => { console.log('init alias', alias, 'bundles',bundles) userInstances = params.userInstances } -let entities = [], - solids = [] + +solids = [] export async function runMain({ params } = {}) { + let entities = [] const transferable = [] if (!main) throw new Error('no main function exported') @@ -60,8 +61,8 @@ export async function runMain({ params } = {}) { entities = JscadToCommon.prepare(solids, transferable, userInstances) entities = entities.all // entities = [...entities.lines, ...entities.line, ...entities.instance] - client.sendNotify('entities', { entities, solidsTime, entitiesTime: Date.now() - time }, transferable) - entities = [] // we lose access to bytearray data, it is transfered, and on our side it shows length=0 + // client.sendNotify('entities', { entities, solidsTime, entitiesTime: Date.now() - time }, transferable) + return withTransferable({entities}, transferable) } // https://stackoverflow.com/questions/52086611/regex-for-matching-js-import-statements @@ -79,23 +80,24 @@ const runScript = async ({ script, url, base=globalBase, root=base }) => { const fromSource = getParameterDefinitionsFromSource(script) def = combineParameterDefinitions(fromSource, await scriptModule.getParameterDefinitions?.()) main = scriptModule.main - await runMain({ params: extractDefaults(def) }) - return {def} + let out = await runMain({ params: extractDefaults(def) }) + out.def = def + return out } // TODO remove, or move to another package, along with exportStlText // this is interesting in regards to exporting to stl, and 3mf which actually need vertex data, -// and not jcad geometry polygons. So it will be interesting to see if main can give back transferable buffers +// and not jcad geometry polygons. So it will be interesting to can give back transferable buffers // instead of re-running conversion. or move export to main thread where the data already is, as it is needed for rendering const exportData = async (params) => { - if(self.exportData) return self.exportData(params, solids, entities) + if(self.exportData) return self.exportData(params) const { format } = params // todo check if it is ok to give back transferables after webgl has used the buffers // then we would not need to clone the data // other option is to clone data before sending transferable JscadToCommon.clearCache() - if (solids.length && !entities.length) entities = JscadToCommon(solids, [], false) + let entities = JscadToCommon(solids, [], false) const arr = exportStlText(entities) data = [await new Blob(arr).arrayBuffer()]