import { defineStore } from "pinia"; import { computed, ref, watch } from "vue"; import { MaterialEditor } from "../common/MaterialEditor"; import { Database, ObjectId, PhysicalMaterialRecord, TextureTableRecord } from "webcad_ue4_api"; import { LoadImageFromUrl } from "../helpers/helper.imageLoader"; import { Texture } from "three"; import { materialRenderer } from "../common/MaterialRenderer"; import { ImgsUrl, MaterialUrls } from "../api/Api"; import { Post, PostJson, RequestStatus } from "../api/Request"; import { MaterialOut } from "../common/MaterialSerializer"; import { DeflateAsync } from "../helpers/helper.compression"; export const useScene = defineStore('scene', () => { let _editor: MaterialEditor; const _currGeometry = ref('球'); const _currTexture = ref(); const CurrGeometry = computed({ get: () => _currGeometry.value, set: (val: string) => ChangeGeometry(val) }) const CurrTexture = computed(() => _currTexture.value); const Geometries = ref([]); const Material = ref(new PhysicalMaterialRecord()); function Initial(canvas: HTMLElement) { if (_editor) { console.warn("SceneStore has already been initialized"); return; } // 为Material配置一个ObjectId,否则其无法被序列化 Material.value.objectId = new ObjectId(undefined, undefined); _editor = MaterialEditor.GetInstance(); Geometries.value = Array.from(_editor.Geometrys.keys()); _currGeometry.value = _editor.CurGeometryName; _editor.SetViewer(canvas); _editor.setMaterial((Material.value) as PhysicalMaterialRecord); const view = _editor.Viewer; window.onresize = () => { view.OnSize(canvas.clientWidth, canvas.clientHeight); view.UpdateRender(); } } function ChangeGeometry(geoName: string) { _currGeometry.value = geoName; let geo = _editor.Geometrys.get(_currGeometry.value); if (geo) { _editor.ShowMesh.geometry = geo; _editor.Viewer.UpdateRender(); } } function Update() { _editor.Viewer.UpdateRender(); } async function UpdateMaterialAsync() { await Material.value.Update(); await _editor.Update(); Update(); } async function ChangeTextureAsync(url: string) { const record = new TextureTableRecord(); record.objectId = new ObjectId(undefined, record); const img = await LoadImageFromUrl(url); _currTexture.value = record['texture'] as Texture; _currTexture.value.image = img; Material.value.map = record.Id; _currTexture.value.needsUpdate = true; await UpdateMaterialAsync(); } function UpdateTexture(adjustment: TextureAdjustment) { const texture = _currTexture.value; texture.wrapS = adjustment.wrapS; texture.wrapT = adjustment.wrapT; texture.anisotropy = 16; texture.rotation = adjustment.rotation; texture.repeat.set(adjustment.repeatX, adjustment.repeatY); texture.offset.set(adjustment.moveX, adjustment.moveY); texture.needsUpdate = true; Update(); } interface UploadMaterialRequest { dirId: string; materialName: string; } async function UploadMaterialAsync(request: UploadMaterialRequest) { const logoPath = await HandleUpdateLogo(); const matJson = MaterialOut(Material.value as PhysicalMaterialRecord); const data = await PostJson(MaterialUrls.create, { dir_id: request, name: request.materialName, logo: logoPath, // jsonString -> Deflate -> BinaryString -> Base64 file: btoa(String.fromCharCode(...await DeflateAsync(matJson))), zip_type: 'gzip', }); if (data.err_code !== RequestStatus.Ok) { throw new Error(data.err_msg); } } async function HandleUpdateLogo() { const blob = await materialRenderer.getBlob(Material.value.Material); const file = new File([blob], "blob.png", { type: blob.type }); const formData = new FormData(); formData.append("file", file); let data = await Post(ImgsUrl.logo, formData); let logoPath = ""; if (data.err_code === RequestStatus.Ok) { logoPath = data.images.path; } return logoPath; } return { CurrGeometry, Geometries, Material, Initial, Update, UpdateMaterialAsync, ChangeTextureAsync, UpdateTexture, UploadMaterialAsync, }; }); export type TextureAdjustment = { wrapS: number, wrapT: number, rotation: number, repeatX: number, repeatY: number, moveX: number, moveY: number }