/** * 材质预设管理器 * 负责管理所有材质预设,包括内置预设和用户自定义预设 */ export class TexturePresetManager { constructor() { // 内置材质预设 this.builtInTextures = []; // 用户自定义材质 this.customTextures = []; // 材质分类 this.categories = new Map(); // 材质缓存 this.textureCache = new Map(); // 事件监听器 this.listeners = { textureAdded: [], textureRemoved: [], textureUpdated: [], }; // 初始化内置材质 this._initBuiltInTextures(); } /** * 初始化内置材质预设 * @private */ _initBuiltInTextures() { // 基于项目中的texture文件夹内容创建预设 const textureList = [ // 基础纹理 { id: "texture0", name: "纸质纹理", category: "基础纹理", path: "/src/assets/texture/texture0.webp", }, { id: "texture1", name: "粗糙表面", category: "基础纹理", path: "/src/assets/texture/texture1.webp", }, { id: "texture2", name: "细腻纹理", category: "基础纹理", path: "/src/assets/texture/texture2.webp", }, { id: "texture3", name: "颗粒质感", category: "基础纹理", path: "/src/assets/texture/texture3.webp", }, { id: "texture4", name: "布料纹理", category: "基础纹理", path: "/src/assets/texture/texture4.webp", }, { id: "texture5", name: "木质纹理", category: "自然纹理", path: "/src/assets/texture/texture5.webp", }, { id: "texture6", name: "石材纹理", category: "自然纹理", path: "/src/assets/texture/texture6.webp", }, { id: "texture7", name: "金属质感", category: "金属纹理", path: "/src/assets/texture/texture7.webp", }, { id: "texture8", name: "皮革纹理", category: "自然纹理", path: "/src/assets/texture/texture8.webp", }, { id: "texture9", name: "水彩纸质", category: "艺术纹理", path: "/src/assets/texture/texture9.webp", }, { id: "texture10", name: "画布纹理", category: "艺术纹理", path: "/src/assets/texture/texture10.webp", }, { id: "texture11", name: "沙砾质感", category: "自然纹理", path: "/src/assets/texture/texture11.webp", }, { id: "texture12", name: "水波纹理", category: "自然纹理", path: "/src/assets/texture/texture12.webp", }, { id: "texture13", name: "云朵纹理", category: "自然纹理", path: "/src/assets/texture/texture13.webp", }, { id: "texture14", name: "火焰纹理", category: "特效纹理", path: "/src/assets/texture/texture14.webp", }, { id: "texture15", name: "烟雾效果", category: "特效纹理", path: "/src/assets/texture/texture15.webp", }, { id: "texture16", name: "星空纹理", category: "特效纹理", path: "/src/assets/texture/texture16.webp", }, { id: "texture17", name: "大理石纹", category: "石材纹理", path: "/src/assets/texture/texture17.webp", }, { id: "texture18", name: "花岗岩纹", category: "石材纹理", path: "/src/assets/texture/texture18.webp", }, { id: "texture19", name: "竹纹理", category: "自然纹理", path: "/src/assets/texture/texture19.webp", }, { id: "texture20", name: "抽象图案", category: "艺术纹理", path: "/src/assets/texture/texture20.webp", }, ]; // 添加内置材质 textureList.forEach((texture) => { this.builtInTextures.push({ id: texture.id, name: texture.name, category: texture.category, path: texture.path, type: "builtin", preview: texture.path, // 使用原图作为预览 description: `内置${texture.category} - ${texture.name}`, tags: [texture.category.replace("纹理", ""), "内置"], created: new Date().toISOString(), // 默认属性 defaultSettings: { scale: 1, opacity: 1, repeat: "repeat", angle: 0, }, }); // 添加到分类 if (!this.categories.has(texture.category)) { this.categories.set(texture.category, []); } this.categories.get(texture.category).push(texture.id); }); } /** * 获取所有材质(内置 + 自定义) * @returns {Array} 材质数组 */ getAllTextures() { return [...this.builtInTextures, ...this.customTextures]; } /** * 根据ID获取材质 * @param {String} textureId 材质ID * @returns {Object|null} 材质对象 */ getTextureById(textureId) { return this.getAllTextures().find((texture) => texture.id === textureId) || null; } /** * 根据分类获取材质 * @param {String} category 分类名称 * @returns {Array} 材质数组 */ getTexturesByCategory(category) { return this.getAllTextures().filter((texture) => texture.category === category); } /** * 获取所有分类 * @returns {Array} 分类名称数组 */ getCategories() { const categories = new Set(); this.getAllTextures().forEach((texture) => { categories.add(texture.category); }); return Array.from(categories); } /** * 添加自定义材质 * @param {Object} textureData 材质数据 * @returns {String} 材质ID */ addCustomTexture(textureData) { const textureId = textureData.id || `custom_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const texture = { id: textureId, name: textureData.name || "自定义材质", category: textureData.category || "自定义材质", path: textureData.path || textureData.dataUrl, type: "custom", preview: textureData.preview || textureData.path || textureData.dataUrl, description: textureData.description || "用户自定义材质", tags: textureData.tags || ["自定义"], created: new Date().toISOString(), defaultSettings: { scale: textureData.scale || 1, opacity: textureData.opacity || 1, repeat: textureData.repeat || "repeat", angle: textureData.angle || 0, ...textureData.defaultSettings, }, // 保存原始文件信息 file: textureData.file || null, dataUrl: textureData.dataUrl || null, }; this.customTextures.push(texture); // 添加到分类 if (!this.categories.has(texture.category)) { this.categories.set(texture.category, []); } this.categories.get(texture.category).push(textureId); // 触发事件 this._triggerEvent("textureAdded", texture); return textureId; } /** * 删除自定义材质 * @param {String} textureId 材质ID * @returns {Boolean} 是否删除成功 */ removeCustomTexture(textureId) { const index = this.customTextures.findIndex((texture) => texture.id === textureId); if (index === -1) { return false; } const texture = this.customTextures[index]; // 只能删除自定义材质 if (texture.type !== "custom") { console.warn("不能删除内置材质"); return false; } this.customTextures.splice(index, 1); // 从分类中移除 if (this.categories.has(texture.category)) { const categoryTextures = this.categories.get(texture.category); const categoryIndex = categoryTextures.indexOf(textureId); if (categoryIndex !== -1) { categoryTextures.splice(categoryIndex, 1); } // 如果分类为空且不是内置分类,删除分类 if (categoryTextures.length === 0 && texture.category === "自定义材质") { this.categories.delete(texture.category); } } // 清除缓存 this.textureCache.delete(textureId); // 触发事件 this._triggerEvent("textureRemoved", texture); return true; } /** * 更新材质信息 * @param {String} textureId 材质ID * @param {Object} updates 更新数据 * @returns {Boolean} 是否更新成功 */ updateTexture(textureId, updates) { const texture = this.getTextureById(textureId); if (!texture || texture.type === "builtin") { return false; } // 更新材质属性 Object.assign(texture, updates); // 触发事件 this._triggerEvent("textureUpdated", texture); return true; } /** * 获取材质预览URL * @param {Object} texture 材质对象 * @returns {String} 预览URL */ getTexturePreviewUrl(texture) { if (!texture) return null; // 如果有预览图,使用预览图 if (texture.preview) { return texture.preview; } // 否则使用原图 return texture.path || texture.dataUrl; } /** * 加载材质图像 * @param {String} textureId 材质ID * @returns {Promise} 图像对象 */ loadTextureImage(textureId) { return new Promise((resolve, reject) => { // 检查缓存 if (this.textureCache.has(textureId)) { resolve(this.textureCache.get(textureId)); return; } const texture = this.getTextureById(textureId); if (!texture) { reject(new Error(`材质 ${textureId} 不存在`)); return; } const img = new Image(); img.crossOrigin = "anonymous"; img.onload = () => { // 缓存图像 this.textureCache.set(textureId, img); resolve(img); }; img.onerror = () => { reject(new Error(`材质 ${textureId} 加载失败`)); }; img.src = texture.path || texture.dataUrl; }); } /** * 搜索材质 * @param {String} query 搜索关键词 * @returns {Array} 匹配的材质数组 */ searchTextures(query) { if (!query) return this.getAllTextures(); const searchTerm = query.toLowerCase(); return this.getAllTextures().filter((texture) => { return ( texture.name.toLowerCase().includes(searchTerm) || texture.category.toLowerCase().includes(searchTerm) || texture.description.toLowerCase().includes(searchTerm) || texture.tags.some((tag) => tag.toLowerCase().includes(searchTerm)) ); }); } /** * 保存自定义材质到本地存储 */ saveCustomTexturesToStorage() { try { const customTexturesData = this.customTextures.map((texture) => ({ ...texture, // 不保存file对象到localStorage file: null, })); localStorage.setItem("canvasEditor_customTextures", JSON.stringify(customTexturesData)); } catch (error) { console.error("保存自定义材质失败:", error); } } /** * 从本地存储加载自定义材质 */ loadCustomTexturesFromStorage() { try { const stored = localStorage.getItem("canvasEditor_customTextures"); if (stored) { const customTexturesData = JSON.parse(stored); this.customTextures = customTexturesData; // 重建分类索引 this.customTextures.forEach((texture) => { if (!this.categories.has(texture.category)) { this.categories.set(texture.category, []); } if (!this.categories.get(texture.category).includes(texture.id)) { this.categories.get(texture.category).push(texture.id); } }); } } catch (error) { console.error("加载自定义材质失败:", error); this.customTextures = []; } } /** * 创建材质预设 * @param {String} name 预设名称 * @param {Object} settings 材质设置 * @returns {String} 预设ID */ createTexturePreset(name, settings) { const presetId = `preset_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const preset = { id: presetId, name: name, type: "preset", category: "材质预设", created: new Date().toISOString(), settings: { textureId: settings.textureId, scale: settings.scale || 1, opacity: settings.opacity || 1, repeat: settings.repeat || "repeat", angle: settings.angle || 0, brushSize: settings.brushSize || 5, brushOpacity: settings.brushOpacity || 1, brushColor: settings.brushColor || "#000000", }, }; this.customTextures.push(preset); this._triggerEvent("textureAdded", preset); return presetId; } /** * 应用材质预设 * @param {String} presetId 预设ID * @returns {Object|null} 预设设置 */ applyTexturePreset(presetId) { const preset = this.getTextureById(presetId); if (!preset || preset.type !== "preset") { return null; } return preset.settings; } /** * 添加事件监听器 * @param {String} event 事件名称 * @param {Function} callback 回调函数 */ addEventListener(event, callback) { if (this.listeners[event]) { this.listeners[event].push(callback); } } /** * 移除事件监听器 * @param {String} event 事件名称 * @param {Function} callback 回调函数 */ removeEventListener(event, callback) { if (this.listeners[event]) { const index = this.listeners[event].indexOf(callback); if (index !== -1) { this.listeners[event].splice(index, 1); } } } /** * 触发事件 * @param {String} event 事件名称 * @param {*} data 事件数据 * @private */ _triggerEvent(event, data) { if (this.listeners[event]) { this.listeners[event].forEach((callback) => { try { callback(data); } catch (error) { console.error(`执行 ${event} 事件监听器出错:`, error); } }); } } /** * 清除所有缓存 */ clearCache() { this.textureCache.clear(); } /** * 获取统计信息 * @returns {Object} 统计信息 */ getStats() { return { builtInCount: this.builtInTextures.length, customCount: this.customTextures.length, totalCount: this.getAllTextures().length, categoriesCount: this.getCategories().length, cacheSize: this.textureCache.size, }; } /** * 验证纹理文件 * @param {File} file 要验证的文件 * @returns {Boolean} 是否为有效的纹理文件 */ validateTextureFile(file) { if (!file) { console.warn("文件不存在"); return false; } // 检查文件类型 if (!file.type.startsWith("image/")) { console.warn("文件类型无效,必须是图片文件"); return false; } // 检查文件大小(限制为 10MB) const maxSize = 10 * 1024 * 1024; // 10MB if (file.size > maxSize) { console.warn("文件大小超过限制(10MB)"); return false; } // 检查支持的图片格式 const supportedTypes = [ "image/jpeg", "image/jpg", "image/png", "image/webp", "image/svg+xml", "image/bmp", "image/gif", ]; if (!supportedTypes.includes(file.type)) { console.warn("不支持的图片格式"); return false; } return true; } } // 创建单例实例 const texturePresetManager = new TexturePresetManager(); // 导出单例 export default texturePresetManager;