diff --git a/app/assets/styles/app.css b/app/assets/styles/app.css index a8d0dd9..acaa435 100755 --- a/app/assets/styles/app.css +++ b/app/assets/styles/app.css @@ -357,6 +357,12 @@ input{ border: none; } +button[eicbutton][rounded] { + min-height: 2em; + padding: 0; + color: #DDD; +} + /* Customizations to buildoz*/ bz-select > button{ background: linear-gradient( to bottom, #251, #372 15%, #483 50%, #372 85%, #251 ) !important; diff --git a/app/controllers/editors/EditorsController.json b/app/controllers/editors/EditorsController.json index dbe8de3..586ca59 100644 --- a/app/controllers/editors/EditorsController.json +++ b/app/controllers/editors/EditorsController.json @@ -23,7 +23,7 @@ "AgentsModel" ], "views": [ - {"view":"editors/KeyframeView", "dependencies": ["editors/modules/agentPreview.module"]} + {"view":"editors/KeyframeView", "dependencies": ["editors/modules/agentPreview.module", "editors/modules/kfArena.module"]} ], "controllerDependencies": [ "/helpers/basicDialogs", @@ -41,7 +41,8 @@ "html": [ { "id":"spaceViewSetting", "name": "spaceViewSetting.html"} ], - "json": [ + "json": [ + {"id":"arenaConfig", "name": "arena/arenaConfig1.json"} ] } } \ No newline at end of file diff --git a/app/views/editors/KeyframeView.html b/app/views/editors/KeyframeView.html index 00566ab..b39d307 100644 --- a/app/views/editors/KeyframeView.html +++ b/app/views/editors/KeyframeView.html @@ -10,12 +10,18 @@ } .kf-editor > article, .kf-editor > article header{ border-color: #473; } .kf-editor article.agent-preview header { padding:0; } - .kf-editor article.agent-preview canvas{ width:100%; aspect-ratio: 1 / 1;} + .kf-editor canvas[data-output="agentSampleCanvas"]{ width:100%; aspect-ratio: 1 / 1;} + .kf-editor canvas[data-output="kfArenaCanvas"]{ width:100%; height:100%; } .kf-editor article.agent-preview section, .kf-editor article.agent-properties section{ display: grid; grid-template-rows: auto 2em; height: 100%; - } + } + .kf-editor article.kfArena section{ + padding: 0; + height: 100%; + + } .kf-editor article.agent-preview section div.actions button{ color: #DDD; padding: 0 0 0 0; @@ -25,11 +31,11 @@ .kf-editor button[data-trigger="onRemoveAgent"] { background-color: #A00; } .kf-editor section[data-output="agentProperties"] label{ font-size: 0.9em; } .kf-editor section[data-output="agentProperties"] div.cols-2 { grid-template-columns: 4fr 3fr; } - +
-
+
@@ -37,9 +43,9 @@
-
+
- Arena +
@@ -52,7 +58,7 @@
- - + + diff --git a/app/views/editors/KeyframeView.js b/app/views/editors/KeyframeView.js index a2970db..2a92b2c 100644 --- a/app/views/editors/KeyframeView.js +++ b/app/views/editors/KeyframeView.js @@ -41,19 +41,31 @@ class KeyframeView extends WindozDomContent { this.agentPreview.startRendering() this.agentPreview.animation = true + this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites) + this.kfArena.startRendering() + + + this.outputs.btnAddAgent.disabled = true + this.outputs.btnRemoveAgent.disabled = true } - - async onChangeAgent(event){ if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value) if(!this.outputs.agentsSelector.value) return - console.log('onChangeAgent',this.outputs.agentsSelector.value) const agent = await this.models.agents.getProperties(this.outputs.agentsSelector.value) this.fillAgentProperties(agent.atp_props) } - fillAgentProperties(agentProps){ console.log('fillAgentProperties', agentProps) + onAddAgent(event){ + const aid = crypto.randomUUIDv7() + this.kfArena.addAgent(this.outputs.agentsSelector.value, aid, { + x: document.querySelector('[name="position.x"]').value, + y: document.querySelector('[name="position.y"]').value, + z: document.querySelector('[name="position.z"]').value, + }) + } + + fillAgentProperties(agentProps){ this.outputs.agentProperties.innerHTML='' this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, 'Internal properties')) this.outputs.agentProperties.append(...this.fieldsFromJSON({ @@ -90,8 +102,10 @@ class KeyframeView extends WindozDomContent { default: "0" }, }, 'Speed vector')) + this.outputs.btnAddAgent.disabled = false } } app.registerClass('KeyframeView', KeyframeView) + diff --git a/app/views/editors/modules/agentPreview.module.js b/app/views/editors/modules/agentPreview.module.js index 8693b07..279cae7 100644 --- a/app/views/editors/modules/agentPreview.module.js +++ b/app/views/editors/modules/agentPreview.module.js @@ -1,6 +1,4 @@ import * as THREE from '/app/thirdparty/Three/three.module.js' -import { OrbitControls } from '/app/thirdparty/Three/OrbitControls.module.js' -import * as TWEEN from '/app/thirdparty/Three/tween.module.js' export class AgentPreview{ diff --git a/app/views/editors/modules/kfArena.module.js b/app/views/editors/modules/kfArena.module.js new file mode 100644 index 0000000..4e931a0 --- /dev/null +++ b/app/views/editors/modules/kfArena.module.js @@ -0,0 +1,106 @@ +import * as THREE from '/app/thirdparty/Three/three.module.js' +import { OrbitControls } from '/app/thirdparty/Three/OrbitControls.module.js' +import * as TWEEN from '/app/thirdparty/Three/tween.module.js' + +export class kfArena{ + + constructor(canvasEl, agentSprites){ + Object.assign(this, app.helpers.helpers3D) + this.agentSprites = app.Assets.Store.json.agentSprites + this.canvasEl = canvasEl + this.agentSprites = agentSprites + this.renderer = null + this.mode='3D' + this.sceneSize = app.Assets.Store.json.arenaConfig.arenaSize + this.initScene() + } + + initScene(){ + // Scene + this.scene = new THREE.Scene() + + // Camera + this.camera = new THREE.PerspectiveCamera(75, this.canvasEl.clientWidth / this.canvasEl.clientHeight, 0.1, 1000) + this.camera.position.set(3, 3, 5) + this.camera.lookAt(0, 0, 0) + this.camera.layers.enable(1) + this.camera.layers.enable(2) + + // Lights + const light = new THREE.DirectionalLight(0xffffff, 1) + light.position.set(5, 5, 5) + light.intensity = 2 + this.scene.add(light) + this.scene.add(new THREE.AmbientLight(0xffffff, 0.4)) + + this.grid = new THREE.GridHelper(this.sceneSize.x, this.sceneSize.y, 0x8888AA, 0x8888AA) + this.grid.layers.set(1) + this.scene.add(this.grid) + + this.axes = new THREE.AxesHelper(this.sceneSize.x/2, this.sceneSize.y/2) + this.axes.layers.set(2) + this.scene.add(this.axes) + + this.renderer = new THREE.WebGLRenderer({ antialias: true, canvas: this.canvasEl }) + } + + startRendering(){ + this.addControls() + this.render() + } + + render() { + TWEEN.update() + if(this.resizeRendererToDisplaySize()) { + this.camera.aspect = this.renderer.domElement.clientWidth / this.canvasEl.clientHeight + this.camera.updateProjectionMatrix() + } + this.renderer.render(this.scene, this.camera) + requestAnimationFrame(this.render.bind(this)) + } + + + resizeRendererToDisplaySize() { + const width = this.canvasEl.clientWidth + const height = this.canvasEl.clientHeight + if (this.canvasEl.width !== width || this.canvasEl.height !== height) { + this.renderer.setSize(width, height, false) + return true + } + return false + } + + addControls(){ + this.controls = new OrbitControls(this.camera, this.canvasEl) + if(this.mode=='2D'){ + this.controls.maxPolarAngle = 0 // Math.PI / 2 + this.controls.minPolarAngle = 0 // Math.PI / 2 + } else if(this.mode=='3D'){ + } + + this.controls.mouseButtons = { + LEFT: THREE.MOUSE.ROTATE, // keep orbit on left + MIDDLE: THREE.MOUSE.PAN, // pan with middle-click + RIGHT: THREE.MOUSE.DOLLY // zoom with right-click + } + } + + addAgent(typeId, aid, position){ + const agentSprite = this.agentSprites.find(item => item.atp_id==typeId) + if(!agentSprite) return + const agentObj = this.agentFromJSON(aid, agentSprite.asp_3d) + + agentObj.position.set(position.x, position.z, position.y ) + this.scene.add(agentObj) + } + + removeAgent(id){ + //find obj by id + //this.scene.remove(this.currentAgentObj) + } +} + +// Make this module available to common JS +if(!app.LoadedModules) app.LoadedModules = {} +app.LoadedModules.kfArena = kfArena + diff --git a/core/Sparc-core-1.0.js b/core/Sparc-core-1.0.js index 3e3189a..eb89309 100755 --- a/core/Sparc-core-1.0.js +++ b/core/Sparc-core-1.0.js @@ -539,7 +539,8 @@ class Loader { */ if(typeof(crypto.randomUUID)!='function'){ - crypto.randomUUID = () => { + crypto.randomUUID = () => { + console.log('Polyfilled crypt !') var buf = new Uint8Array(14); crypto.getRandomValues(buf); var uuid = Array.from(buf, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join(''); @@ -550,8 +551,22 @@ if(typeof(crypto.randomUUID)!='function'){ uuid.substring(18,4) + '-' + uuid.substring(22) ); - } + } } +crypto.randomUUIDv7 = () => { + const now = BigInt(Date.now()) + const time = now << 16n | BigInt(crypto.getRandomValues(new Uint16Array(1))[0]) + const bytes = new Uint8Array(16) + new DataView(bytes.buffer).setBigUint64(0, time) + crypto.getRandomValues(bytes.subarray(8)) + bytes[6] = (bytes[6] & 0x0f) | 0x70 // version 7 + bytes[8] = (bytes[8] & 0x3f) | 0x80 // variant + return [...bytes].map((b,i) => + (b + 0x100).toString(16).substring(1) + ([3,5,7,9].includes(i) ? '-' : '') + ).join('') +} + + if(typeof(typeof(Promise.allSettled))!='function'){ Promise.allSettled = ((promises) => Promise.all(