修复材质加载与导出

This commit is contained in:
xief
2025-05-27 16:54:25 +08:00
parent a1a541fff0
commit 16fac2ab19
8 changed files with 50 additions and 197 deletions

View File

@@ -1,4 +1,4 @@
import { CADFactory, CADFiler, CADObject, Database, DuplicateRecordCloning, Factory, LayerNode, ObjectId, PhysicalMaterialRecord } from "webcad_ue4_api";
import { CADFiler, CADObject, Database, DuplicateRecordCloning, Factory, LayerNode, ObjectId, PhysicalMaterialRecord } from "webcad_ue4_api";
// TODO: Danger: 注意入侵性代码
// 疑似是WebCAD中的漏洞当传入new Database()时,

View File

@@ -6,12 +6,15 @@
<legend>DEBUG</legend>
<label>上传路径ID</label>
<input v-model="materialInfo.dirId" type="text" placeholder="材质路径ID" />
<label>配置JSON</label>
<input v-model="materialInfo.inputText" type="text" />
<button class="btn-success" style="min-width: 110px;" @click="loadData">加载</button>
</fieldset>
<label>材质名</label>
<input v-model.trim="materialInfo.materialName" type="text" placeholder="材质名" />
<CfFlex gap="1em" v-if="debugMode">
<button class="btn-success" style="min-width: 110px;" @click="HandleUpload">上传</button>
<button class="btn-success" style="min-width: 110px;" @click="HandleUpload">保存</button>
<button class="btn-danger" style="min-width: 110px;" @click="HandleCancel">取消</button>
</CfFlex>
</div>
@@ -111,8 +114,8 @@ import { storeToRefs } from "pinia";
import CfFlex from "./CfFlex.vue";
import { DirectoryId } from "../api/Request";
import { IsNullOrWhitespace } from "../helpers/helper.string";
import { DeflateAsync } from "../helpers/helper.compression";
import { ToDeflatedBase64 } from "../helpers/helper.material";
import { FromDeflateBase64, ToDeflatedBase64 } from "../helpers/helper.material";
import { MaterialIn } from "../common/MaterialSerializer";
export interface MaterialRequest {
/** 材质名 */
@@ -133,7 +136,7 @@ const emits = defineEmits<{
(e: 'submit', data: MaterialRequest): void;
}>();
const debugMode = ref(false);
const debugMode = ref(true);
const { CurrGeometry, Geometries, Material } = storeToRefs(scene);
const enableTexture = ref(Material.value.useMap);
const _textureSrc = ref(props.textureSrc);
@@ -155,7 +158,8 @@ const model = reactive({
});
const materialInfo = reactive({
dirId: DirectoryId.MaterialDir, // 正常来说是2
materialName: '材质1'
materialName: '材质1',
inputText:'',
});
onMounted(() => {
@@ -220,6 +224,14 @@ async function EnableTexture(enable: boolean) {
await scene.UpdateMaterialAsync();
}
async function loadData() {
if(!materialInfo.inputText) return;
const json = JSON.parse(materialInfo.inputText);
const cadFile = FromDeflateBase64(json.file);
MaterialIn(JSON.parse(cadFile));
}
async function HandleUpload() {
try {
if (IsNullOrWhitespace(materialInfo.materialName)) {
@@ -250,6 +262,7 @@ defineExpose({
Cancel: HandleCancel
})
</script>
<style scoped>

View File

@@ -1,155 +0,0 @@
import * as fflate from 'fflate'
/**
* 使用deflate算法压缩文件
* @param data
*/
export function Deflate(data: Uint8Array | string): Uint8Array {
if (typeof data === 'string')
data = StrToU8(data);
return fflate.deflateSync(data);
}
/**
* 异步地使用deflate算法压缩文件
* @param data
*/
export function DeflateAsync(data: Uint8Array | string): Promise<Uint8Array> {
if (typeof data === 'string')
data = StrToU8(data);
return new Promise<Uint8Array>((resolve, reject) => {
const termiante = fflate.deflate(data as Uint8Array, (err, result) => {
if (err)
reject(err.message);
else
resolve(result);
})
})
}
/**
* 使用Zlib压缩文件
* @param data
*/
export function Zlib(data: Uint8Array | string): Uint8Array {
if (typeof data === "string")
data = fflate.strToU8(data);
return fflate.zlibSync(data);
}
/**
* 异步地使用Zlib压缩文件
* @param data
*/
export async function ZlibAsync(data: Uint8Array | string): Promise<Uint8Array> {
if (typeof data === 'string')
data = StrToU8(data);
return new Promise<Uint8Array>((resolve, reject) => {
const terminate = fflate.zlib(data as Uint8Array, (err, result) => {
if (err)
reject(err.message);
else
resolve(result);
});
})
}
/**
* 创建zip文件
* @param data Zip格式对象
*/
export function Zip(data: fflate.Zippable): Uint8Array {
return fflate.zipSync(data);
}
/**
* 异步地创建zip文件
* @param data Zip格式对象
*/
export async function ZipAsync(data: fflate.Zippable): Promise<Uint8Array> {
return new Promise<Uint8Array>((resolve, reject) => {
const terminate = fflate.zip(data, (err, result) => {
if (err)
reject(err.message);
else
resolve(result);
});
});
}
/**
* 解压Zip文件
* @param data
*/
export function Unzip(data: Uint8Array): fflate.Unzipped {
return fflate.unzipSync(data);
}
/**
* 异步地解压Zip文件
* @param data
*/
export function UnzipAsync(data: Uint8Array): Promise<fflate.Unzipped> {
return new Promise<fflate.Unzipped>((resolve, reject) => {
const terminate = fflate.unzip(data, (err, result) => {
if (err)
reject(err.message);
else
resolve(result);
})
});
}
/**
* 解压缩文件支持GZipZlib或DEFLATE数据
* @param data
*/
export function Decompress(data: Uint8Array): string | undefined {
// decompressSync 存在eof问题
let stringData: string | undefined = undefined;
const utfDecode = new fflate.DecodeUTF8((data) => {
stringData = data;
});
const dcmpStrm = new fflate.Decompress((chunk, final) => {
utfDecode.push(chunk, final);
});
try {
dcmpStrm.push(data);
} catch (error) {
console.log(error)
}
return stringData;
}
/**
* 异步地解压缩文件支持GZipZlib或DEFLATE数据
* @param data
*/
export async function DecompressAsync(data: Uint8Array, size: number | undefined = undefined): Promise<Uint8Array> {
return new Promise<Uint8Array>((resolve, reject) => {
const terminate = fflate.decompress(data, { size: size }, (err, result) => {
if (err)
reject(err.message);
else
resolve(result);
});
})
}
/**
* 将字符串转换为8位无符号整型数组
* @param str
*/
export function StrToU8(str: string): Uint8Array {
return fflate.strToU8(str);
}
/**
* 将8位无符号整形数组转换为字符串
* @param u8arr
*/
export function U8ToStr(u8arr: Uint8Array): string {
return fflate.strFromU8(u8arr);
}

View File

@@ -1,9 +1,10 @@
import Pako from "pako";
import { Decompress, DecompressAsync, Deflate, DeflateAsync, StrToU8, U8ToStr } from "./helper.compression";
export function ToDeflatedBase64(materialJson: string)
{
return btoa(String.fromCharCode(...Deflate(materialJson)))
// return btoa(String.fromCharCode(...Deflate(materialJson)))
const bin = Pako.deflate(materialJson,{to:"string"});
return btoa(bin);
}
export function FromDeflateBase64(base64: string) {

View File

@@ -6,8 +6,8 @@ import { createPinia, disposePinia } from 'pinia';
import { ConfigureLibOutput, type LibOutputConfig } from './libOutputConfig';
import { useEvent } from '../stores/eventStore';
import { useScene, useSceneRaw } from '../stores/sceneStore';
import { DeflateAsync } from '../helpers/helper.compression';
import { CADFactory, Factory, LayerNode } from 'webcad_ue4_api';
import { CADFactory, LayerNode, PhysicalMaterialRecord, TextureTableRecord } from 'webcad_ue4_api';
import { ToDeflatedBase64 } from '../helpers/helper.material';
let app: VueApp<Element> = undefined;
@@ -16,15 +16,17 @@ let app: VueApp<Element> = undefined;
* @param element 要挂载的HTML元素
* @param options 程序配置
*/
export function Mount(element: Element, options: Partial<LibOutputConfig>) {
ConfigureLibOutput(options);
export function Mount(element: string | Element, options?: Partial<LibOutputConfig>) {
options && ConfigureLibOutput(options);
const pinia = createPinia();
// TODO: Warn: 有BUG部分实体的构造函数名带_1后缀原因未知这会导致CADFactory在创建实体时找不到注册的类名
// @ts-ignore
// console.log(CADFactory.factory.objectNameMap); // 为什么Map中的构造函数名带_1后缀
console.log(CADFactory['factory'].objectNameMap); // 为什么Map中的构造函数名带_1后缀
CADFactory.RegisterObjectAlias(LayerNode, "LayerNode");
CADFactory.RegisterObjectAlias(TextureTableRecord, "TextureTableRecord");
CADFactory.RegisterObjectAlias(PhysicalMaterialRecord, "PhysicalMaterialRecord");
app = createApp(App);
app.use(pinia)
@@ -52,8 +54,7 @@ export function UpdateTexture() {
useEvent().Publish('update-texture');
}
export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{ file: string }>
{
export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{ file: string }> {
let pinia = createPinia();
const scene = useSceneRaw(pinia);
@@ -61,8 +62,8 @@ export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{
virtualDom.style.display = 'none';
scene.Initial(virtualDom);
await scene.ChangeTextureFromUrlAsync(options.textureSrc);
var json = btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())));
var json = ToDeflatedBase64(await scene.SerializeMaterialAsync());
scene.Dispose();
virtualDom.remove();
disposePinia(pinia);

View File

@@ -1,12 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import './assets/main.css'
import { createPinia } from 'pinia';
import { Mount } from './lib';
const pinia = createPinia();
createApp(App)
.use(pinia)
.mount('#app')
Mount("#app");