Skip to content

Commit

Permalink
WIP: throttle attempt (has console.log for inspection) (#65)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hrgdavor authored Oct 26, 2023
1 parent 4e87351 commit eea3288
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 17 deletions.
7 changes: 5 additions & 2 deletions apps/engine-test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 31 additions & 1 deletion apps/engine-test/src_bundle/bundle.threejs.js
Original file line number Diff line number Diff line change
@@ -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';

18 changes: 18 additions & 0 deletions apps/jscad-web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
```
<IfModule mod_headers.c>
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"
</IfModule>
```

If you are using github you should be fine, as gists and github pages have those CORS headers.
22 changes: 19 additions & 3 deletions apps/jscad-web/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
2 changes: 1 addition & 1 deletion packages/postmessage/index.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/themes/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "tsconfig/themes.json",
"extends": "../tsconfig/themes.json",
"include": ["."],
"exclude": ["dist", "build", "node_modules"]
}
Expand Down
20 changes: 11 additions & 9 deletions packages/worker/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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
Expand All @@ -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()]
Expand Down

0 comments on commit eea3288

Please sign in to comment.