public static RenderBase.OModelGroup load(string fileName) { FileStream data = new FileStream(fileName, FileMode.Open); BinaryReader input = new BinaryReader(data); RenderBase.OModelGroup models; RenderBase.OModel model; string extension = Path.GetExtension(fileName).ToLower(); string bchFile = fileName.Replace(extension, ".bch"); bool isBCHLoaded = false; if (File.Exists(bchFile)) { models = BCH.load(bchFile); model = models.model[0]; models.model.Clear(); isBCHLoaded = true; } else { models = new RenderBase.OModelGroup(); model = new RenderBase.OModel(); model.name = "model"; model.material.Add(new RenderBase.OMaterial()); } ushort format = input.ReadUInt16(); bool isDataWithinHeader = format == 4; input.ReadUInt16(); //-1? uint contentFlags = input.ReadUInt32(); bool hasNameTable = (contentFlags & 2) > 0; uint mode = input.ReadUInt32(); uint meshCount = input.ReadUInt32(); List <vtxEntry> vtxDescriptors = new List <vtxEntry>(); List <idxEntry> idxDescriptors = new List <idxEntry>(); for (int i = 0; i < meshCount; i++) { if (mode == 1 && i == 0) { vtxDescriptors.Add(getVtxDescriptor(input)); } uint facesCount = input.ReadUInt32(); for (int j = 0; j < facesCount; j++) { idxEntry face = new idxEntry(); face.meshIndex = i; uint nodesCount = input.ReadUInt32(); for (int k = 0; k < nodesCount; k++) { face.nodeList.Add(input.ReadUInt32()); } face.primitiveCount = input.ReadUInt32(); if (hasNameTable) { face.nameId = input.ReadUInt32(); } if (isDataWithinHeader) { face.buffer = new ushort[face.primitiveCount]; for (int k = 0; k < face.primitiveCount; k++) { face.buffer[k] = input.ReadUInt16(); } alignWord(input); } idxDescriptors.Add(face); } if (mode == 0) { if (isDataWithinHeader) { vtxEntry desc = getVtxDescriptor(input); desc.buffer = new byte[desc.length]; input.Read(desc.buffer, 0, desc.buffer.Length); vtxDescriptors.Add(desc); alignWord(input); } else { vtxDescriptors.Add(getVtxDescriptor(input)); } } } List <string> objNameTable = new List <string>(); if (hasNameTable) { for (int i = 0; i < meshCount; i++) { byte index = input.ReadByte(); objNameTable.Add(IOUtils.readString(input, (uint)data.Position, true)); } } if (!isDataWithinHeader) { align(input); } byte[] vtxBuffer = null; vtxEntry currVertex = null; int faceIndex = 0; for (int i = 0; i < meshCount; i++) { if (mode == 0 || i == 0) { currVertex = vtxDescriptors[i]; if (!isDataWithinHeader) { vtxBuffer = new byte[vtxDescriptors[i].length]; input.Read(vtxBuffer, 0, vtxBuffer.Length); align(input); } else { vtxBuffer = currVertex.buffer; } } RenderBase.OMesh obj; if (isBCHLoaded) { obj = model.mesh[0]; model.mesh.RemoveAt(0); } else { obj = new RenderBase.OMesh(); obj.name = "mesh_" + i.ToString(); } for (int j = 0; j < currVertex.attributes.Count; j++) { switch (currVertex.attributes[j].type) { case vtxAttributeType.normal: obj.hasNormal = true; break; case vtxAttributeType.color: obj.hasColor = true; break; case vtxAttributeType.textureCoordinate0: obj.texUVCount = 1; break; case vtxAttributeType.textureCoordinate1: obj.texUVCount = 2; break; case vtxAttributeType.boneIndex: obj.hasNode = true; break; case vtxAttributeType.boneWeight: obj.hasWeight = true; break; } } for (;;) { int indexBufferPos = 0; for (int j = 0; j < idxDescriptors[faceIndex].primitiveCount; j++) { ushort index; if (isDataWithinHeader) { index = idxDescriptors[faceIndex].buffer[indexBufferPos++]; } else { index = input.ReadUInt16(); } RenderBase.OVertex vertex = new RenderBase.OVertex(); vertex.diffuseColor = 0xffffffff; for (int k = 0; k < currVertex.attributes.Count; k++) { vtxAttribute att = currVertex.attributes[k]; int pos = (int)(index * currVertex.stride + att.offset); float scale = att.scale; switch (currVertex.attributes[k].type) { case vtxAttributeType.position: vertex.position = getVector3(vtxBuffer, pos, att.format, scale); break; case vtxAttributeType.normal: vertex.normal = getVector3(vtxBuffer, pos, att.format, scale); break; case vtxAttributeType.color: RenderBase.OVector4 c = getVector4(vtxBuffer, pos, att.format, scale); uint r = MeshUtils.saturate(c.x * 0xff); uint g = MeshUtils.saturate(c.y * 0xff); uint b = MeshUtils.saturate(c.z * 0xff); uint a = MeshUtils.saturate(c.w * 0xff); vertex.diffuseColor = b | (g << 8) | (r << 16) | (a << 24); break; case vtxAttributeType.textureCoordinate0: vertex.texture0 = getVector2(vtxBuffer, pos, att.format, scale); break; case vtxAttributeType.textureCoordinate1: vertex.texture1 = getVector2(vtxBuffer, pos, att.format, scale); break; case vtxAttributeType.boneIndex: byte n0 = vtxBuffer[pos]; byte n1 = vtxBuffer[pos + 1]; vertex.node.Add((int)idxDescriptors[faceIndex].nodeList[n0]); vertex.node.Add((int)idxDescriptors[faceIndex].nodeList[n1]); break; case vtxAttributeType.boneWeight: RenderBase.OVector2 w = getVector2(vtxBuffer, pos, att.format, scale); vertex.weight.Add(w.x); vertex.weight.Add(w.y); break; } } MeshUtils.calculateBounds(model, vertex); obj.vertices.Add(vertex); } faceIndex++; if (!isDataWithinHeader) { align(input); } if (faceIndex >= idxDescriptors.Count) { break; } if (idxDescriptors[faceIndex].meshIndex == i) { continue; } break; } model.mesh.Add(obj); } models.model.Add(model); data.Close(); return(models); }
/// <summary> /// Reads a Vertex Descriptor from the mbn file. /// </summary> /// <param name="input">The Binary Reader of the mbn file</param> /// <returns></returns> private static vtxEntry getVtxDescriptor(BinaryReader input) { vtxEntry vtx = new vtxEntry(); uint attributesCount = input.ReadUInt32(); for (int j = 0; j < attributesCount; j++) { vtxAttribute att = new vtxAttribute(); att.type = (vtxAttributeType)input.ReadUInt32(); if (att.type != vtxAttributeType.color) while ((vtx.stride & 1) != 0) vtx.stride++; att.format = (vtxAttributeQuantization)input.ReadUInt32(); att.scale = input.ReadSingle(); att.offset = vtx.stride; vtx.attributes.Add(att); uint len = 0; switch (att.format) { case vtxAttributeQuantization.single: len = 4; break; case vtxAttributeQuantization.unsignedByte: len = 1; break; case vtxAttributeQuantization.signedByte: len = 1; break; case vtxAttributeQuantization.signedShort: len = 2; break; } switch (att.type) { case vtxAttributeType.position: vtx.stride += 3 * len; break; case vtxAttributeType.normal: vtx.stride += 3 * len; break; case vtxAttributeType.color: vtx.stride += 4 * len; break; case vtxAttributeType.textureCoordinate0: vtx.stride += 2 * len; break; case vtxAttributeType.textureCoordinate1: vtx.stride += 2 * len; break; case vtxAttributeType.boneIndex: vtx.stride += 2 * len; break; case vtxAttributeType.boneWeight: vtx.stride += 2 * len; break; case vtxAttributeType.unk1: vtx.stride += 2 * len; break; default: throw new Exception("MBN: Unknown Vertex Attribute type, can't calculate Stride! STOP!"); } } while ((vtx.stride & 1) != 0) vtx.stride++; vtx.length = input.ReadUInt32(); return vtx; }
/// <summary> /// Reads a Vertex Descriptor from the mbn file. /// </summary> /// <param name="input">The Binary Reader of the mbn file</param> /// <returns></returns> private static vtxEntry getVtxDescriptor(BinaryReader input) { vtxEntry vtx = new vtxEntry(); uint attributesCount = input.ReadUInt32(); for (int j = 0; j < attributesCount; j++) { vtxAttribute att = new vtxAttribute(); att.type = (vtxAttributeType)input.ReadUInt32(); if (att.type != vtxAttributeType.color) { while ((vtx.stride & 1) != 0) { vtx.stride++; } } att.format = (vtxAttributeQuantization)input.ReadUInt32(); att.scale = input.ReadSingle(); att.offset = vtx.stride; vtx.attributes.Add(att); uint len = 0; switch (att.format) { case vtxAttributeQuantization.single: len = 4; break; case vtxAttributeQuantization.unsignedByte: len = 1; break; case vtxAttributeQuantization.signedByte: len = 1; break; case vtxAttributeQuantization.signedShort: len = 2; break; } switch (att.type) { case vtxAttributeType.position: vtx.stride += 3 * len; break; case vtxAttributeType.normal: vtx.stride += 3 * len; break; case vtxAttributeType.color: vtx.stride += 4 * len; break; case vtxAttributeType.textureCoordinate0: vtx.stride += 2 * len; break; case vtxAttributeType.textureCoordinate1: vtx.stride += 2 * len; break; case vtxAttributeType.boneIndex: vtx.stride += 2 * len; break; case vtxAttributeType.boneWeight: vtx.stride += 2 * len; break; case vtxAttributeType.unk1: vtx.stride += 2 * len; break; default: throw new Exception("MBN: Unknown Vertex Attribute type, can't calculate Stride! STOP!"); } } while ((vtx.stride & 1) != 0) { vtx.stride++; } vtx.length = input.ReadUInt32(); return(vtx); }