// src/mmd/pmx/parser/PMXParser.ts
var PMXParser = class {
  constructor() {
    this.offset = 0;
    this.textEncoding = "utf16le";
    this.textureIndexSize = 1;
    this.additionalVec4Count = 0;
    this.vertexIndexSize = 1;
    this.boneIndexSize = 1;
  }
  /**
   * 从URL加载并解析PMX文件
   */
  async loadAndParse(url) {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`Failed to load PMX file: ${response.statusText}`);
    }
    const buffer = await response.arrayBuffer();
    return this.parse(buffer);
  }
  /**
   * 解析PMX文件
   */
  parse(buffer) {
    this.view = new DataView(buffer);
    this.offset = 0;
    console.log("[PMXParser] Starting parse, file size:", buffer.byteLength);
    const header = this.parseHeader();
    console.log("[PMXParser] Header parsed, offset:", this.offset);
    console.log("[PMXParser] Globals:", header.globals);
    const modelInfo = this.parseModelInfo();
    console.log("[PMXParser] Model info parsed, offset:", this.offset);
    console.log("[PMXParser] Model name:", modelInfo.modelName);
    const vertexCount = this.skipVertices();
    console.log("[PMXParser] Vertices skipped, count:", vertexCount, "offset:", this.offset);
    const faceCount = this.skipFaces();
    console.log("[PMXParser] Faces skipped, count:", faceCount, "offset:", this.offset);
    const textures = this.parseTextures();
    console.log("[PMXParser] Textures parsed, count:", textures.length, "offset:", this.offset);
    const materials = this.parseMaterials();
    console.log("[PMXParser] Materials parsed, count:", materials.length, "offset:", this.offset);
    const materialTextureMappings = this.generateMaterialTextureMappings(
      materials,
      textures
    );
    return {
      header,
      modelInfo,
      textures,
      materials,
      materialTextureMappings,
      vertexCount,
      faceCount
    };
  }
  /**
   * 解析文件头
   */
  parseHeader() {
    const signature = this.readString(4);
    if (signature !== "PMX ") {
      throw new Error(`Invalid PMX signature: ${signature}`);
    }
    const version = this.view.getFloat32(this.offset, true);
    this.offset += 4;
    const globalsCount = this.view.getUint8(this.offset);
    this.offset += 1;
    if (globalsCount !== 8) {
      throw new Error(`Unexpected globals count: ${globalsCount}`);
    }
    const encoding = this.view.getUint8(this.offset);
    this.offset += 1;
    this.textEncoding = encoding === 0 ? "utf16le" : "utf8";
    const additionalVec4Count = this.view.getUint8(this.offset);
    this.offset += 1;
    this.additionalVec4Count = additionalVec4Count;
    const vertexIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    this.vertexIndexSize = vertexIndexSize;
    const textureIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    this.textureIndexSize = textureIndexSize;
    const materialIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    const boneIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    this.boneIndexSize = boneIndexSize;
    const morphIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    const rigidBodyIndexSize = this.view.getUint8(this.offset);
    this.offset += 1;
    return {
      signature,
      version,
      globals: {
        encoding,
        additionalVec4Count,
        vertexIndexSize,
        textureIndexSize,
        materialIndexSize,
        boneIndexSize,
        morphIndexSize,
        rigidBodyIndexSize
      }
    };
  }
  /**
   * 解析模型信息
   */
  parseModelInfo() {
    const modelName = this.readTextBuffer();
    const modelNameEnglish = this.readTextBuffer();
    const comment = this.readTextBuffer();
    const commentEnglish = this.readTextBuffer();
    return {
      modelName,
      modelNameEnglish,
      comment,
      commentEnglish
    };
  }
  /**
   * 跳过顶点数据（只返回数量）
   */
  skipVertices() {
    const count = this.view.getInt32(this.offset, true);
    this.offset += 4;
    for (let i = 0; i < count; i++) {
      this.offset += 12;
      this.offset += 12;
      this.offset += 8;
      this.offset += this.additionalVec4Count * 16;
      const weightType = this.view.getUint8(this.offset);
      this.offset += 1;
      this.skipVertexWeight(weightType);
      this.offset += 4;
    }
    return count;
  }
  /**
   * 跳过顶点权重数据
   */
  skipVertexWeight(weightType) {
    switch (weightType) {
      case 0:
        this.offset += this.boneIndexSize;
        break;
      case 1:
        this.offset += this.boneIndexSize * 2 + 4;
        break;
      case 2:
        this.offset += this.boneIndexSize * 4 + 16;
        break;
      case 3:
        this.offset += this.boneIndexSize * 2 + 4 + 36;
        break;
      case 4:
        this.offset += this.boneIndexSize * 4 + 16;
        break;
    }
  }
  /**
   * 跳过面数据（只返回数量）
   */
  skipFaces() {
    const count = this.view.getInt32(this.offset, true);
    this.offset += 4;
    this.offset += count * this.vertexIndexSize;
    return count / 3;
  }
  /**
   * 解析纹理列表
   */
  parseTextures() {
    const count = this.view.getInt32(this.offset, true);
    this.offset += 4;
    console.log("[PMXParser] Parsing textures, count:", count);
    if (count < 0 || count > 1e4) {
      throw new Error(`Invalid texture count: ${count} at offset ${this.offset - 4}`);
    }
    const textures = [];
    for (let i = 0; i < count; i++) {
      const path = this.readTextBuffer();
      textures.push({
        index: i,
        path
      });
      console.log(`[PMXParser]   Texture ${i}: ${path}`);
    }
    return textures;
  }
  /**
   * 解析材质列表
   */
  parseMaterials() {
    const count = this.view.getInt32(this.offset, true);
    this.offset += 4;
    const materials = [];
    for (let i = 0; i < count; i++) {
      const name = this.readTextBuffer();
      const nameEnglish = this.readTextBuffer();
      const diffuse = [
        this.view.getFloat32(this.offset, true),
        this.view.getFloat32(this.offset + 4, true),
        this.view.getFloat32(this.offset + 8, true),
        this.view.getFloat32(this.offset + 12, true)
      ];
      this.offset += 16;
      const specular = [
        this.view.getFloat32(this.offset, true),
        this.view.getFloat32(this.offset + 4, true),
        this.view.getFloat32(this.offset + 8, true)
      ];
      this.offset += 12;
      const specularStrength = this.view.getFloat32(this.offset, true);
      this.offset += 4;
      const ambient = [
        this.view.getFloat32(this.offset, true),
        this.view.getFloat32(this.offset + 4, true),
        this.view.getFloat32(this.offset + 8, true)
      ];
      this.offset += 12;
      const drawingFlags = this.view.getUint8(this.offset);
      this.offset += 1;
      const edgeColor = [
        this.view.getFloat32(this.offset, true),
        this.view.getFloat32(this.offset + 4, true),
        this.view.getFloat32(this.offset + 8, true),
        this.view.getFloat32(this.offset + 12, true)
      ];
      this.offset += 16;
      const edgeSize = this.view.getFloat32(this.offset, true);
      this.offset += 4;
      const textureIndex = this.readIndex(this.textureIndexSize);
      const sphereTextureIndex = this.readIndex(this.textureIndexSize);
      const sphereMode = this.view.getUint8(this.offset);
      this.offset += 1;
      const isSharedToon = this.view.getUint8(this.offset) === 1;
      this.offset += 1;
      const toonTextureIndex = isSharedToon ? this.view.getUint8(this.offset++) : this.readIndex(this.textureIndexSize);
      const memo = this.readTextBuffer();
      const surfaceCount = this.view.getInt32(this.offset, true);
      this.offset += 4;
      materials.push({
        name,
        nameEnglish,
        diffuse,
        specular,
        specularStrength,
        ambient,
        drawingFlags,
        edgeColor,
        edgeSize,
        textureIndex,
        sphereTextureIndex,
        sphereMode,
        isSharedToon,
        toonTextureIndex,
        memo,
        surfaceCount
      });
    }
    return materials;
  }
  /**
   * 生成材质纹理映射
   */
  generateMaterialTextureMappings(materials, textures) {
    const sphereModeMap = ["none", "multiply", "add", "subTexture"];
    return materials.map((material, index) => {
      const mapping = {
        materialIndex: index,
        materialName: material.name,
        materialNameEnglish: material.nameEnglish,
        surfaceCount: material.surfaceCount
      };
      if (material.textureIndex >= 0 && material.textureIndex < textures.length) {
        mapping.mainTexture = {
          index: material.textureIndex,
          path: textures[material.textureIndex].path
        };
      }
      if (material.sphereTextureIndex >= 0 && material.sphereTextureIndex < textures.length && material.sphereMode > 0) {
        mapping.sphereTexture = {
          index: material.sphereTextureIndex,
          path: textures[material.sphereTextureIndex].path,
          mode: sphereModeMap[material.sphereMode]
        };
      }
      if (material.isSharedToon) {
        mapping.toonTexture = {
          index: material.toonTextureIndex,
          path: `toon${String(material.toonTextureIndex).padStart(2, "0")}.bmp`,
          isShared: true
        };
      } else if (material.toonTextureIndex >= 0 && material.toonTextureIndex < textures.length) {
        mapping.toonTexture = {
          index: material.toonTextureIndex,
          path: textures[material.toonTextureIndex].path,
          isShared: false
        };
      }
      return mapping;
    });
  }
  /**
   * 读取文本缓冲区
   */
  readTextBuffer() {
    const length = this.view.getInt32(this.offset, true);
    this.offset += 4;
    if (length === 0) return "";
    if (length < 0 || length > 1e7) {
      throw new Error(`Invalid text buffer length: ${length} at offset ${this.offset - 4}`);
    }
    if (this.offset + length > this.view.buffer.byteLength) {
      throw new Error(`Text buffer extends beyond file boundary: offset=${this.offset}, length=${length}, fileSize=${this.view.buffer.byteLength}`);
    }
    const bytes = new Uint8Array(this.view.buffer, this.offset, length);
    this.offset += length;
    if (this.textEncoding === "utf8") {
      return new TextDecoder("utf-8").decode(bytes);
    } else {
      return new TextDecoder("utf-16le").decode(bytes);
    }
  }
  /**
   * 读取固定长度字符串
   */
  readString(length) {
    const bytes = new Uint8Array(this.view.buffer, this.offset, length);
    this.offset += length;
    return new TextDecoder("ascii").decode(bytes);
  }
  /**
   * 读取索引
   */
  readIndex(size) {
    let value;
    switch (size) {
      case 1:
        value = this.view.getInt8(this.offset);
        break;
      case 2:
        value = this.view.getInt16(this.offset, true);
        break;
      case 4:
        value = this.view.getInt32(this.offset, true);
        break;
      default:
        throw new Error(`Invalid index size: ${size}`);
    }
    this.offset += size;
    return value;
  }
};

export { PMXParser };
//# sourceMappingURL=chunk-VRTRSEEH.mjs.map
//# sourceMappingURL=chunk-VRTRSEEH.mjs.map