294 lines
12 KiB
JavaScript
294 lines
12 KiB
JavaScript
class KeyframeView extends WindozDomContent {
|
|
|
|
constructor() {
|
|
super()
|
|
Object.assign(this, app.helpers.activeAttributes)
|
|
Object.assign(this, app.helpers.formBuilder)
|
|
}
|
|
|
|
DOMContentFocused(options) {
|
|
if(this.wasBlured){ // Avoid 2nd refesh on DomContentLoaded
|
|
//this.refreshyoustuff()
|
|
}
|
|
this.wasBlured = false
|
|
}
|
|
|
|
DOMContentBlured(options) { this.wasBlured = true }
|
|
|
|
async DOMContentLoaded(options) {
|
|
this.windowPrefsId = `editors.keyframeview`
|
|
this.models = options.models
|
|
const components = ui.eicfy(this.el)
|
|
this.setupTriggers(components)
|
|
this.setupRefs(components)
|
|
|
|
const [sprites, types] = await Promise.all([
|
|
this.models.agents.getSprites('Basic 3D'),
|
|
this.models.agents.getTypes('Test agents')
|
|
])
|
|
|
|
this.agentSprites = sprites
|
|
this.agentTypes = types
|
|
this.currentAgentType = null
|
|
|
|
//TODO from browser
|
|
this.currentKeyframe = { }
|
|
|
|
this.outputs.agentsSelector.fillOptions( this.agentTypes.map(item => {
|
|
return({ markup: `<i class="icon-${item.atp_hascode ? 'bug' : 'atom1'}"></i>${item.atp_name}`, value: item.atp_id})
|
|
}))
|
|
this.outputs.agentsSelector.addEventListener('change',this.onChangeAgent.bind(this))
|
|
|
|
this.agentPreview = new app.LoadedModules.AgentPreview(this.outputs.agentSampleCanvas, this.agentSprites)
|
|
this.onChangeAgent()
|
|
this.agentPreview.startRendering()
|
|
this.agentPreview.animation = true
|
|
|
|
this.models.keyframes.list('', null).then(data => data.payload).then(kflist => {
|
|
this.outputs.keyframesSelector.fillOptions(kflist.map(item => {
|
|
return({
|
|
markup: item.ekf_name,
|
|
value: item.ekf_uuid
|
|
})
|
|
}))
|
|
})
|
|
this.outputs.keyframesSelector.addEventListener('change',this.onChangeKeyframe.bind(this))
|
|
|
|
this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites)
|
|
this.kfArena.onclickAgent = this.onclickAgent.bind(this)
|
|
this.kfArena.startRendering()
|
|
|
|
this.outputs.btnAddAgent.disabled = true
|
|
this.outputs.btnRemoveAgent.disabled = true
|
|
this.outputs.btnSaveKF.disabled = true
|
|
this.outputs.kfName.addEventListener('keyup', this.updateKfButtons.bind(this))
|
|
this.currentlySelectedAid = null
|
|
}
|
|
|
|
async execCommand(event){
|
|
console.log('cmd:', this.outputs.commands)
|
|
if(this.outputs.commands.value.trim()=='\\help'){
|
|
this.outputs.results.innerHTML += await app.Assets.loadHtml({ name: 'help/KFconsoleHelp.html' })
|
|
} else if(this.outputs.commands.value.trim()=='\\clear'){
|
|
this.outputs.results.innerHTML = ''
|
|
} else {
|
|
this.outputs.results.innerHTML += await this.evalCmd(this.outputs.commands.value)
|
|
}
|
|
const lines = this.outputs.results.querySelectorAll('div.line')
|
|
if(lines.length > 100) {
|
|
for(let i=0; i<(lines.length-100); i++) lines[i].remove()
|
|
}
|
|
|
|
}
|
|
|
|
async evalCmd(code){
|
|
const api = {
|
|
newAgent: async (type, properties) => {
|
|
if(Array.from(this.outputs.agentsSelector.options).find(item => item.value==type)){
|
|
this.outputs.agentsSelector.value = type
|
|
await this.onChangeAgent()
|
|
const defaultValues = this.getFieldsValues('div[data-output="agentProperties"]')
|
|
return(await this.newAgent(type, { ...defaultValues, ...properties })) //TODO: deepMerge
|
|
} else {
|
|
throw(`Invalid agent type: ${type}`)
|
|
}
|
|
},
|
|
removeAgent: (aid) => {
|
|
|
|
},
|
|
updateAgent: (aid, properties) => {
|
|
|
|
},
|
|
}
|
|
try {
|
|
const fn = new Function(...Object.keys(api), `
|
|
return(
|
|
(async () => {
|
|
const logs = []
|
|
const log = (item) => { logs.push(item) }
|
|
${code}
|
|
return(logs)
|
|
})()
|
|
)
|
|
`)
|
|
|
|
const res = await fn(...Object.values(api))
|
|
return(
|
|
'<div class="line">'+
|
|
res.map(item => {
|
|
if(typeof(item) == 'object') return(JSON.stringify(item))
|
|
return(item)
|
|
}).join('</div><div class="line">')
|
|
+'</div>'
|
|
)
|
|
} catch (err) {
|
|
return(`<div class="error">${err.name}: ${err.message}</div>`)
|
|
}
|
|
}
|
|
|
|
async onChangeAgent(event){
|
|
if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value)
|
|
if(!this.outputs.agentsSelector.value) return
|
|
|
|
if(this.notUserChange) {
|
|
|
|
} else {
|
|
this.currentAgentType = await this.models.agents.getProperties(this.outputs.agentsSelector.value)
|
|
this.fillAgentProperties('', this.currentAgentType.atp_props)
|
|
// Deselect any on-scene selection
|
|
if(this.currentlySelectedAid){
|
|
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
|
|
}
|
|
this.currentlySelectedAid = null
|
|
}
|
|
}
|
|
|
|
async onChangeKeyframe(event){
|
|
if(!this.outputs.keyframesSelector.value) return
|
|
let kfData = await this.models.keyframes.getKeyframe(this.outputs.keyframesSelector.value).then(data => data.payload)
|
|
this.currentKeyframe = {
|
|
kfId: kfData.info.ekf_uuid,
|
|
kfName: kfData.info.ekf_name,
|
|
prevKfId: kfData.info.ekf_prev_uuid,
|
|
}
|
|
this.outputs.kfName.value = kfData.info.ekf_name
|
|
this.kfArena.reloadAgents(kfData.agents)
|
|
}
|
|
|
|
onclickAgent(obj3D){
|
|
const aid = obj3D.name
|
|
if(this.currentlySelectedAid == aid){ // Deselect
|
|
this.kfArena.clearHighlight3DObj(obj3D, this.kfArena.scene)
|
|
this.currentlySelectedAid = null
|
|
this.outputs.btnRemoveAgent.disabled = true
|
|
} else { // Select
|
|
if(this.currentlySelectedAid){
|
|
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
|
|
}
|
|
this.currentlySelectedAid = aid
|
|
this.outputs.btnRemoveAgent.disabled = false
|
|
if(this.kfArena.agents[aid]) {
|
|
this.kfArena.highlight3DObj(obj3D, this.kfArena.scene)
|
|
this.fillAgentProperties(aid, this.kfArena.agents[aid].props, this.kfArena.agents[aid].values)
|
|
this.notUserChange = true
|
|
this.outputs.agentsSelector.value = this.kfArena.agents[aid].type
|
|
this.notUserChange = false
|
|
}
|
|
}
|
|
this.updateKfButtons()
|
|
}
|
|
|
|
onAddAgent(event){
|
|
//TODO prevent collisions !
|
|
const AgentValues = this.getFieldsValues('div[data-output="agentProperties"]')
|
|
const aid = this.newAgent(this.outputs.agentsSelector.value, AgentValues)
|
|
this.output('agentId', `ID: ${aid}`)
|
|
this.updateKfButtons()
|
|
}
|
|
|
|
onRemoveAgent(event){
|
|
if(!this.currentlySelectedAid) return
|
|
this.kfArena.removeAgent(this.currentlySelectedAid)
|
|
}
|
|
|
|
newAgent(aType, AgentValues){
|
|
const aid = crypto.randomUUIDv7()
|
|
this.kfArena.addAgent(aType, aid, this.currentAgentType.atp_props , AgentValues)
|
|
return(aid)
|
|
}
|
|
|
|
|
|
updateKfButtons(){
|
|
if((Object.keys(this.kfArena.agents).length > 0) && (this.outputs.kfName.value.length > 5)) { this.outputs.btnSaveKF.disabled = false }
|
|
else { this.outputs.btnSaveKF.disabled = true }
|
|
}
|
|
|
|
onPropsChanged(evt, comp){
|
|
if(this.currentlySelectedAid && this.kfArena.agents[this.currentlySelectedAid]){
|
|
const AgentValues = this.getFieldsValues('div[data-output="agentProperties"]')
|
|
this.kfArena.agents[this.currentlySelectedAid].values = AgentValues
|
|
const val = Number.parseInt(comp.value, 10)
|
|
if((comp.name.startsWith('position.')) && (!Number.isNaN(val))){
|
|
this.kfArena.moveAgent(this.currentlySelectedAid, {
|
|
x: this.getFieldValue('div[data-output="agentProperties"]', 'position.x'),
|
|
y: this.getFieldValue('div[data-output="agentProperties"]', 'position.y'),
|
|
z: this.getFieldValue('div[data-output="agentProperties"]', 'position.z'),
|
|
})
|
|
} else if((comp.name.startsWith('speed.')) && (!Number.isNaN(val))){
|
|
this.kfArena.changeAgentSpeed(this.currentlySelectedAid, {
|
|
x: this.getFieldValue('div[data-output="agentProperties"]', 'speed.x'),
|
|
y: this.getFieldValue('div[data-output="agentProperties"]', 'speed.y'),
|
|
z: this.getFieldValue('div[data-output="agentProperties"]', 'speed.z'),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
fillAgentProperties(aid, agentProps, agentValues = {}){
|
|
this.outputs.agentProperties.innerHTML = `
|
|
<div data-output="agentId">ID: ${aid}</div>
|
|
`
|
|
this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, agentValues, 'Internal properties', this.onPropsChanged.bind(this)))
|
|
this.outputs.agentProperties.append(...this.fieldsFromJSON({
|
|
"position.x": {
|
|
label: "Position X",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
"position.y": {
|
|
label: "Position Y",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
"position.z": {
|
|
label: "Position Z",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
}, agentValues, 'Coordinates', this.onPropsChanged.bind(this)))
|
|
this.outputs.agentProperties.append(...this.fieldsFromJSON({
|
|
"speed.x": {
|
|
label: "Speed X",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
"speed.y": {
|
|
label: "Speed Y",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
"speed.z": {
|
|
label: "Speed Z",
|
|
type: "number",
|
|
default: "0"
|
|
},
|
|
}, agentValues, 'Speed vector', this.onPropsChanged.bind(this)))
|
|
this.outputs.btnAddAgent.disabled = false
|
|
this.setupRefs()
|
|
}
|
|
|
|
async onSaveKF(evt){
|
|
let result = { success: true }
|
|
if(!this.currentKeyframe.kfId){ // Create first (and get new kfId)
|
|
this.currentKeyframe.kfName = this.outputs.kfName.value
|
|
result = await this.models.keyframes.create(this.currentKeyframe)
|
|
this.currentKeyframe.kfId = result.payload.kfId
|
|
} else if(this.currentKeyframe.kfName != this.outputs.kfName.value){ //rename
|
|
this.currentKeyframe.kfName = this.outputs.kfName.value
|
|
result = await this.models.keyframes.rename(this.currentKeyframe)
|
|
}
|
|
|
|
if(result.success){
|
|
|
|
await this.models.keyframes.save(this.currentKeyframe.kfId, this.kfArena.agents)
|
|
this.outputs.btnSaveKF.disabled = true
|
|
ui.growl.append('Keyframe saved!','success',3000)
|
|
setTimeout(() => { this.outputs.btnSaveKF.disabled = false}, 3000)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
app.registerClass('KeyframeView', KeyframeView)
|
|
|