From 9eb14f06687900949230eac6aefc470523927e2c Mon Sep 17 00:00:00 2001 From: goynov Date: Mon, 17 Mar 2025 19:49:41 +0200 Subject: [PATCH] presentation --- backend/app/bl/GameObjectsManager.js | 16 +++- src/components/AssetPreview.vue | 82 +++++++++++++++++++ src/components/SceneDesigner/GameObject.vue | 6 +- src/components/SceneDesigner/Scene.vue | 11 +-- .../SceneDesigner/SceneDesigner.vue | 43 ++++++---- src/components/SceneDesigner/Task.vue | 20 +++-- src/pages/game-objects/[[id]].vue | 68 ++------------- src/pages/game-objects/list.vue | 19 ++++- src/pages/scenarios/[[id]].vue | 35 ++++---- src/plugins/lang.js | 4 + src/plugins/params.js | 24 ++++-- src/plugins/vuetify.js | 3 + src/styles/style.scss | 4 + 13 files changed, 218 insertions(+), 117 deletions(-) create mode 100644 src/components/AssetPreview.vue diff --git a/backend/app/bl/GameObjectsManager.js b/backend/app/bl/GameObjectsManager.js index 2111bab..e1b3406 100644 --- a/backend/app/bl/GameObjectsManager.js +++ b/backend/app/bl/GameObjectsManager.js @@ -2,6 +2,10 @@ import decompress from "decompress"; import sharp from 'sharp'; sharp.cache({ files : 0 }); +import util from 'node:util'; +import { execFile as npExecFile } from 'child_process'; +const execFile = util.promisify(npExecFile); + import fs from 'fs'; import path from 'path'; @@ -99,7 +103,7 @@ class GameObjectsManager{ }else{ object.asset.type = 'single'; await fs.promises.copyFile(src, def + ext); - if (['.jpg', '.png', '.webp'].includes(ext)){ + if (['.jpg', '.png', '.webp', '.mp4', '.avi', '.webv'].includes(ext)){ await this.addThumb(object, src); } } @@ -111,8 +115,16 @@ class GameObjectsManager{ * @param {File} thumbSrc A thumbnail, представително изображение */ this.addThumb = async function(object, thumbSrc){ + let ext = path.extname(object.asset.ofn).toLowerCase(); let dest = `${config.fs.repo}/thumb/${object.id}.webp`; - await sharp(thumbSrc).resize({height: 250}).toFile(dest); + if (['.jpg', '.png', '.webp'].includes(ext)){ + await sharp(thumbSrc).resize({height: 250}).toFile(dest); + }else if (['.mp4', '.avi', '.webv'].includes(ext)){ + let frame = 1; + await execFile('ffmpeg', [ + '-i', thumbSrc, '-vf', `select=eq(n\\,${frame}),scale=-2:300`, + '-vframes', 1, '-f', 'image2', '-y', dest]); + } object.asset.thumb = `${object.id}.webp`; } diff --git a/src/components/AssetPreview.vue b/src/components/AssetPreview.vue new file mode 100644 index 0000000..14e6b67 --- /dev/null +++ b/src/components/AssetPreview.vue @@ -0,0 +1,82 @@ + + + \ No newline at end of file diff --git a/src/components/SceneDesigner/GameObject.vue b/src/components/SceneDesigner/GameObject.vue index de78298..c0fd22c 100644 --- a/src/components/SceneDesigner/GameObject.vue +++ b/src/components/SceneDesigner/GameObject.vue @@ -3,9 +3,10 @@ + {{ modelValue.title }} - + @@ -46,7 +48,7 @@ export default { modifiers: ['x1', 'y1'], methods:{ intersect(v){ - return Utils.intersectLineRect(this.vd, v); + return Utils.intersectPointRect([this.vd.x1, this.vd.y1], v); }, assignGameObject(e){ this.modelValue.go = e.id; diff --git a/src/components/SceneDesigner/Scene.vue b/src/components/SceneDesigner/Scene.vue index 88d3643..af5f1de 100644 --- a/src/components/SceneDesigner/Scene.vue +++ b/src/components/SceneDesigner/Scene.vue @@ -2,10 +2,11 @@ + {{ modelValue.title }} - - + + @@ -13,8 +14,8 @@ + - @@ -48,9 +49,9 @@ export default { modifiers: ['x1', 'y1'], methods:{ intersect(v){ - return Utils.intersectLineRect(this.vd, v); + return Utils.intersectPointRect([this.vd.x1, this.vd.y1], v); }, - assignGameObject(e){ + assignEnvironment(e){ this.modelValue.environment = e.id; if (this.modelValue.id == this.modelValue.title){ this.modelValue.title = e.name diff --git a/src/components/SceneDesigner/SceneDesigner.vue b/src/components/SceneDesigner/SceneDesigner.vue index 8803923..4dd06e6 100644 --- a/src/components/SceneDesigner/SceneDesigner.vue +++ b/src/components/SceneDesigner/SceneDesigner.vue @@ -26,11 +26,22 @@ - + + + + + + :key="i" :title="item.data.title" :value="item" :style="`padding-left:${item.__level}rem`" + v-show="!item.__parent || item.__parent.vd.expanded" :color="[0,'secondary', 'primary', 'success'][item.__level]"> @@ -98,7 +102,9 @@ export default { assetSelector: { active: false, type: 'Scene' - } + }, + dialog: false, + expandDrawer: false } }, mounted(){ @@ -277,12 +283,11 @@ export default { id = `${this.components[this.mode].name}-${nid++}` }while (this.flatItems.find(i=>i.data.id == id)); - let targetContainer = this.selectedItem[0]?.data; //this.items; - if (targetContainer){ + let targetContainer = this.items; + if (this.mode != 'Scene'){ + targetContainer = this.selectedItem[0]?.data; //this.items; targetContainer.items = targetContainer.items || []; targetContainer = targetContainer.items; - }else{ - targetContainer = this.items } targetContainer.push({ //__type: this.mode, @@ -337,7 +342,7 @@ export default { }, select(){ let r = Utils.adjustMinMax(this.selector); - this.selectedItem = this.flatItems.filter(i=>this.$refs['svg-'+i.id][0].intersect(r)); + this.selectedItem = this.flatItems.filter(i=>this.$refs['sc-'+i.__path][0].intersect(r)); }, resize(){ let r = this.$refs.svgContainer; @@ -384,11 +389,17 @@ export default { stroke-dasharray: 0 calc(8 * var(--svg-scale)) 0; } } + text { + text-anchor: middle; + fill:rgb(var(--v-theme-on-surface)); + stroke-width: 0;//calc( .1px * var(--svg-scale) );; + } + background-color: rgba(128,128,128,.05); } overflow: hidden; width: 100%; max-width: 100vw; - height: 95vh; + height: calc(100vh - 244px); &.pan { cursor: grab; } diff --git a/src/components/SceneDesigner/Task.vue b/src/components/SceneDesigner/Task.vue index 4b3b757..f622d30 100644 --- a/src/components/SceneDesigner/Task.vue +++ b/src/components/SceneDesigner/Task.vue @@ -3,18 +3,20 @@ - + + {{ modelValue.title }} - + + - + @@ -47,7 +49,13 @@ export default { modifiers: ['x1', 'y1'], methods:{ intersect(v){ - return Utils.intersectLineRect(this.vd, v); + return Utils.intersectPointRect([this.vd.x1, this.vd.y1], v); + }, + assignTaskIntro(e){ + this.modelValue.intro = e.id; + if (this.modelValue.id == this.modelValue.title){ + this.modelValue.title = e.name + } } } } diff --git a/src/pages/game-objects/[[id]].vue b/src/pages/game-objects/[[id]].vue index a5e8658..649a825 100644 --- a/src/pages/game-objects/[[id]].vue +++ b/src/pages/game-objects/[[id]].vue @@ -2,6 +2,7 @@ + @@ -18,17 +19,7 @@ -
-
- - - - {{ a.name }} - - - -
- + {{ $l.captureThumbnail }} @@ -38,8 +29,6 @@