/*type 1 - collisions * type 2 - spawns * type 3 - respawns * type 4 - camera bounds * type 5 - death boundaries * type 6 - ??? * type 7 - ITEMPT_transform * type 8 - enemyGenerator * type 9 - ITEMPT * type 10 - fsAreaCam (and other fsArea's ? ) * type 11 - fsCamLimit * type 12 - damageShapes (damage sphere and damage capsule are the only ones I've seen, type 2 and 3 respectively) * type 13 - item spawners * type 14 - general shapes (general rect, general path, etc.) * type 15 - general points * type 16 - ??? * type 17 - FsStartPoint * type 18 - ??? * type 19 - ???*/ public override void Read(string filename) { FileData f = new FileData(filename); f.seek(0xB);//It's magic int collisionCount = f.readInt(); for (int i = 0; i < collisionCount; i++) { Collision temp = new Collision(); temp.read(f); collisions.Add(temp); } f.skip(1); //Seperation char int spawnCount = f.readInt(); for (int i = 0; i < spawnCount; i++) { Point temp = new Point(); f.skip(0xD); temp.name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char temp.subname = f.readString(f.pos(), 0x40); f.skip(0xA6); temp.x = f.readFloat(); temp.y = f.readFloat(); spawns.Add(temp); } f.skip(1);//Seperation char int respawnCount = f.readInt(); for (int i = 0; i < respawnCount; i++) { Point temp = new Point(); f.skip(0xD); temp.name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char temp.subname = f.readString(f.pos(), 0x40); f.skip(0xA6); temp.x = f.readFloat(); temp.y = f.readFloat(); respawns.Add(temp); } f.skip(1);//Seperation char int cameraCount = f.readInt(); for (int i = 0; i < cameraCount; i++) { Bounds temp = new Bounds(); f.skip(0xD); temp.name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char temp.subname = f.readString(f.pos(), 0x40); f.skip(0xA6); temp.left = f.readFloat(); temp.right = f.readFloat(); temp.top = f.readFloat(); temp.bottom = f.readFloat(); cameraBounds.Add(temp); } f.skip(1);//Seperation char int blastzoneCount = f.readInt(); for (int i = 0; i < blastzoneCount; i++) { Bounds temp = new Bounds(); f.skip(0xD); temp.name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char temp.subname = f.readString(f.pos(), 0x40); f.skip(0xA6); temp.left = f.readFloat(); temp.right = f.readFloat(); temp.top = f.readFloat(); temp.bottom = f.readFloat(); blastzones.Add(temp); } f.skip(1); //Seperation char if (f.readInt() != 0) //1 { return; } f.skip(1); //Seperation char if (f.readInt() != 0) //2 { return; } f.skip(1);//Seperation char int enemyGeneratorCount = f.readInt(); if (enemyGeneratorCount != 0) { return; } f.skip(1); //Seperation char if (f.readInt() != 0) //4 { return; } f.skip(1);//Seperation char int fsAreaCamCount = f.readInt(); if (fsAreaCamCount != 0) { return; } f.skip(1);//Seperation char int fsCamLimitCount = f.readInt(); if (fsCamLimitCount != 0) { return; } f.skip(1);//Seperation char int damageShapeCount = f.readInt(); for (int i = 0; i < damageShapeCount; i++) { f.skip(0xD); string tempName = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char string tempSubname = f.readString(f.pos(), 0x40); f.skip(0xA6); int shapeType = f.readInt(); if (shapeType == 2) { Sphere temp = new Sphere(); temp.name = tempName; temp.subname = tempSubname; temp.x = f.readFloat(); temp.y = f.readFloat(); temp.z = f.readFloat(); temp.radius = f.readFloat(); f.skip(0x11); damageSpheres.Add(temp); } else if (shapeType == 3) { Capsule temp = new Capsule(); temp.name = tempName; temp.subname = tempSubname; temp.x = f.readFloat(); temp.y = f.readFloat(); temp.z = f.readFloat(); temp.dx = f.readFloat(); temp.dy = f.readFloat(); temp.dz = f.readFloat(); temp.r = f.readFloat(); temp.unk = f.readFloat(); f.skip(1); damageCapsules.Add(temp); } else { throw new NotImplementedException(); } } f.skip(1);//Seperation char int itemCount = f.readInt(); for (int i = 0; i < itemCount; i++) { ItemSpawner temp = new ItemSpawner(); temp.read(f); items.Add(temp); } f.skip(1);//Seperation char int generalShapeCount = f.readInt(); for (int i = 0; i < generalShapeCount; i++) { f.skip(0xD); string tempName = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char string tempSubname = f.readString(f.pos(), 0x40); f.skip(0xAB); int shapeType = f.readInt(); LVDGeneralShape p; if (shapeType == 1) { p = new GeneralPoint(); } else if (shapeType == 3) { p = new GeneralRect(); } else if (shapeType == 4) { p = new GeneralPath(); } else { throw new Exception($"Unknown shape type {shapeType} at offset {f.pos() - 4}"); } p.name = tempName; p.subname = tempSubname; p.Read(f); generalShapes.Add(p); } f.skip(1); int generalPointCount = f.readInt(); for (int i = 0; i < generalPointCount; i++) { Point temp = new Point(); f.skip(0xD); temp.name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char temp.subname = f.readString(f.pos(), 0x40); f.skip(0xAF); temp.x = f.readFloat(); temp.y = f.readFloat(); f.skip(0x14); generalPoints.Add(temp); } if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); if (f.readInt() != 0) //8 { return; //no clue how to be consistent in reading these so... } f.skip(1); //LVD doesn't end here and neither does my confusion, will update this part later }
public override void Read(string filename) { bchHeader header = new bchHeader(); FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(4); header.backwardCompatibility = f.readByte(); header.forwardCompatibility = f.readByte(); header.version = f.readUShort(); header.mainHeaderOffset = f.readInt(); header.stringTableOffset = f.readInt(); header.gpuCommandsOffset = f.readInt(); header.dataOffset = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedOffset = f.readInt(); } header.relocationTableOffset = f.readInt(); header.mainHeaderLength = f.readInt(); header.stringTableLength = f.readInt(); header.gpuCommandsLength = f.readInt(); header.dataLength = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedLength = f.readInt(); } header.relocationTableLength = f.readInt(); header.uninitializedDataSectionLength = f.readInt(); header.uninitializedDescriptionSectionLength = f.readInt(); if (header.backwardCompatibility > 7) { header.flags = f.readUShort(); header.addressCount = f.readUShort(); } // Relocation table for (int i = 0; i < header.relocationTableLength; i += 4) { f.seek(header.relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.mainHeaderOffset); break; case 1: f.seek(off + header.mainHeaderOffset); f.writeInt((off) + header.mainHeaderOffset, f.readInt() + header.stringTableOffset); break; case 2: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.gpuCommandsOffset); break; case 0xc: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; } f.seek((off * 4) + header.gpuCommandsOffset); if (header.backwardCompatibility < 6) { switch (flag) { case 0x23: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, ((f.readInt() + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x27: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 8) { switch (flag) { case 0x24: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x28: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 0x21) { switch (flag) { case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x27: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x28: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x29: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else { switch (flag) { case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex relative to Data Offset //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset case 0x28: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset case 0x2b: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataExtendedOffset); break; //Vertex relative to Data Extended Offset //case 0x2c: writer.Write(((peek(input) + header.dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset case 0x2d: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset } } } // Content Header f.seek(header.mainHeaderOffset); bchContentHeader content = new bchContentHeader(); { content.modelsPointerTableOffset = f.readInt(); content.modelsPointerTableEntries = f.readInt(); content.modelsNameOffset = f.readInt(); content.materialsPointerTableOffset = f.readInt(); content.materialsPointerTableEntries = f.readInt(); content.materialsNameOffset = f.readInt(); content.shadersPointerTableOffset = f.readInt(); content.shadersPointerTableEntries = f.readInt(); content.shadersNameOffset = f.readInt(); content.texturesPointerTableOffset = f.readInt(); content.texturesPointerTableEntries = f.readInt(); content.texturesNameOffset = f.readInt(); content.materialsLUTPointerTableOffset = f.readInt(); content.materialsLUTPointerTableEntries = f.readInt(); content.materialsLUTNameOffset = f.readInt(); content.lightsPointerTableOffset = f.readInt(); content.lightsPointerTableEntries = f.readInt(); content.lightsNameOffset = f.readInt(); content.camerasPointerTableOffset = f.readInt(); content.camerasPointerTableEntries = f.readInt(); content.camerasNameOffset = f.readInt(); content.fogsPointerTableOffset = f.readInt(); content.fogsPointerTableEntries = f.readInt(); content.fogsNameOffset = f.readInt(); content.skeletalAnimationsPointerTableOffset = f.readInt(); content.skeletalAnimationsPointerTableEntries = f.readInt(); content.skeletalAnimationsNameOffset = f.readInt(); content.materialAnimationsPointerTableOffset = f.readInt(); content.materialAnimationsPointerTableEntries = f.readInt(); content.materialAnimationsNameOffset = f.readInt(); content.visibilityAnimationsPointerTableOffset = f.readInt(); content.visibilityAnimationsPointerTableEntries = f.readInt(); content.visibilityAnimationsNameOffset = f.readInt(); content.lightAnimationsPointerTableOffset = f.readInt(); content.lightAnimationsPointerTableEntries = f.readInt(); content.lightAnimationsNameOffset = f.readInt(); content.cameraAnimationsPointerTableOffset = f.readInt(); content.cameraAnimationsPointerTableEntries = f.readInt(); content.cameraAnimationsNameOffset = f.readInt(); content.fogAnimationsPointerTableOffset = f.readInt(); content.fogAnimationsPointerTableEntries = f.readInt(); content.fogAnimationsNameOffset = f.readInt(); content.scenePointerTableOffset = f.readInt(); content.scenePointerTableEntries = f.readInt(); content.sceneNameOffset = f.readInt(); } //Skeletal animation for (int index1 = 0; index1 < content.skeletalAnimationsPointerTableEntries; index1++) { f.seek(content.skeletalAnimationsPointerTableOffset + (index1 * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); string skeletalAnimationName = f.readString(f.readInt(), -1); int animationFlags = f.readInt(); //int skeletalAnimationloopMode = f.readByte(); //pas ça du tout float skeletalAnimationframeSize = f.readFloat(); int boneTableOffset = f.readInt(); int boneTableEntries = f.readInt(); int metaDataPointerOffset = f.readInt(); //Debug.WriteLine("Animation Name: " + skeletalAnimationName); //Debug.WriteLine("BonetableOffset: " + boneTableOffset.ToString("X")); //Debug.WriteLine("BonetableEntry: " + boneTableEntries.ToString("X")); for (int i = 0; i < boneTableEntries; i++) { f.seek(boneTableOffset + (i * 4)); int offset = f.readInt(); OSkeletalAnimationBone bone = new OSkeletalAnimationBone(); f.seek(offset); bone.name = f.readString(f.readInt(), -1); Console.WriteLine("Bone Name: " + bone.name); int animationTypeFlags = f.readInt(); int flags = f.readInt(); OSegmentType segmentType = (OSegmentType)((animationTypeFlags >> 16) & 0xf); switch (segmentType) { case OSegmentType.transform: f.seek(offset + 0x18); int notExistMask = 0x80000; int constantMask = 0x200; for (int j = 0; j < 2; j++) { for (int axis = 0; axis < 3; axis++) { bool notExist = (flags & notExistMask) > 0; bool constant = (flags & constantMask) > 0; OAnimationKeyFrameGroup frame = new OAnimationKeyFrameGroup(); frame.exists = !notExist; if (frame.exists) { if (constant) { frame.interpolation = OInterpolationMode.linear; frame.keyFrames.Add(new OAnimationKeyFrame(f.readFloat(), 0)); } else { int frameOffset = f.readInt(); int position = f.pos(); f.seek(frameOffset); //getAnimationKeyFrame(input, frame); f.seek(position); } } else { f.seek(f.pos() + 0x04); } if (j == 0) { switch (axis) { case 0: bone.rotationX = frame; break; case 1: bone.rotationY = frame; break; case 2: bone.rotationZ = frame; break; } } else { switch (axis) { case 0: bone.translationX = frame; break; case 1: bone.translationY = frame; break; case 2: bone.translationZ = frame; break; } } notExistMask <<= 1; constantMask <<= 1; } constantMask <<= 1; } break; case OSegmentType.transformQuaternion: bone.isFrameFormat = true; int scaleOffset = f.readInt(); int rotationOffset = f.readInt(); int translationOffset = f.readInt(); if ((flags & 0x20) == 0) { bone.scale.exists = true; f.seek(scaleOffset); if ((flags & 4) > 0) { bone.scale.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), 0)); } else { bone.scale.startFrame = f.readFloat(); bone.scale.endFrame = f.readFloat(); int scaleFlags = f.readInt(); int scaleDataOffset = f.readInt(); int scaleEntries = f.readInt(); f.seek(scaleDataOffset); for (int j = 0; j < scaleEntries; j++) { bone.scale.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), 0)); } } } if ((flags & 0x10) == 0) { bone.rotationQuaternion.exists = true; f.seek(rotationOffset); if ((flags & 2) > 0) { bone.rotationQuaternion.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat())); } else { bone.rotationQuaternion.startFrame = f.readFloat(); bone.rotationQuaternion.endFrame = f.readFloat(); int rotationFlags = f.readInt(); int rotationDataOffset = f.readInt(); int rotationEntries = f.readInt(); f.seek(rotationDataOffset); for (int j = 0; j < rotationEntries; j++) { bone.rotationQuaternion.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat())); } } } if ((flags & 8) == 0) { bone.translation.exists = true; f.seek(translationOffset); if ((flags & 1) > 0) { bone.translation.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), 0)); } else { bone.translation.startFrame = f.readFloat(); bone.translation.endFrame = f.readFloat(); int translationFlags = f.readInt(); int translationDataOffset = f.readInt(); int translationEntries = f.readInt(); f.seek(translationDataOffset); for (int j = 0; j < translationEntries; j++) { bone.translation.vector.Add(new Vector4( f.readFloat(), f.readFloat(), f.readFloat(), 0)); } } } break; case OSegmentType.transformMatrix: bone.isFullBakedFormat = true; f.readInt(); f.readInt(); int matrixOffset = f.readInt(); int entries = f.readInt(); f.seek(matrixOffset); for (int j = 0; j < entries; j++) { /*OMatrix transform = new OMatrix(); * transform.M11 = f.readFloat(); * transform.M21 = f.readFloat(); * transform.M31 = f.readFloat(); * transform.M41 = f.readFloat(); * * transform.M12 = f.readFloat(); * transform.M22 = f.readFloat(); * transform.M32 = f.readFloat(); * transform.M42 = f.readFloat(); * * transform.M13 = f.readFloat(); * transform.M23 = f.readFloat(); * transform.M33 = f.readFloat(); * transform.M43 = f.readFloat(); * * bone.transform.Add(transform);*/ } break; default: throw new Exception(string.Format("BCH: Unknow Segment Type {0} on Skeletal Animation bone {1}! STOP!", segmentType, bone.name)); } //skeletalAnimation.bone.Add(bone); } } //Shaders (unused for now, until someone wants to add them) for (int index = 0; index < content.shadersPointerTableEntries; index++) { f.seek(content.shadersPointerTableOffset + (index * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); int shaderDataOffset = f.readInt(); int shaderDataLength = f.readInt(); } // Textures // WIP Section for (int index = 0; index < content.texturesPointerTableEntries; index++) { f.seek(content.texturesPointerTableOffset + (index * 4)); int dOffset = f.readInt(); f.seek(dOffset); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); f.seek(f.pos() + 0x14); String textureName = f.readString(f.readInt(), -1); //Debug.WriteLine("gpuCommandOffset: " + header.gpuCommandsOffset.ToString("X")); f.seek(textureCommandsOffset); //Debug.WriteLine("textureCommandOffset: " + textureCommandsOffset.ToString("X")); BCH_Texture tex = new BCH_Texture(); textures.Add(textureName, tex); tex.Height = f.readUShort(); tex.Width = f.readUShort(); f.skip(12); int doffset = f.readInt(); //Debug.WriteLine("doffset: " + doffset.ToString("X")); f.skip(4); tex.type = f.readInt(); tex.data = f.getSection(doffset, f.size() - doffset); tex.texture = _3DS.DecodeImage(tex.data, tex.Width, tex.Height, (_3DS.Tex_Formats)tex.type); tex.display = Rendering.Texture.CreateGlTextureFromBitmap(tex.texture); } // Model data for (int modelIndex = 0; modelIndex < content.modelsPointerTableEntries; modelIndex++) { f.seek(content.modelsPointerTableOffset + (modelIndex * 4)); int objectsHeaderOffset = f.readInt(); // Objects f.seek(objectsHeaderOffset); BCH_Model model = new BCH_Model(); models.Add(model); model.flags = f.readByte(); model.skeletonScaleType = f.readByte(); model.silhouetteMaterialEntries = f.readUShort(); model.worldTransform = new Matrix4(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , 0, 0, 0, 1); int materialsTableOffset = f.readInt(); int materialsTableEntries = f.readInt(); int materialsNameOffset = f.readInt(); int verticesTableOffset = f.readInt(); //Debug.WriteLine("Mesh Count: " + f.pos().ToString("X")); int verticesTableEntries = f.readInt(); f.skip(0x28); int skeletonOffset = f.readInt(); int skeletonEntries = f.readInt(); int skeletonNameOffset = f.readInt(); int objectsNodeVisibilityOffset = f.readInt(); int objectsNodeCount = f.readInt(); String name = f.readString(f.readInt(), -1); int objectsNodeNameEntries = f.readInt(); int objectsNodeNameOffset = f.readInt(); f.readInt(); //0x0 int metaDataPointerOffset = f.readInt(); f.seek(objectsNodeVisibilityOffset); int nodeVisibility = f.readInt(); string[] objectName = new string[objectsNodeNameEntries]; f.seek(objectsNodeNameOffset); int rootReferenceBit = f.readInt(); //Radix tree int rootLeftNode = f.readUShort(); int rootRightNode = f.readUShort(); int rootNameOffset = f.readInt(); for (int i = 0; i < objectsNodeNameEntries; i++) { int referenceBit = f.readInt(); short leftNode = f.readShort(); short rightNode = f.readShort(); objectName[i] = f.readString(f.readInt(), -1); //Debug.WriteLine(objectName[i]); } // Materials // NOTE: MATERIALS AND OBJECT SECTIONS ARE REALLY MESSY ATM String[] materialNames = new String[materialsTableEntries]; for (int index = 0; index < materialsTableEntries; index++) { f.seek(materialsTableOffset + (index * 0x2c)); int materialParametersOffset = f.readInt(); f.readInt(); f.readInt(); f.readInt(); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); int materialMapperOffset = f.readInt(); materialNames[index] = f.readString(f.readInt(), -1); } // Object Descriptions... // Assumes MBN is already loaded for now f.seek(verticesTableOffset); List <objDes> objDescriptors = new List <objDes>(); if (mbn == null) { mbn = new Smash_Forge.MBN(); for (int index = 0; index < verticesTableEntries; index++) { mbn.mesh.Add(new MBN.Mesh()); } mbn.PreRender(); } for (int index = 0; index < mbn.mesh.Count; index++) { int i = f.readUShort(); if (index > mbn.mesh.Count) { break; } if (i > materialNames.Length) { break; } mbn.mesh[index].texId = textures[materialNames[i]].display; Console.WriteLine("Tex index" + mbn.mesh[index].texId); f.skip(2); // flags int nameId = f.readUShort(); mbn.mesh[index].Text = objectName[nameId]; // node visibility TODO: finish... mbn.mesh[index].Checked = ((nodeVisibility & (1 << nameId)) > 0); mbn.mesh[index].renderPriority = f.readUShort(); objDes des = new objDes(); objDescriptors.Add(des); des.vshAttBufferCommandOffset = f.readInt(); des.vshAttBufferCommandCount = f.readInt(); des.faceOffset = f.readInt(); des.faceCount = f.readInt(); des.vshAttBufferCommandOffsetEx = f.readInt(); des.vshAttBufferCommandCountEx = f.readInt(); f.skip(12); // center vector f.skip(4); // flagsOffset f.skip(4); // 0? f.readInt(); //bbOffsets[i] //Debug.WriteLine(des.vshAttBufferCommandOffset.ToString("X")); } //Skeleton f.seek(skeletonOffset); for (int index = 0; index < skeletonEntries; index++) { Bone bone = new Smash_Forge.Bone(model.skeleton); //Bone bone = new Bone(bones); int boneFlags = f.readInt(); bone.parentIndex = f.readShort(); short boneSpace = f.readShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.readFloat(); bone.scale[1] = f.readFloat(); bone.scale[2] = f.readFloat(); bone.rotation[0] = f.readFloat(); bone.rotation[1] = f.readFloat(); bone.rotation[2] = f.readFloat(); bone.position[0] = f.readFloat(); bone.position[1] = f.readFloat(); bone.position[2] = f.readFloat(); // bone matrix... not really needed to be stored per say f.skip(4 * 4 * 3); bone.Text = f.readString(f.readInt(), -1); f.skip(4); // Meta data bones.bones.Add(bone); model.skeleton.bones.Add(bone); } model.skeleton.reset(); model.skeleton.update(); } }
public void Read(byte[] file) { FileData f = new FileData(file); f.Endian = Endianness.Big; f.seek(0); f.seek(4); // magic check SwitchCheck = f.readInt(); //Switch version only has padded magic verNumD = f.readByte(); verNumC = f.readByte(); verNumB = f.readByte(); verNumA = f.readByte(); if (SwitchCheck == 0x20202020) { //Console.WriteLine("Version = " + verNumA + "." + verNumB + "." + verNumC + "." + verNumD); if (f.readShort() == 0xFEFF) { f.Endian = Endianness.Big; } else { f.Endian = Endianness.Little; } f.skip(2); //Size Headeer f.skip(4); //File Name Direct int fileAlignment = f.readInt(); int RelocationTableOffset = f.readInt(); int BfresSize = f.readInt(); string name = f.readString(readOffset(f) + 2, -1); f.skip(4); // Padding long FMDLOffset = f.readInt64(); long FMDLDict = f.readInt64(); long FSKAOffset = f.readInt64(); long FSKADict = f.readInt64(); long FMAAOffset = f.readInt64(); long FMAADict = f.readInt64(); long FVISOffset = f.readInt64(); long FVISDict = f.readInt64(); long FSHUOffset = f.readInt64(); long FSHUDict = f.readInt64(); long FSCNOffset = f.readInt64(); long FSCNDict = f.readInt64(); long BuffMemPool = f.readInt64(); long BuffMemPoolInfo = f.readInt64(); long EMBOffset = f.readInt64(); long EMBDict = f.readInt64(); f.skip(8); // Padding long StringTableOffset = f.readInt64(); int unk11 = f.readInt(); int FMDLCount = f.readShort(); /*FSKACount =*/ f.readShort(); int FMAACount = f.readShort(); int FVISCount = f.readShort(); int FSHUCount = f.readShort(); int FSCNCount = f.readShort(); int EMBCount = f.readShort(); f.skip(12); // Padding // //Console.WriteLine($"FMDLOffset {FMDLOffset} FMDLCount {FMDLCount} FMDLDict {FMDLDict} FSKAOffset {FSKAOffset} FSKADict {FSKADict}"); // //Console.WriteLine($"FMAAOffset {FMAAOffset} FMAADict {FMAADict} FVISOffset {FVISOffset} FSHUOffset {FSKAOffset} FSKADict {FSHUDict}"); //FMDLs -Models- for (int i = 0; i < EMBCount; i++) { f.seek((int)EMBOffset + (i * 16)); int DataOffset = f.readInt(); f.seek(DataOffset); string EmMagic = f.readString(f.pos(), 4); if (EmMagic.Equals("BNTX")) //Textures { f.skip(24); int size = f.readInt(); f.seek(DataOffset); BinaryTexture t = new BinaryTexture(f.GetStream(size)); textures.Add(t.Name, t); } } f.seek((int)FMDLOffset); for (int i = 0; i < FMDLCount; i++) { // //Console.WriteLine("Reading FMDL...."); FMDL_Model model = new FMDL_Model(); //FMDL modelTest = new FMDL(); //modelTest.Read(f); f.skip(16); FMDLheader fmdl_info = new FMDLheader { name = f.readString(f.readInt() + 2, -1), padding = f.readInt(), eofString = f.readInt64(), fsklOff = f.readInt64(), fvtxArrOff = f.readInt64(), fshpOffset = f.readInt64(), fshpIndx = f.readInt64(), fmatOffset = f.readInt64(), fmatIndx = f.readInt64(), UserDataOffset = f.readInt64(), padding1 = f.readInt64(), padding2 = f.readInt64(), fvtxCount = f.readShort(), fshpCount = f.readShort(), fmatCount = f.readShort(), paramCount = f.readShort(), VertCount = f.readInt(), unk2 = f.readInt(), }; int NextFMDL = f.pos(); //Models.Nodes.Add(fmdl_info.name); // //Console.WriteLine($" Name {fmdl_info.name} eofString {fmdl_info.eofString} fsklOff {fmdl_info.fsklOff}"); // //Console.WriteLine(fmdl_info.fvtxCount); List <FVTXH> FVTXArr = new List <FVTXH>(); f.seek((int)fmdl_info.fvtxArrOff); for (int vtx = 0; vtx < fmdl_info.fvtxCount; vtx++) { // //Console.WriteLine("Reading FVTX...."); f.skip(16); FVTXArr.Add(new FVTXH { attArrOff = f.readInt64(), attIndxOff = f.readInt64(), unk1 = f.readInt64(), unk2 = f.readInt64(), unk3 = f.readInt64(), buffSizeOff = f.readInt64(), buffStrideSizeOff = f.readInt64(), buffArrOff = f.readInt64(), buffOff = f.readInt(), attCount = f.readByte(), buffCount = f.readByte(), sectIndx = f.readShort(), vertCount = f.readInt(), SkinWeightInfluence = f.readInt() }); // //Console.WriteLine($"attCount {FVTXArr[vtx].attCount}"); } f.seek((int)fmdl_info.fmatOffset); List <FMATH> FMATheaders = new List <FMATH>(); for (int mat = 0; mat < fmdl_info.fmatCount; mat++) { // //Console.WriteLine("Reading FMAT...."); f.skip(16); FMATH fmat_info = new FMATH { name = f.readString((int)f.readInt64() + 2, -1), renderInfoOff = f.readInt64(), renderInfoIndx = f.readInt64(), shaderAssignOff = f.readInt64(), u1 = f.readInt64(), texSelOff = f.readInt64(), u2 = f.readInt64(), texAttSelOff = f.readInt64(), texAttIndxOff = f.readInt64(), matParamArrOff = f.readInt64(), matParamIndxOff = f.readInt64(), matParamOff = f.readInt64(), userDataOff = f.readInt64(), userDataIndxOff = f.readInt64(), volatileFlagOffset = f.readInt64(), u3 = f.readInt64(), samplerSlotOff = f.readInt64(), textureSlotOff = f.readInt64(), flags = f.readInt(), //This toggles material visabilty sectIndx = f.readShort(), rendParamCount = f.readShort(), texSelCount = f.readByte(), texAttSelCount = f.readByte(), matParamCount = f.readShort(), u4 = f.readShort(), matParamSize = f.readShort(), rawParamDataSize = f.readShort(), userDataCount = f.readShort(), padding = f.readInt(), }; string FMATNameOffset = fmat_info.name; // //Console.WriteLine($"{FMATNameOffset} {fmat_info.texSelCount} "); FMATheaders.Add(fmat_info); } f.seek((int)fmdl_info.fsklOff + 16); // //Console.WriteLine("Reading FSKL...."); FSKLH fskl_info = new FSKLH { boneIndxOff = f.readInt64(), boneArrOff = f.readInt64(), invIndxArrOff = f.readInt64(), invMatrArrOff = f.readInt64(), padding1 = f.readInt64(), fsklType = f.readInt(), //flags boneArrCount = f.readShort(), invIndxArrCount = f.readShort(), exIndxCount = f.readShort(), u1 = f.readInt(), }; f.seek((int)fmdl_info.fsklOff + 16); FSKLH fskl_infov8 = new FSKLH { boneIndxOff = f.readInt64(), boneArrOff = f.readInt64(), invIndxArrOff = f.readInt64(), invMatrArrOff = f.readInt64(), padding1 = f.readInt64(), padding2 = f.readInt64(), padding3 = f.readInt64(), fsklType = f.readInt(), //flags boneArrCount = f.readShort(), invIndxArrCount = f.readShort(), exIndxCount = f.readShort(), u1 = f.readInt(), }; // //Console.WriteLine($"Bone Count {fskl_info.boneArrCount}"); //FSKL and many other sections will be revised and cleaner later if (verNumB == 8) { model.Node_Array = new int[fskl_infov8.invIndxArrCount + fskl_infov8.exIndxCount]; f.seek((int)fskl_infov8.invIndxArrOff); for (int nodes = 0; nodes < fskl_infov8.invIndxArrCount + fskl_infov8.exIndxCount; nodes++) { model.Node_Array[nodes] = (f.readShort()); } } else { model.Node_Array = new int[fskl_info.invIndxArrCount + fskl_info.exIndxCount]; f.seek((int)fskl_info.invIndxArrOff); for (int nodes = 0; nodes < fskl_info.invIndxArrCount + fskl_info.exIndxCount; nodes++) { model.Node_Array[nodes] = (f.readShort()); } } List <FSHPH> FSHPArr = new List <FSHPH>(); // //Console.WriteLine("Reading FSHP...."); f.seek((int)fmdl_info.fshpOffset); for (int shp = 0; shp < fmdl_info.fshpCount; shp++) { f.skip(16); FSHPArr.Add(new FSHPH { polyNameOff = f.readInt(), u1 = f.readInt(), fvtxOff = f.readInt64(), lodMdlOff = f.readInt64(), fsklIndxArrOff = f.readInt64(), u3 = f.readInt64(), u4 = f.readInt64(), boundingBoxOff = f.readInt64(), radiusOff = f.readInt64(), padding = f.readInt64(), flags = f.readInt(), sectIndx = f.readShort(), fmatIndx = f.readShort(), fsklIndx = f.readShort(), fvtxIndx = f.readShort(), fsklIndxArrCount = f.readShort(), matrFlag = f.readByte(), lodMdlCount = f.readByte(), visGrpCount = f.readInt(), visGrpIndxOff = f.readShort(), visGrpNodeOff = f.readShort(), }); } // //Console.WriteLine("Reading Bones...."); // //Console.WriteLine("Reading FSHP Array...."); //MeshTime!! for (int m = 0; m < FSHPArr.Count; m++) { Mesh poly = new Mesh(); poly.name = f.readString(FSHPArr[m].polyNameOff + 2, -1); // //Console.WriteLine("Polygon = " + poly.name); List <attdata> AttrArr = new List <attdata>(); f.seek((int)FVTXArr[FSHPArr[m].fvtxIndx].attArrOff); for (int att = 0; att < FVTXArr[FSHPArr[m].fvtxIndx].attCount; att++) { string AttType = f.readString(f.readInt() + 2, -1); f.skip(4); //padding f.Endian = Endianness.Big; int vertType = f.readShort(); f.skip(2); f.Endian = Endianness.Little; int buffOff = f.readShort(); int buffIndx = f.readShort(); // //Console.WriteLine($"{AttType} Type = {vertType} Offset = {buffOff} Index = {buffIndx} "); AttrArr.Add(new attdata { attName = AttType, buffIndx = buffIndx, buffOff = buffOff, vertType = vertType }); } //Get RLT real quick for buffer offset f.seek(0x18); int RTLOffset = f.readInt(); f.seek(RTLOffset); f.skip(0x030); int DataStart = f.readInt(); // //Console.WriteLine($"RLT {DataStart}"); List <buffData> BuffArr = new List <buffData>(); f.seek((int)FVTXArr[FSHPArr[m].fvtxIndx].buffArrOff); for (int buff = 0; buff < FVTXArr[FSHPArr[m].fvtxIndx].buffCount; buff++) { buffData data = new buffData(); f.seek((int)FVTXArr[FSHPArr[m].fvtxIndx].buffSizeOff + ((buff) * 0x10)); data.buffSize = f.readInt(); f.seek((int)FVTXArr[FSHPArr[m].fvtxIndx].buffStrideSizeOff + ((buff) * 0x10)); data.strideSize = f.readInt(); //So these work by grabbing the RLT offset first and then adding the buffer offset. Then they keep adding each other by their buffer sizes if (buff == 0) { data.DataOffset = (DataStart + FVTXArr[FSHPArr[m].fvtxIndx].buffOff); } if (buff > 0) { data.DataOffset = BuffArr[buff - 1].DataOffset + BuffArr[buff - 1].buffSize; } if (data.DataOffset % 8 != 0) { data.DataOffset = data.DataOffset + (8 - (data.DataOffset % 8)); } BuffArr.Add(data); // //Console.WriteLine("Data Offset = " + data.DataOffset + " Vertex Buffer Size =" + data.buffSize + " Index = " + buff + " vertexStrideSize size =" + data.strideSize); } for (int v = 0; v < FVTXArr[FSHPArr[m].fvtxIndx].vertCount; v++) { Vertex vert = new Vertex(); for (int attr = 0; attr < AttrArr.Count; attr++) { f.seek(((BuffArr[AttrArr[attr].buffIndx].DataOffset) + (AttrArr[attr].buffOff) + (BuffArr[AttrArr[attr].buffIndx].strideSize * v))); switch (AttrArr[attr].attName) { case "_p0": if (AttrArr[attr].vertType == 1301) { vert.pos = new Vector3 { X = f.readHalfFloat(), Y = f.readHalfFloat(), Z = f.readHalfFloat() } } ; if (AttrArr[attr].vertType == 1304) { vert.pos = new Vector3 { X = f.readFloat(), Y = f.readFloat(), Z = f.readFloat() } } ; break; case "_c0": if (AttrArr[attr].vertType == 1301) { vert.col = new Vector4(f.readHalfFloat(), f.readHalfFloat(), f.readHalfFloat(), f.readHalfFloat()); } if (AttrArr[attr].vertType == 2067) { vert.col = new Vector4 { X = f.readFloat(), Y = f.readFloat(), Z = f.readFloat(), W = f.readFloat() } } ; if (AttrArr[attr].vertType == 267) { vert.col = new Vector4(f.readByte() / 255f, f.readByte() / 255f, f.readByte() / 255f, f.readByte() / 255f); } break; case "_n0": if (AttrArr[attr].vertType == 526) { int normVal = (int)f.readInt(); //Thanks RayKoopa! vert.nrm = new Vector3 { X = sign10Bit((normVal) & 0x3FF) / (float)511, Y = sign10Bit((normVal >> 10) & 0x3FF) / (float)511, Z = sign10Bit((normVal >> 20) & 0x3FF) / (float)511 }; } break; case "_u0": case "color": case "_t0": case "_b0": case "_u1": case "_u2": case "_u3": if (AttrArr[attr].vertType == 265 || AttrArr[attr].vertType == 521) { vert.tx.Add(new Vector2 { X = ((float)f.readByte()) / 255, Y = ((float)f.readByte()) / 255 }); } if (AttrArr[attr].vertType == 274) { vert.tx.Add(new Vector2 { X = ((float)f.readShort()) / 65535, Y = ((float)f.readShort()) / 65535 }); } if (AttrArr[attr].vertType == 530) { vert.tx.Add(new Vector2 { X = ((float)f.readShort()) / 32767, Y = ((float)f.readShort()) / 32767 }); } if (AttrArr[attr].vertType == 1298) { vert.tx.Add(new Vector2 { X = f.readHalfFloat(), Y = f.readHalfFloat() }); } if (AttrArr[attr].vertType == 1303) { vert.tx.Add(new Vector2 { X = f.readFloat(), Y = f.readFloat() }); } break; case "_i0": if (AttrArr[attr].vertType == 770) { vert.node.Add(f.readByte()); vert.weight.Add((float)1.0); } if (AttrArr[attr].vertType == 777) { vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); } if (AttrArr[attr].vertType == 779) { vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); } if (AttrArr[attr].vertType == 523) { vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); vert.node.Add(f.readByte()); } break; case "_w0": if (AttrArr[attr].vertType == 258) { vert.weight.Add((f.readByte()) / (float)255); } if (AttrArr[attr].vertType == 265) { vert.weight.Add((f.readByte()) / (float)255); vert.weight.Add((f.readByte()) / (float)255); } if (AttrArr[attr].vertType == 267) { vert.weight.Add((f.readByte()) / (float)255); vert.weight.Add((f.readByte()) / (float)255); vert.weight.Add((f.readByte()) / (float)255); vert.weight.Add((f.readByte()) / (float)255); } if (AttrArr[attr].vertType == 274) { vert.weight.Add((f.readShort()) / (float)255); vert.weight.Add((f.readShort()) / (float)255); } break; default: // //Console.WriteLine(AttrArr[attr].attName + " Unknown type " + AttrArr[attr].vertType.ToString("x") + " 0x"); break; } } poly.vertices.Add(vert); } int LoadLOD = FSHPArr[m].lodMdlCount - 1; f.seek((int)FSHPArr[m].lodMdlOff); for (int lod = 0; lod < FSHPArr[m].lodMdlCount; lod++) { long SubMeshOff = f.readInt64(); long unk1 = f.readInt64(); long unk2 = f.readInt64(); long indxBuffOff = f.readInt64(); int FaceBuffer = f.readInt(); int PrimativefaceType = f.readInt(); int faceType = f.readInt(); int FaceCount = f.readInt(); int elmSkip = f.readInt(); int subMeshCount = f.readInt(); int temp = f.pos(); f.seek(FaceBuffer + DataStart); if (faceType == 1) { FaceCount = FaceCount / 3; } if (faceType == 2) { FaceCount = FaceCount / 6; } if (lod == LoadLOD) { for (int face = 0; face < FaceCount; face++) { if (faceType == 1) { poly.faces.Add(new List <int> { elmSkip + f.readShort(), elmSkip + f.readShort(), elmSkip + f.readShort() }); } else if (faceType == 2) { poly.faces.Add(new List <int> { elmSkip + f.readInt(), elmSkip + f.readInt(), elmSkip + f.readInt() }); } else { Console.Write("UnkFaceFormat"); } } } f.seek(temp); } f.seek((int)FMATheaders[FSHPArr[m].fmatIndx].texSelOff); List <string> MatTexList = new List <string>(); for (int tex = 0; FMATheaders[FSHPArr[m].fmatIndx].texAttSelCount > tex; tex++) { string TextureName = f.readString((int)f.readInt64() + 2, -1).ToLower(); MatTexList.Add(TextureName); } if (MatTexList.Count > 0) { poly.texNames.Add(MatTexList[0]); } //Console.WriteLine(String.Join(",",MatTexList)); model.poly.Add(poly); } models.Add(model); f.seek(NextFMDL); } } }
public void ReadNTP3(FileData d) { d.seek(0x4); Version = d.readUShort(); ushort count = d.readUShort(); if (Version == 0x100) { count -= 1; } d.skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.seek(headerPtr); NutTexture tex = new NutTexture(); tex.isDds = true; tex.pixelInternalFormat = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); int dataSize = d.readInt(); int headerSize = d.readUShort(); d.skip(2); //It might seem that mipmapCount and pixelFormat would be shorts, but they're bytes because they stay in the same place regardless of endianness d.skip(1); byte mipmapCount = d.readByte(); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readUShort(); tex.Height = d.readUShort(); d.skip(4); uint caps2 = d.readUInt(); bool isCubemap = false; byte surfaceCount = 1; if ((caps2 & (uint)DDS.DDSCAPS2.CUBEMAP) == (uint)DDS.DDSCAPS2.CUBEMAP) { //Only supporting all six faces if ((caps2 & (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES) == (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES) { isCubemap = true; surfaceCount = 6; } else { throw new NotImplementedException($"Unsupported cubemap face amount for texture {i} with hash 0x{tex.HashId:X}. Six faces are required."); } } int dataOffset = d.readInt() + headerPtr; d.readInt(); d.readInt(); d.readInt(); //The size of a single cubemap face (discounting mipmaps). I don't know why it is repeated. If mipmaps are present, this is also specified in the mipSize section anyway. int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.readInt(); cmapSize2 = d.readInt(); d.skip(8); } int[] mipSizes = new int[mipmapCount]; if (mipmapCount == 1) { if (isCubemap) { mipSizes[0] = cmapSize1; } else { mipSizes[0] = dataSize; } } else { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { mipSizes[mipLevel] = d.readInt(); } d.align(0x10); } d.skip(0x10); //eXt data - always the same d.skip(4); //GIDX d.readInt(); //Always 0x10 tex.HashId = d.readInt(); d.skip(4); // padding align 8 if (Version == 0x100) { dataOffset = d.pos(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { TextureSurface surface = new TextureSurface(); for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { byte[] texArray = d.getSection(dataOffset, mipSizes[mipLevel]); surface.mipmaps.Add(texArray); dataOffset += mipSizes[mipLevel]; } tex.surfaces.Add(surface); } if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { tex.SwapChannelOrderUp(); } headerPtr += headerSize; Nodes.Add(tex); } }
public void readKeyFrame(FileData d, int length, int dataoff, int valueFormat, int tanFormat, int keyframeCount, int boneId, int trackType) { int temp = d.pos(); d.seek(dataoff); if (Debug) { Console.WriteLine("Start 0x" + d.pos() + " " + keyframeCount); } DATAnimTrack track = new DATAnimTrack(); track.type = (AnimType)trackType; nodes[boneId].Add(track); while (d.pos() < dataoff + length) { int type = readExtendedByte(d); int interpolation = ((type) & 0x0F); int numOfKey = ((type >> 4) & 0xFF) + 1; if (Debug) { Console.WriteLine("Interpolation type: " + (InterpolationType)interpolation + "\tnumofkey: " + numOfKey); } for (int i = 0; i < numOfKey; i++) { double value = -99, tan = -99; int time = 0; if (interpolation == 1) { // step value = readVal(d, valueFormat); time = readExtendedByte(d); if (Debug) { Console.WriteLine("\t" + value + "\t" + time); } } if (interpolation == 2) { // linear value = readVal(d, valueFormat); time = readExtendedByte(d); //Console.WriteLine("\t" + value + "\t" + time); } if (interpolation == 3) { // hermite value = readVal(d, valueFormat); tan = 0; time = readExtendedByte(d); if (Debug) { Console.WriteLine("\t" + value + "\t" + time); } } if (interpolation == 4) { // hermite value = readVal(d, valueFormat); tan = readVal(d, tanFormat); time = readExtendedByte(d); if (Debug) { Console.WriteLine("\t" + value + "\t" + tan + "\t" + time); } } if (interpolation == 5) { // hermite tan = readVal(d, tanFormat); if (Debug) { Console.WriteLine("\t" + "Tan" + tan); } } if (interpolation == 6) { // constant value = readVal(d, valueFormat); time = readExtendedByte(d); //Console.WriteLine("\t" + value + "\t" + time); } KeyNode node = new KeyNode(); node.value = (float)value; node.frame = time; node.tan = (float)tan; node.interpolationType = (InterpolationType)interpolation; track.keys.Add(node); //node.boneID = boneId; } d.Endian = System.IO.Endianness.Big; } //Console.WriteLine("Ends at: " + (d.pos() + 8 - (d.pos() % 8)).ToString("x")); d.seek(temp); }
/** * Reading and saving -------------------- **/ public override void Read(string filename) { FileData d = new FileData(filename); d.seek(0); d.Endian = Endianness.Little; format = d.readShort(); unkown = (ushort)d.readShort(); flags = d.readInt(); mode = d.readInt(); bool hasNameTable = (flags & 2) > 0; int polyCount = d.readInt(); mesh = new List <Mesh>(); descript = new List <Descriptor>(); List <List <int> > prim = new List <List <int> >(); for (int i = 0; i < polyCount; i++) { if (i == 0 && mode == 1) { Descriptor des = new Descriptor(); des.ReadDescription(d); descript.Add(des); } Mesh m = new Mesh(); mesh.Add(m); int faceCount = d.readInt(); List <int> prims = new List <int>(); prim.Add(prims); for (int j = 0; j < faceCount; j++) { int nodeCount = d.readInt(); List <int> nodeList = new List <int>(); m.nodeList.Add(nodeList); for (int k = 0; k < nodeCount; k++) { nodeList.Add(d.readInt()); // for a node list? } int primitiveCount = d.readInt(); prims.Add(primitiveCount); if (hasNameTable) { int nameId = d.readInt(); } if (mode == 0) { if (format == 4) { int[] buffer = new int[primitiveCount]; for (int k = 0; k < primitiveCount; k++) { buffer[k] = d.readShort(); } d.align(4); List <int> buf = new List <int>(); buf.AddRange(buffer); m.faces.Add(buf); } else { Descriptor des = new Descriptor(); des.ReadDescription(d); descript.Add(des); } } } } if (mode == 0) { //Console.WriteLine("Extra!"); } // TODO: STRING TABLE if (hasNameTable) { for (int i = 0; i < mesh.Count; i++) { int index = d.readByte(); nameTable.Add(d.readString()); } } if (format != 4) { d.align(32); } // Vertex Bank int start = d.pos(); for (int i = 0; i < 1; i++) { if (mode == 0 || i == 0) { Descriptor des = descript[i]; if (format != 4) { while (d.pos() < start + des.length) { Vertex v = new Vertex(); vertices.Add(v); for (int k = 0; k < des.type.Length; k++) { d.align(2); switch (des.type[k]) { case 0: //Position v.pos.X = readType(d, des.format[k], des.scale[k]); v.pos.Y = readType(d, des.format[k], des.scale[k]); v.pos.Z = readType(d, des.format[k], des.scale[k]); break; case 1: //Normal v.nrm.X = readType(d, des.format[k], des.scale[k]); v.nrm.Y = readType(d, des.format[k], des.scale[k]); v.nrm.Z = readType(d, des.format[k], des.scale[k]); break; case 2: //Color v.col.X = (int)(readType(d, des.format[k], des.scale[k])); v.col.Y = (int)(readType(d, des.format[k], des.scale[k])); v.col.Z = (int)(readType(d, des.format[k], des.scale[k])); v.col.W = (int)(readType(d, des.format[k], des.scale[k])); break; case 3: //Tex0 v.tx.Add(new Vector2(readType(d, des.format[k], des.scale[k]), readType(d, des.format[k], des.scale[k]))); break; case 4: //Tex1 v.tx.Add(new Vector2(readType(d, des.format[k], des.scale[k]), readType(d, des.format[k], des.scale[k]))); break; case 5: //Bone Index v.node.Add(d.readByte()); v.node.Add(d.readByte()); break; case 6: //Bone Weight v.weight.Add(readType(d, des.format[k], des.scale[k])); v.weight.Add(readType(d, des.format[k], des.scale[k])); break; //default: // Console.WriteLine("WTF is this"); } } } d.align(32); } } for (int j = 0; j < mesh.Count; j++) { foreach (int l in prim[j]) { List <int> face = new List <int>(); mesh[j].faces.Add(face); for (int k = 0; k < l; k++) { face.Add(d.readShort()); } d.align(32); } } } PreRender(); }
public void ReadNTP3(FileData d) { Version = d.readShort(); int count = d.readShort(); d.skip(0x8); if (Version == 0x100) { count -= 1; } int dataPtr = 0; for (int i = 0; i < count; i++) { //Debug.WriteLine(d.pos().ToString("x")); NutTexture tex = new NutTexture(); tex.type = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); // padding int dataSize = d.readInt(); int headerSize = d.readShort(); d.skip(3); int numMips = d.readByte(); //Debug.WriteLine(numMips); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readShort(); tex.Height = d.readShort(); d.skip(8); // padding? int dataOffset = d.readInt() + dataPtr + 0x10; d.skip(0x0C); int[] mipSizes = new int[numMips]; if (numMips == 1) { mipSizes[0] = dataSize; } else { for (int j = 0; j < numMips; j++) { mipSizes[j] = d.readInt(); } } d.align(16); d.skip(0x18); tex.HASHID = d.readInt(); d.skip(4); // padding align 8 if (Version == 0x100) { dataOffset = d.pos(); } // add mipmap data for (int miplevel = 0; miplevel < numMips; miplevel++) { byte[] texArray = d.getSection(dataOffset, mipSizes[miplevel]); //Debug.WriteLine(texArray.Length.ToString("x")); tex.mipmaps.Add(texArray); dataOffset += mipSizes[miplevel]; } dataPtr += headerSize; if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { Console.WriteLine("Endian swap"); // swap foreach (byte[] mip in tex.mipmaps) { for (int t = 0; t < mip.Length; t += 4) { byte t1 = mip[t]; mip[t] = mip[t + 1]; mip[t + 1] = mip[t + 2]; mip[t + 2] = mip[t + 3]; mip[t + 3] = t1; /*byte t1 = mip[t]; * byte t2 = mip[t+1]; * mip[t] = mip[t + 3]; * mip[t + 1] = mip[t + 2]; * mip[t + 2] = t2; * mip[t + 3] = t1;*/ } } } Nodes.Add(tex); /*for (int miplevel = 0; miplevel < numMips; miplevel++) * { * byte[] texArray = d.getSection(dataOffset, mipSizes[miplevel]); * * if (tex.getNutFormat() == 14) * { * byte[] oldArray = texArray; * for (int pos = 0; pos < mipSizes[miplevel]; pos+=4) * { * * for (int p = 0; p < 4; p++) * { * if (p == 0) * texArray[pos + 3] = oldArray[pos]; * else * texArray[pos + p - 1] = oldArray[pos + p]; * } * * } * } * tex.mipmaps.Add(texArray); * dataOffset += mipSizes[miplevel]; * }*/ } foreach (NutTexture tex in Nodes) { if (!draw.ContainsKey(tex.HASHID)) { draw.Add(tex.HASHID, loadImage(tex, true)); } } }
public void Read(FileData f) { f.Endian = Endianness.Little; f.seek(4); int count = f.readInt(); f.skip(12); int dataCount = f.readInt(); int boneCount = f.readInt(); int hashCount = f.readInt(); int hashOffset = f.readInt() + 0x28; f.skip(4); Console.WriteLine("Count " + count); for (int i = 0; i < dataCount; i++) { Console.WriteLine("Bone " + i + " start at " + f.pos().ToString("x")); // 3 sections int secLength = f.readInt(); int someCount = f.readInt(); // usually 2? int size1 = f.readInt(); Console.Write(size1 + "\t"); for (int j = 0; j < (size1 / 4) - 1; j++) Console.Write(f.readShort() + " " + f.readShort() + "\t"); Console.WriteLine(); int size2 = f.readInt(); Console.Write(size2 + "\t"); for (int j = 0; j < (size2 / 4) - 1; j++) Console.Write(f.readShort() + " " + f.readShort() + "\t"); Console.WriteLine(); int size3 = f.readInt(); Console.Write(size3 + "\t"); for (int j = 0; j < (size3 / 4) - 1; j++) Console.Write(f.readShort() + " " + f.readShort() + "\t"); Console.WriteLine(); int size4 = f.readInt(); Console.Write(size4 + "\t"); for (int j = 0; j < (size4 / 4) - 1; j++) Console.Write(f.readShort() + " " + f.readShort() + "\t"); Console.WriteLine(); int size5 = f.readInt(); Console.Write(size5 + "\t"); for (int j = 0; j < (size5 / 4) - 1; j++) Console.Write(f.readShort() + " " + f.readShort() + "\t"); Console.WriteLine(); f.skip(8); } Console.WriteLine("0x" + f.pos().ToString("X")); f.skip(8); int hashSize = f.readInt(); int unk = f.readInt(); for (int i = 0; i < hashCount; i++) { Console.WriteLine(f.readInt().ToString("X")); } }
public override void Read(string filename) { FileData f = new FileData(filename); header.magic = f.readInt(); header.unk0 = f.readInt(); if (header.unk0 == 0x10000000) { f.Endian = Endianness.Little; f.skip(f.pos() - 4); header.unk0 = f.readInt(); } header.unk1 = f.readInt(); header.unk2 = f.readInt(); header.unk3 = f.readInt(); header.unk4 = f.readInt(); header.unk5 = f.readInt(); header.filesize = f.readInt(); header.unk6 = f.readInt(); header.unk7 = f.readInt(); header.unk8 = f.readInt(); header.unk9 = f.readInt(); header.unk10 = f.readInt(); header.unk11 = f.readInt(); header.unk12 = f.readInt(); header.unk13 = f.readInt(); bool done = false; while (!done) { int tagOffset = f.pos(); TagType tagType = (TagType)f.readInt(); int tagSize = f.readInt(); // in dwords! switch (tagType) { case TagType.Invalid: { // uhhh. i think there's a specific exception for this throw new Exception("Malformed file"); } case TagType.Symbols: { int numSymbols = f.readInt(); while (Strings.Count < numSymbols) { int len = f.readInt(); Strings.Add(f.readString()); f.skip(4 - (f.pos() % 4)); } break; } case TagType.Colors: { int numColors = f.readInt(); for (int i = 0; i < numColors; i++) { AddColor(new Vector4(f.readShort() / 256f, f.readShort() / 256f, f.readShort() / 256f, f.readShort() / 256f)); } break; } case TagType.Fonts: { unk000A = new UnhandledTag(tagType, tagSize, f); break; } case TagType.UnkF00A: { unkF00A = new UnhandledTag(tagType, tagSize, f); break; } case TagType.UnkF00B: { unkF00B = new UnhandledTag(tagType, tagSize, f); break; } case TagType.UnkF008: { unkF008 = new UnhandledTag(tagType, tagSize, f); break; } case TagType.UnkF009: { unkF009 = new UnhandledTag(tagType, tagSize, f); break; } case TagType.Defines: { Defines = new Properties2(f); break; } case TagType.ActionScript: { Actionscript = new UnhandledTag(tagType, tagSize, f); break; } case TagType.ActionScript2: { Actionscript2 = new UnhandledTag(tagType, tagSize, f); break; } case TagType.End: { done = true; break; } case TagType.Transforms: { int numTransforms = f.readInt(); for (int i = 0; i < numTransforms; i++) { float a = f.readFloat(); float b = f.readFloat(); float c = f.readFloat(); float d = f.readFloat(); float x = f.readFloat(); float y = f.readFloat(); var mat = new Matrix4( a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, x, y, 0, 1 ); Transforms.Add(mat); } break; } case TagType.Positions: { int numPositions = f.readInt(); for (int i = 0; i < numPositions; i++) { Positions.Add(new Vector2(f.readFloat(), f.readFloat())); } break; } case TagType.Bounds: { int numBounds = f.readInt(); for (int i = 0; i < numBounds; i++) { Bounds.Add(new Rect(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat())); } break; } case TagType.Properties: { properties = new Properties(f); break; } case TagType.TextureAtlases: { int numAtlases = f.readInt(); for (int i = 0; i < numAtlases; i++) { TextureAtlas atlas = new TextureAtlas(); atlas.id = f.readInt(); atlas.nameId = f.readInt(); atlas.width = f.readFloat(); atlas.height = f.readFloat(); Atlases.Add(atlas); } break; } case TagType.Shape: { Shapes.Add(new Shape(f)); break; } case TagType.DynamicText: { Texts.Add(new DynamicText(f)); break; } case TagType.DefineSprite: { Sprites.Add(new Sprite(f)); break; } default: { throw new NotImplementedException($"Unhandled tag id: 0x{(uint)tagType:X} @ 0x{tagOffset:X}"); } } } } // Read()
public override void Read(string filename) { bchHeader header = new bchHeader(); FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(4); header.backwardCompatibility = f.readByte(); header.forwardCompatibility = f.readByte(); header.version = f.readShort(); header.mainHeaderOffset = f.readInt(); header.stringTableOffset = f.readInt(); header.gpuCommandsOffset = f.readInt(); header.dataOffset = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedOffset = f.readInt(); } header.relocationTableOffset = f.readInt(); header.mainHeaderLength = f.readInt(); header.stringTableLength = f.readInt(); header.gpuCommandsLength = f.readInt(); header.dataLength = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedLength = f.readInt(); } header.relocationTableLength = f.readInt(); header.uninitializedDataSectionLength = f.readInt(); header.uninitializedDescriptionSectionLength = f.readInt(); if (header.backwardCompatibility > 7) { header.flags = f.readShort(); header.addressCount = f.readShort(); } // TODO: Finished Relocation table stuff for (int i = 0; i < header.relocationTableLength; i += 4) { f.seek(header.relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.mainHeaderOffset); break; case 1: f.seek(off + header.mainHeaderOffset); f.writeInt((off) + header.mainHeaderOffset, f.readInt() + header.stringTableOffset); break; case 2: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.gpuCommandsOffset); break; case 0xc: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; } /*f.seek((off * 4) + header.gpuCommandsOffset); * if (header.backwardCompatibility < 6) * { * switch (flag) * { * case 0x23: f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; //Texture * case 0x25: f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; //Vertex * // Trying to understand the mess first * case 0x26: f.writeInt((off * 4) + header.mainHeaderOffset, Convert.ToInt32(((f.readInt() + header.dataOffset) & 0x7fffffff) | 0x80000000)); break; //Index 16 bits mode * //case 0x27: writer.Write((peek(input) + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode * } * } * else if (header.backwardCompatibility < 8) * { * switch (flag) * { * case 0x24: writer.Write(peek(input) + header.dataOffset); break; //Texture * case 0x26: writer.Write(peek(input) + header.dataOffset); break; //Vertex * case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode * case 0x28: writer.Write((peek(input) + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode * } * } * else if (header.backwardCompatibility < 0x21) * { * switch (flag) * { * case 0x25: writer.Write(peek(input) + header.dataOffset); break; //Texture * case 0x27: writer.Write(peek(input) + header.dataOffset); break; //Vertex * case 0x28: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode * case 0x29: writer.Write((peek(input) + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode * } * } * else * { * switch (flag) * { * case 0x25: writer.Write(peek(input) + header.dataOffset); break; //Texture * case 0x26: writer.Write(peek(input) + header.dataOffset); break; //Vertex relative to Data Offset * case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset * case 0x28: writer.Write((peek(input) + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset * case 0x2b: writer.Write(peek(input) + header.dataExtendedOffset); break; //Vertex relative to Data Extended Offset * case 0x2c: writer.Write(((peek(input) + header.dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset * case 0x2d: writer.Write((peek(input) + header.dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset * } * } */ } // Content Header f.seek(header.mainHeaderOffset); bchContentHeader content = new bchContentHeader(); { content.modelsPointerTableOffset = f.readInt(); content.modelsPointerTableEntries = f.readInt(); content.modelsNameOffset = f.readInt(); content.materialsPointerTableOffset = f.readInt(); content.materialsPointerTableEntries = f.readInt(); content.materialsNameOffset = f.readInt(); content.shadersPointerTableOffset = f.readInt(); content.shadersPointerTableEntries = f.readInt(); content.shadersNameOffset = f.readInt(); content.texturesPointerTableOffset = f.readInt(); content.texturesPointerTableEntries = f.readInt(); content.texturesNameOffset = f.readInt(); content.materialsLUTPointerTableOffset = f.readInt(); content.materialsLUTPointerTableEntries = f.readInt(); content.materialsLUTNameOffset = f.readInt(); content.lightsPointerTableOffset = f.readInt(); content.lightsPointerTableEntries = f.readInt(); content.lightsNameOffset = f.readInt(); content.camerasPointerTableOffset = f.readInt(); content.camerasPointerTableEntries = f.readInt(); content.camerasNameOffset = f.readInt(); content.fogsPointerTableOffset = f.readInt(); content.fogsPointerTableEntries = f.readInt(); content.fogsNameOffset = f.readInt(); content.skeletalAnimationsPointerTableOffset = f.readInt(); content.skeletalAnimationsPointerTableEntries = f.readInt(); content.skeletalAnimationsNameOffset = f.readInt(); content.materialAnimationsPointerTableOffset = f.readInt(); content.materialAnimationsPointerTableEntries = f.readInt(); content.materialAnimationsNameOffset = f.readInt(); content.visibilityAnimationsPointerTableOffset = f.readInt(); content.visibilityAnimationsPointerTableEntries = f.readInt(); content.visibilityAnimationsNameOffset = f.readInt(); content.lightAnimationsPointerTableOffset = f.readInt(); content.lightAnimationsPointerTableEntries = f.readInt(); content.lightAnimationsNameOffset = f.readInt(); content.cameraAnimationsPointerTableOffset = f.readInt(); content.cameraAnimationsPointerTableEntries = f.readInt(); content.cameraAnimationsNameOffset = f.readInt(); content.fogAnimationsPointerTableOffset = f.readInt(); content.fogAnimationsPointerTableEntries = f.readInt(); content.fogAnimationsNameOffset = f.readInt(); content.scenePointerTableOffset = f.readInt(); content.scenePointerTableEntries = f.readInt(); content.sceneNameOffset = f.readInt(); } //Shaders (unused for now, until someone wants to add them) for (int index = 0; index < content.shadersPointerTableEntries; index++) { f.seek(content.shadersPointerTableOffset + (index * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); int shaderDataOffset = f.readInt(); int shaderDataLength = f.readInt(); } // Textures // WIP Section for (int index = 0; index < content.texturesPointerTableEntries; index++) { f.seek(content.texturesPointerTableOffset + (index * 4)); int dOffset = f.readInt(); f.seek(dOffset); Debug.WriteLine("dOffset: " + dOffset.ToString("X")); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); f.seek(f.pos() + 0x14); String textureName = f.readString(f.readInt(), -1); //Debug.WriteLine("gpuCommandOffset: " + header.gpuCommandsOffset.ToString("X")); f.seek(textureCommandsOffset); //Debug.WriteLine("textureCommandOffset: " + textureCommandsOffset.ToString("X")); BCH_Texture tex = new BCH_Texture(); textures.Add(textureName, tex); tex.height = f.readShort(); tex.width = f.readShort(); f.skip(12); int doffset = f.readInt(); //Debug.WriteLine("doffset: " + doffset.ToString("X")); f.skip(4); tex.type = f.readInt(); tex.data = f.getSection(doffset, f.size() - doffset); if (tex.type == 12) { tex.display = NUT.loadImage(Pixel.decodeETC(tex.data, tex.width, tex.height)); } } // Model data for (int modelIndex = 0; modelIndex < content.modelsPointerTableEntries; modelIndex++) { f.seek(content.modelsPointerTableOffset + (modelIndex * 4)); int objectsHeaderOffset = f.readInt(); // Objects f.seek(objectsHeaderOffset); BCH_Model model = new BCH_Model(); models.Add(model); model.flags = f.readByte(); model.skeletonScaleType = f.readByte(); model.silhouetteMaterialEntries = f.readShort(); model.worldTransform = new Matrix4(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , 0, 0, 0, 1); model.materialsTableOffset = f.readInt(); model.materialsTableEntries = f.readInt(); model.materialsNameOffset = f.readInt(); model.verticesTableOffset = f.readInt(); //Debug.WriteLine("Mesh Count: " + f.pos().ToString("X")); model.verticesTableEntries = f.readInt(); f.skip(0x28); model.skeletonOffset = f.readInt(); model.skeletonEntries = f.readInt(); model.skeletonNameOffset = f.readInt(); model.objectsNodeVisibilityOffset = f.readInt(); model.objectsNodeCount = f.readInt(); model.name = f.readString(f.readInt(), -1); model.objectsNodeNameEntries = f.readInt(); model.objectsNodeNameOffset = f.readInt(); f.readInt(); //0x0 model.metaDataPointerOffset = f.readInt(); f.seek(model.objectsNodeVisibilityOffset); int nodeVisibility = f.readInt(); string[] objectName = new string[model.objectsNodeNameEntries]; f.seek(model.objectsNodeNameOffset); int rootReferenceBit = f.readInt(); //Radix tree int rootLeftNode = f.readShort(); int rootRightNode = f.readShort(); int rootNameOffset = f.readInt() + header.mainHeaderOffset; for (int i = 0; i < model.objectsNodeNameEntries; i++) { int referenceBit = f.readInt(); short leftNode = (short)f.readShort(); short rightNode = (short)f.readShort(); objectName[i] = f.readString(f.readInt(), -1); //Debug.WriteLine(objectName[i]); } // Materials // NOTE: MATERIALS AND OBJECT SECTIONS ARE REALLY MESSY ATM String[] materialNames = new String[model.materialsTableEntries]; for (int index = 0; index < model.materialsTableEntries; index++) { f.seek(model.materialsTableOffset + (index * 0x2c)); int materialParametersOffset = f.readInt(); f.readInt(); f.readInt(); f.readInt(); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); int materialMapperOffset = f.readInt(); materialNames[index] = f.readString(f.readInt(), -1); } // Object Descriptions... // Assumes MBN is already loaded for now f.seek(model.verticesTableOffset); List <objDes> objDescriptors = new List <objDes>(); Debug.WriteLine(model.name); if (mbn == null) { mbn = new Smash_Forge.MBN(); for (int index = 0; index < model.verticesTableEntries; index++) { mbn.mesh.Add(new MBN.Mesh()); } mbn.PreRender(); } for (int index = 0; index < mbn.mesh.Count; index++) { int i = f.readShort(); if (index > mbn.mesh.Count) { break; } if (i > materialNames.Length) { break; } mbn.mesh[index].texId = textures[materialNames[i]].display; Console.WriteLine("Tex index" + mbn.mesh[index].texId); f.skip(2); // flags int nameId = f.readShort(); mbn.mesh[index].name = objectName[nameId]; // node visibility TODO: finish... //mbn.mesh[index].isVisible = ((nodeVisibility & (1 << nameId)) > 0); mbn.mesh[index].renderPriority = f.readShort(); objDes des = new objDes(); objDescriptors.Add(des); des.vshAttBufferCommandOffset = f.readInt(); des.vshAttBufferCommandCount = f.readInt(); des.faceOffset = f.readInt(); des.faceCount = f.readInt(); des.vshAttBufferCommandOffsetEx = f.readInt(); des.vshAttBufferCommandCountEx = f.readInt(); f.skip(12); // center vector f.skip(4); // flagsOffset f.skip(4); // 0? f.readInt(); //bbOffsets[i] = + mainheaderOffset //Debug.WriteLine(des.vshAttBufferCommandOffset.ToString("X")); } //Skeleton f.seek(model.skeletonOffset); for (int index = 0; index < model.skeletonEntries; index++) { Bone bone = new Smash_Forge.Bone(model.skeleton); int boneFlags = f.readInt(); bone.parentIndex = (short)f.readShort(); short boneSpace = (short)f.readShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.readFloat(); bone.scale[1] = f.readFloat(); bone.scale[2] = f.readFloat(); bone.rotation[0] = f.readFloat(); bone.rotation[1] = f.readFloat(); bone.rotation[2] = f.readFloat(); bone.position[0] = f.readFloat(); bone.position[1] = f.readFloat(); bone.position[2] = f.readFloat(); // bone matrix... not really needed to be stored per say f.skip(4 * 4 * 3); bone.boneName = f.readString(f.readInt(), -1).ToCharArray(); f.skip(4); // Meta data model.skeleton.bones.Add(bone); } model.skeleton.reset(); /* //Skeletal Animations * * SkelAnimation anim = new SkelAnimation(); * * for (int index = 0; index < content.skeletalAnimationsPointerTableEntries; index++) * { * f.seek(content.skeletalAnimationsPointerTableOffset + (index * 4)); * int dataOffset = f.readInt(); * f.seek(dataOffset); * * RenderBase.OSkeletalAnimation skeletalAnimation = new RenderBase.OSkeletalAnimation(); * * skeletalAnimation.name = f.readString(f.readInt(), -1); * int animationFlags = f.readInt(); * skeletalAnimation.loopMode = (RenderBase.OLoopMode)(animationFlags & 1); * skeletalAnimation.frameSize = f.readFloat(); * int boneTableOffset = f.readInt(); * int boneTableEntries = f.readInt(); * int metaDataPointerOffset = f.readInt(); * * // /*if (metaDataPointerOffset != 0) * // { * // data.Seek(metaDataPointerOffset, SeekOrigin.Begin); * // skeletalAnimation.userData = getMetaData(input); * // } * * for (int i = 0; i < boneTableEntries; i++) * { * f.seek(boneTableOffset + (i * 4)); * int offset = f.readInt(); * * RenderBase.OSkeletalAnimationBone bone = new RenderBase.OSkeletalAnimationBone(); * * f.seek(offset); * bone.name = f.readString(f.readInt(), -1); * int animationTypeFlags = f.readInt(); * * int flags = f.readInt(); * * RenderBase.OSegmentType segmentType = (RenderBase.OSegmentType)((animationTypeFlags >> 16) & 0xf); * switch (segmentType) * { * case RenderBase.OSegmentType.transform: * f.seek(offset + 0x18); * * uint notExistMask = 0x80000; * uint constantMask = 0x200; * * for (int j = 0; j < 2; j++) * { * for (int axis = 0; axis < 3; axis++) * { * bool notExist = (flags & notExistMask) > 0; * bool constant = (flags & constantMask) > 0; * * RenderBase.OAnimationKeyFrameGroup frame = new RenderBase.OAnimationKeyFrameGroup(); * frame.exists = !notExist; * if (frame.exists) * { * if (constant) * { * frame.interpolation = RenderBase.OInterpolationMode.linear; * frame.keyFrames.Add(new RenderBase.OAnimationKeyFrame(input.ReadSingle(), 0)); * } * else * { * int frameOffset = f.readInt(); * long position = data.Position; * f.seek(frameOffset); * getAnimationKeyFrame(input, frame); * f.seek(position); * } * } * else * data.Seek(4, SeekOrigin.Current); * * if (j == 0) * { * switch (axis) * { * case 0: bone.rotationX = frame; break; * case 1: bone.rotationY = frame; break; * case 2: bone.rotationZ = frame; break; * } * } * else * { * switch (axis) * { * case 0: bone.translationX = frame; break; * case 1: bone.translationY = frame; break; * case 2: bone.translationZ = frame; break; * } * } * * notExistMask <<= 1; * constantMask <<= 1; * } * * constantMask <<= 1; * } * * break; * case RenderBase.OSegmentType.transformQuaternion: * bone.isFrameFormat = true; * * uint scaleOffset = input.ReadUInt32(); * uint rotationOffset = input.ReadUInt32(); * uint translationOffset = input.ReadUInt32(); * * if ((flags & 0x20) == 0) * { * bone.scale.exists = true; * data.Seek(scaleOffset, SeekOrigin.Begin); * * if ((flags & 4) > 0) * { * bone.scale.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * 0)); * } * else * { * bone.scale.startFrame = input.ReadSingle(); * bone.scale.endFrame = input.ReadSingle(); * * uint scaleFlags = input.ReadUInt32(); * uint scaleDataOffset = input.ReadUInt32(); * uint scaleEntries = input.ReadUInt32(); * * data.Seek(scaleDataOffset, SeekOrigin.Begin); * for (int j = 0; j < scaleEntries; j++) * { * bone.scale.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * 0)); * } * } * } * * if ((flags & 0x10) == 0) * { * bone.rotationQuaternion.exists = true; * data.Seek(rotationOffset, SeekOrigin.Begin); * * if ((flags & 2) > 0) * { * bone.rotationQuaternion.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle())); * } * else * { * bone.rotationQuaternion.startFrame = input.ReadSingle(); * bone.rotationQuaternion.endFrame = input.ReadSingle(); * * uint rotationFlags = input.ReadUInt32(); * uint rotationDataOffset = input.ReadUInt32(); * uint rotationEntries = input.ReadUInt32(); * * data.Seek(rotationDataOffset, SeekOrigin.Begin); * for (int j = 0; j < rotationEntries; j++) * { * bone.rotationQuaternion.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle())); * } * } * } * * if ((flags & 8) == 0) * { * bone.translation.exists = true; * data.Seek(translationOffset, SeekOrigin.Begin); * * if ((flags & 1) > 0) * { * bone.translation.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * 0)); * } * else * { * bone.translation.startFrame = input.ReadSingle(); * bone.translation.endFrame = input.ReadSingle(); * * uint translationFlags = input.ReadUInt32(); * uint translationDataOffset = input.ReadUInt32(); * uint translationEntries = input.ReadUInt32(); * * data.Seek(translationDataOffset, SeekOrigin.Begin); * for (int j = 0; j < translationEntries; j++) * { * bone.translation.vector.Add(new RenderBase.OVector4( * input.ReadSingle(), * input.ReadSingle(), * input.ReadSingle(), * 0)); * } * } * } * * break; * case RenderBase.OSegmentType.transformMatrix: * bone.isFullBakedFormat = true; * * input.ReadUInt32(); * input.ReadUInt32(); * uint matrixOffset = input.ReadUInt32(); * uint entries = input.ReadUInt32(); * * data.Seek(matrixOffset, SeekOrigin.Begin); * for (int j = 0; j < entries; j++) * { * RenderBase.OMatrix transform = new RenderBase.OMatrix(); * transform.M11 = input.ReadSingle(); * transform.M21 = input.ReadSingle(); * transform.M31 = input.ReadSingle(); * transform.M41 = input.ReadSingle(); * * transform.M12 = input.ReadSingle(); * transform.M22 = input.ReadSingle(); * transform.M32 = input.ReadSingle(); * transform.M42 = input.ReadSingle(); * * transform.M13 = input.ReadSingle(); * transform.M23 = input.ReadSingle(); * transform.M33 = input.ReadSingle(); * transform.M43 = input.ReadSingle(); * * bone.transform.Add(transform); * } * * break; * default: throw new Exception(string.Format("BCH: Unknow Segment Type {0} on Skeletal Animation bone {1}! STOP!", segmentType, bone.name)); * } * * skeletalAnimation.bone.Add(bone); * } * * models.skeletalAnimation.list.Add(skeletalAnimation); * } * * //Material Animations * for (int index = 0; index < contentHeader.materialAnimationsPointerTableEntries; index++) * { * data.Seek(contentHeader.materialAnimationsPointerTableOffset + (index * 4), SeekOrigin.Begin); * uint dataOffset = input.ReadUInt32(); * data.Seek(dataOffset, SeekOrigin.Begin); * * RenderBase.OMaterialAnimation materialAnimation = new RenderBase.OMaterialAnimation(); * * materialAnimation.name = readString(input); * uint animationFlags = input.ReadUInt32(); * materialAnimation.loopMode = (RenderBase.OLoopMode)(animationFlags & 1); * materialAnimation.frameSize = input.ReadSingle(); * uint dataTableOffset = input.ReadUInt32(); * uint dataTableEntries = input.ReadUInt32(); * input.ReadUInt32(); * uint textureNameTableOffset = input.ReadUInt32(); * uint textureNameTableEntries = input.ReadUInt32(); * * data.Seek(textureNameTableOffset, SeekOrigin.Begin); * for (int i = 0; i < textureNameTableEntries; i++) * { * string name = readString(input); * materialAnimation.textureName.Add(name); * } * * for (int i = 0; i < dataTableEntries; i++) * { * data.Seek(dataTableOffset + (i * 4), SeekOrigin.Begin); * uint offset = input.ReadUInt32(); * * RenderBase.OMaterialAnimationData animationData = new RenderBase.OMaterialAnimationData(); * * data.Seek(offset, SeekOrigin.Begin); * animationData.name = readString(input); * uint animationTypeFlags = input.ReadUInt32(); * uint flags = input.ReadUInt32(); * * animationData.type = (RenderBase.OMaterialAnimationType)(animationTypeFlags & 0xff); * RenderBase.OSegmentType segmentType = (RenderBase.OSegmentType)((animationTypeFlags >> 16) & 0xf); * * int segmentCount = 0; * switch (segmentType) * { * case RenderBase.OSegmentType.rgbaColor: segmentCount = 4; break; * case RenderBase.OSegmentType.vector2: segmentCount = 2; break; * case RenderBase.OSegmentType.single: segmentCount = 1; break; * case RenderBase.OSegmentType.integer: segmentCount = 1; break; * } * * for (int j = 0; j < segmentCount; j++) * { * RenderBase.OAnimationKeyFrameGroup frame = new RenderBase.OAnimationKeyFrameGroup(); * * data.Seek(offset + 0xc + (j * 4), SeekOrigin.Begin); * * frame.exists = (flags & (0x100 << j)) == 0; * bool constant = (flags & (1 << j)) > 0; * * if (frame.exists) * { * if (constant) * { * frame.interpolation = RenderBase.OInterpolationMode.linear; * frame.keyFrames.Add(new RenderBase.OAnimationKeyFrame(input.ReadSingle(), 0)); * } * else * { * uint frameOffset = input.ReadUInt32(); * data.Seek(frameOffset, SeekOrigin.Begin); * getAnimationKeyFrame(input, frame); * } * } * * animationData.frameList.Add(frame); * } * * materialAnimation.data.Add(animationData); * } * * models.materialAnimation.list.Add(materialAnimation); * } * */ } }
public VBN GetVBN(FileData d) { VBN v = new VBN(); d.Endian = Endianness.Big; d.seek(8); int ver = d.readInt(); d.skip(4); //outer offset to brres int boneHeader = 0x40; // for version 9 only int dlist = d.readInt(); int boneSec = d.readInt(); int vertSec = d.readInt(); int normSec = d.readInt(); int colrSec = d.readInt(); int texcSec = d.readInt(); d.skip(8); int polySec = d.readInt(); d.seek(0x40); d.skip(16); int vertCount = d.readInt(); int faceCount = d.readInt(); d.skip(4); int boneCount = d.readInt(); v.totalBoneCount = (uint)boneCount; for (int i = 0; i < 3; i++) { v.boneCountPerType[i + 1] = 0; } d.skip(4); int bonetableoff = d.readInt() + boneHeader; d.seek(bonetableoff); int bcount = d.readInt(); int[] nodeIndex = new int[bcount]; for (int i = 0; i < bcount; i++) { nodeIndex[i] = d.readInt(); } Random rng = new Random(); uint boneID = (uint)rng.Next(1, 0xFFFFFF); // BONES----------------------------------------------- d.seek(boneSec); d.skip(4); // length int bseccount = d.readInt(); for (int i = 0; i < bseccount; i++) { Debug.Write(i); d.skip(4); // entry id and unknown d.skip(4); // left and right index int name = d.readInt() + boneSec; int data = d.readInt() + boneSec; int temp = d.pos(); if (name != boneSec && data != boneSec) { // read bone data d.seek(data); d.skip(8); int nameOff = d.readInt() + data; int index = d.readInt(); // id d.skip(4); // index d.skip(8); // idk billboard settings and padding Bone n = new Bone(v); n.scale = new float[3]; n.position = new float[3]; n.rotation = new float[3]; d.skip(4); // index n.scale[0] = d.readFloat(); n.scale[1] = d.readFloat(); n.scale[2] = d.readFloat(); n.rotation[0] = toRadians(d.readFloat()); n.rotation[1] = toRadians(d.readFloat()); n.rotation[2] = toRadians(d.readFloat()); n.position[0] = d.readFloat(); n.position[1] = d.readFloat(); n.position[2] = d.readFloat(); n.pos = new Vector3(n.position[0], n.position[1], n.position[2]); n.sca = new Vector3(n.scale[0], n.scale[1], n.scale[2]); n.rot = (VBN.FromEulerAngles(n.rotation [2], n.rotation [1], n.rotation [0])); d.skip(24); d.seek(data + 0x5C); d.seek(d.readInt() + data + 12); int parentid = 0x0FFFFFFF; if (d.pos() != data + 12) { parentid = d.readInt(); } n.parentIndex = (int)parentid; n.boneName = d.readString(nameOff, -1).ToCharArray(); n.boneId = boneID; boneID++; v.bones.Add(n); } else { bseccount++; } d.seek(temp); } v.update(); //v.updateChildren(); v.boneCountPerType[0] = (uint)v.bones.Count; return(v); }
public void read(FileData f) { base.read(f); f.skip(1); type = f.readInt(); //2 = sphere, 3 = capsule if ((type != 2) && (type != 3)) { throw new NotImplementedException($"Unknown damage shape type {type} at offset {f.pos()-4}"); } x = f.readFloat(); y = f.readFloat(); z = f.readFloat(); if (type == 2) { radius = f.readFloat(); dx = f.readFloat(); dy = f.readFloat(); dz = f.readFloat(); } else if (type == 3) { dx = f.readFloat(); dy = f.readFloat(); dz = f.readFloat(); radius = f.readFloat(); } unk = f.readFloat(); f.skip(0x1); }
public void read(FileData f) { base.read(f); f.readByte(); type = f.readInt(); //3 = rect, 4 = path if ((type != 3) && (type != 4)) { throw new NotImplementedException($"Unknown general shape type {type} at offset {f.pos()-4}"); } x1 = f.readFloat(); y1 = f.readFloat(); x2 = f.readFloat(); y2 = f.readFloat(); f.skip(1); f.skip(1); int pointCount = f.readInt(); for (int i = 0; i < pointCount; i++) { f.skip(1); points.Add(new Vector2D() { x = f.readFloat(), y = f.readFloat() }); } }
public override void Read(string filename) { FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(4); int backwardCompatibility = f.readByte(); int forwardCompatibility = f.readByte(); int version = f.readUShort(); int mainHeaderOffset = f.readInt(); int stringTableOffset = f.readInt(); int gpuCommandsOffset = f.readInt(); int dataOffset = f.readInt(); int dataExtendedOffset = 0; int dataExtendedLength = 0; if (backwardCompatibility > 0x20) { dataExtendedOffset = f.readInt(); } int relocationTableOffset = f.readInt(); int mainHeaderLength = f.readInt(); int stringTableLength = f.readInt(); int gpuCommandsLength = f.readInt(); int dataLength = f.readInt(); if (backwardCompatibility > 0x20) { dataExtendedLength = f.readInt(); } int relocationTableLength = f.readInt(); int uninitializedDataSectionLength = f.readInt(); int uninitializedDescriptionSectionLength = f.readInt(); if (backwardCompatibility > 7) { int flags = f.readUShort(); int addressCount = f.readUShort(); } // Relocation table for (int i = 0; i < relocationTableLength; i += 4) { f.seek(relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + mainHeaderOffset); f.writeInt((off * 4) + mainHeaderOffset, f.readInt() + mainHeaderOffset); break; case 1: f.seek(off + mainHeaderOffset); f.writeInt((off) + mainHeaderOffset, f.readInt() + stringTableOffset); break; case 2: f.seek((off * 4) + mainHeaderOffset); f.writeInt((off * 4) + mainHeaderOffset, f.readInt() + gpuCommandsOffset); break; case 0xc: f.seek((off * 4) + mainHeaderOffset); f.writeInt((off * 4) + mainHeaderOffset, f.readInt() + dataOffset); break; } f.seek((off * 4) + gpuCommandsOffset); if (backwardCompatibility < 6) { switch (flag) { case 0x23: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Texture case 0x25: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Vertex //case 0x26: f.writeInt((off * 4) + int gpuCommandsOffset, ((f.readInt() + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x27: f.writeInt((off * 4) + gpuCommandsOffset, (f.readInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (backwardCompatibility < 8) { switch (flag) { case 0x24: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Vertex //case 0x27: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x28: f.writeInt((off * 4) + gpuCommandsOffset, (f.readInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (backwardCompatibility < 0x21) { switch (flag) { case 0x25: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Texture case 0x27: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Vertex //case 0x28: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x29: f.writeInt((off * 4) + gpuCommandsOffset, (f.readInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else { switch (flag) { case 0x25: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataOffset); break; //Vertex relative to Data Offset //case 0x27: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset case 0x28: f.writeInt((off * 4) + gpuCommandsOffset, (f.readInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset case 0x2b: f.writeInt((off * 4) + gpuCommandsOffset, f.readInt() + dataExtendedOffset); break; //Vertex relative to Data Extended Offset //case 0x2c: writer.Write(((peek(input) + int dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset case 0x2d: f.writeInt((off * 4) + gpuCommandsOffset, (f.readInt() + dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset } } } //File.WriteAllBytes(filename + "_offset", f.getSection(0, f.size())); f.seek(mainHeaderOffset); int modelsPointerTableOffset = f.readInt(); int modelsPointerTableEntries = f.readInt(); int modelsNameOffset = f.readInt(); int materialsPointerTableOffset = f.readInt(); int materialsPointerTableEntries = f.readInt(); int materialsNameOffset = f.readInt(); int shadersPointerTableOffset = f.readInt(); int shadersPointerTableEntries = f.readInt(); int shadersNameOffset = f.readInt(); int texturesPointerTableOffset = f.readInt(); int texturesPointerTableEntries = f.readInt(); int texturesNameOffset = f.readInt(); int materialsLUTPointerTableOffset = f.readInt(); int materialsLUTPointerTableEntries = f.readInt(); int materialsLUTNameOffset = f.readInt(); int lightsPointerTableOffset = f.readInt(); int lightsPointerTableEntries = f.readInt(); int lightsNameOffset = f.readInt(); int camerasPointerTableOffset = f.readInt(); int camerasPointerTableEntries = f.readInt(); int camerasNameOffset = f.readInt(); int fogsPointerTableOffset = f.readInt(); int fogsPointerTableEntries = f.readInt(); int fogsNameOffset = f.readInt(); int skeletalAnimationsPointerTableOffset = f.readInt(); int skeletalAnimationsPointerTableEntries = f.readInt(); int skeletalAnimationsNameOffset = f.readInt(); int materialAnimationsPointerTableOffset = f.readInt(); int materialAnimationsPointerTableEntries = f.readInt(); int materialAnimationsNameOffset = f.readInt(); int visibilityAnimationsPointerTableOffset = f.readInt(); int visibilityAnimationsPointerTableEntries = f.readInt(); int visibilityAnimationsNameOffset = f.readInt(); int lightAnimationsPointerTableOffset = f.readInt(); int lightAnimationsPointerTableEntries = f.readInt(); int lightAnimationsNameOffset = f.readInt(); int cameraAnimationsPointerTableOffset = f.readInt(); int cameraAnimationsPointerTableEntries = f.readInt(); int cameraAnimationsNameOffset = f.readInt(); int fogAnimationsPointerTableOffset = f.readInt(); int fogAnimationsPointerTableEntries = f.readInt(); int fogAnimationsNameOffset = f.readInt(); int scenePointerTableOffset = f.readInt(); int scenePointerTableEntries = f.readInt(); int sceneNameOffset = f.readInt(); Console.WriteLine(modelsPointerTableEntries > 0 ? "Has Models" : ""); Console.WriteLine(shadersPointerTableEntries > 0 ? "Has Shaders" : ""); Console.WriteLine(texturesPointerTableEntries > 0 ? "Has Textures" : ""); Console.WriteLine(materialsPointerTableEntries > 0 ? "Has Materials" : ""); Console.WriteLine(materialsLUTPointerTableEntries > 0 ? "Has Material LUT" : ""); Console.WriteLine(materialAnimationsPointerTableEntries > 0 ? "Has Material Animation" : ""); Console.WriteLine(lightsPointerTableEntries > 0 ? "Has Lights" : ""); Console.WriteLine(lightAnimationsPointerTableEntries > 0 ? "Has LightAnimations" : ""); Console.WriteLine(camerasPointerTableEntries > 0 ? "Has Camera" : ""); Console.WriteLine(cameraAnimationsPointerTableEntries > 0 ? "Has CameraAnimation" : ""); Console.WriteLine(fogsPointerTableEntries > 0 ? "Has Fog" : ""); Console.WriteLine(fogAnimationsPointerTableEntries > 0 ? "Has FogAnimation" : ""); Console.WriteLine(skeletalAnimationsPointerTableEntries > 0 ? "Has Skeletal Animations" : ""); Console.WriteLine(visibilityAnimationsPointerTableEntries > 0 ? "Has Visibility" : ""); Console.WriteLine(scenePointerTableEntries > 0 ? "Has Scene" : ""); // Textures for (int index = 0; index < texturesPointerTableEntries; index++) { f.seek(texturesPointerTableOffset + (index * 4)); int dOffset = f.readInt(); f.seek(dOffset); // one for each mip I assume int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); int textureCommandsOffset2 = f.readInt(); int textureCommandsWordCount2 = f.readInt(); int textureCommandsOffset3 = f.readInt(); int textureCommandsWordCount3 = f.readInt(); int unk = f.readInt(); BCH_Texture tex = new BCH_Texture(); tex.Text = f.readString(f.readInt(), -1); Textures.Nodes.Add(tex); f.seek(textureCommandsOffset); tex.ReadParameters(f, textureCommandsWordCount); } //Models for (int index = 0; index < modelsPointerTableEntries; index++) { f.seek(modelsPointerTableOffset + (index * 4)); f.seek(f.readInt()); BCH_Model model = new BCH_Model(); Models.Nodes.Add(model); model.flags = f.readByte(); model.skeletonScaleType = f.readByte(); model.silhouetteMaterialEntries = f.readUShort(); model.worldTransform = new OpenTK.Matrix4(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , 0, 0, 0, 1); int materialsTableOffset = f.readInt(); int materialsTableEntries = f.readInt(); int materialNameOffset = f.readInt(); int verticesTableOffset = f.readInt(); int verticesTableEntries = f.readInt(); f.skip(0x28); int skeletonOffset = f.readInt(); int skeletonEntries = f.readInt(); int skeletonNameOffset = f.readInt(); int objectsNodeVisibilityOffset = f.readInt(); int objectsNodeCount = f.readInt(); model.Text = f.readString(f.readInt(), -1); int objectsNodeNameEntries = f.readInt(); int objectsNodeNameOffset = f.readInt(); f.readInt(); //0x0 int metaDataPointerOffset = f.readInt(); f.seek(objectsNodeVisibilityOffset); int nodeVisibility = f.readInt(); string[] objectName = new string[objectsNodeNameEntries]; f.seek(objectsNodeNameOffset); int rootReferenceBit = f.readInt(); int rootLeftNode = f.readUShort(); int rootRightNode = f.readUShort(); int rootNameOffset = f.readInt(); //Console.WriteLine(rootReferenceBit.ToString("x") + " " + f.readString(rootNameOffset, -1) + " " + rootLeftNode + " " + rootRightNode); // Object name tree Radix Tree for (int i = 0; i < objectsNodeNameEntries; i++) { int referenceBit = f.readInt(); short leftNode = f.readShort(); short rightNode = f.readShort(); objectName[i] = f.readString(f.readInt(), -1); Console.WriteLine((referenceBit >> 3) + " " + (referenceBit & 0x7) + " " + objectName[i] + " " + leftNode + " " + rightNode); } //TODO: Metadata, boundingbox, normal mesh, materials f.seek(verticesTableOffset); Dictionary <int, BCH_Mesh> MeshIndex = new Dictionary <int, BCH_Mesh>(); int nim = 0; for (int i = 0; i < verticesTableEntries; i++) { BCH_Mesh Mesh = new BCH_Mesh(); Mesh.MaterialIndex = f.readUShort(); int mflags = f.readUShort(); int meshId = f.readUShort(); if (!MeshIndex.ContainsKey(meshId)) { MeshIndex.Add(meshId, Mesh); Mesh.Text = nim < objectName.Length ? objectName[nim++] : i + ""; model.Nodes.Add(Mesh); } else { BCH_Mesh m = MeshIndex[meshId]; Mesh.Text = m.Text; model.Nodes.Insert(model.Nodes.IndexOf(m) - 1, Mesh); } // node visibility TODO: finish... Mesh.Checked = ((nodeVisibility & (1 << i)) > 0); Mesh.renderPriority = f.readUShort(); int vshAttBufferCommandOffset = f.readInt(); int vshAttBufferCommandCount = f.readInt(); int faceOffset = f.readInt(); int faceCount = f.readInt(); int vshAttBufferCommandOffsetEx = f.readInt(); int vshAttBufferCommandCountEx = f.readInt(); Vector3 Center = new Vector3(f.readFloat(), f.readFloat(), f.readFloat()); int flagoffset = f.readInt(); // flagsOffset f.skip(4); // 0? int boundingBoxOffset = f.readInt(); } //Materials Console.WriteLine(materialsTableOffset.ToString("x") + " " + materialsPointerTableOffset.ToString("x")); for (int i = 0; i < materialsTableEntries; i++) { f.seek(materialsTableOffset + (i * 0x2c)); int paramOffset = f.readInt(); f.skip(12); // other offsets int texCommandOffset = f.readInt(); int texCommandCount = f.readInt(); int mapperOffset = f.readInt(); BCH_Material mat = new BCH_Material(); Materials.Nodes.Add(mat); mat.Text = f.readString(f.readInt(), -1); Console.WriteLine(mat.Text); //Console.WriteLine(f.readString(f.readInt(), -1)); //Console.WriteLine(f.readString(f.readInt(), -1)); //Console.WriteLine(f.readString(f.readInt(), -1)); // TODO: Parameters } //Skeleton f.seek(skeletonOffset); for (int bindex = 0; bindex < skeletonEntries; bindex++) { Bone bone = new Bone(model.skeleton); int boneFlags = f.readInt(); bone.parentIndex = f.readShort(); short boneSpace = f.readShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.readFloat(); bone.scale[1] = f.readFloat(); bone.scale[2] = f.readFloat(); bone.rotation[0] = f.readFloat(); bone.rotation[1] = f.readFloat(); bone.rotation[2] = f.readFloat(); bone.position[0] = f.readFloat(); bone.position[1] = f.readFloat(); bone.position[2] = f.readFloat(); // bone matrix... not really needed to be stored per say f.skip(4 * 4 * 3); bone.Text = f.readString(f.readInt(), -1); int metaDataPointerOffset2 = f.readInt(); if (metaDataPointerOffset2 != 0) { int position = f.pos(); f.seek(metaDataPointerOffset2); //bone.userData = getMetaData(input); f.seek(position); } model.skeleton.bones.Add(bone); } model.skeleton.reset(); model.skeleton.update(); } }
public override void Read(string filename) { bchHeader header = new bchHeader(); FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(4); header.backwardCompatibility = f.readByte(); header.forwardCompatibility = f.readByte(); header.version = f.readShort(); header.mainHeaderOffset = f.readInt(); header.stringTableOffset = f.readInt(); header.gpuCommandsOffset = f.readInt(); header.dataOffset = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedOffset = f.readInt(); } header.relocationTableOffset = f.readInt(); header.mainHeaderLength = f.readInt(); header.stringTableLength = f.readInt(); header.gpuCommandsLength = f.readInt(); header.dataLength = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedLength = f.readInt(); } header.relocationTableLength = f.readInt(); header.uninitializedDataSectionLength = f.readInt(); header.uninitializedDescriptionSectionLength = f.readInt(); if (header.backwardCompatibility > 7) { header.flags = f.readShort(); header.addressCount = f.readShort(); } // Relocation table for (int i = 0; i < header.relocationTableLength; i += 4) { f.seek(header.relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.mainHeaderOffset); break; case 1: f.seek(off + header.mainHeaderOffset); f.writeInt((off) + header.mainHeaderOffset, f.readInt() + header.stringTableOffset); break; case 2: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.gpuCommandsOffset); break; case 0xc: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; } f.seek((off * 4) + header.gpuCommandsOffset); if (header.backwardCompatibility < 6) { switch (flag) { case 0x23: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, ((f.readInt() + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x27: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 8) { switch (flag) { case 0x24: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x28: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 0x21) { switch (flag) { case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x27: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex //case 0x28: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x29: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else { switch (flag) { case 0x25: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Texture case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataOffset); break; //Vertex relative to Data Offset //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset case 0x28: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset case 0x2b: f.writeInt((off * 4) + header.gpuCommandsOffset, f.readInt() + header.dataExtendedOffset); break; //Vertex relative to Data Extended Offset //case 0x2c: writer.Write(((peek(input) + header.dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset case 0x2d: f.writeInt((off * 4) + header.gpuCommandsOffset, (f.readInt() + header.dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset } } } // Content Header f.seek(header.mainHeaderOffset); bchContentHeader content = new bchContentHeader(); { content.modelsPointerTableOffset = f.readInt(); content.modelsPointerTableEntries = f.readInt(); content.modelsNameOffset = f.readInt(); content.materialsPointerTableOffset = f.readInt(); content.materialsPointerTableEntries = f.readInt(); content.materialsNameOffset = f.readInt(); content.shadersPointerTableOffset = f.readInt(); content.shadersPointerTableEntries = f.readInt(); content.shadersNameOffset = f.readInt(); content.texturesPointerTableOffset = f.readInt(); content.texturesPointerTableEntries = f.readInt(); content.texturesNameOffset = f.readInt(); content.materialsLUTPointerTableOffset = f.readInt(); content.materialsLUTPointerTableEntries = f.readInt(); content.materialsLUTNameOffset = f.readInt(); content.lightsPointerTableOffset = f.readInt(); content.lightsPointerTableEntries = f.readInt(); content.lightsNameOffset = f.readInt(); content.camerasPointerTableOffset = f.readInt(); content.camerasPointerTableEntries = f.readInt(); content.camerasNameOffset = f.readInt(); content.fogsPointerTableOffset = f.readInt(); content.fogsPointerTableEntries = f.readInt(); content.fogsNameOffset = f.readInt(); content.skeletalAnimationsPointerTableOffset = f.readInt(); content.skeletalAnimationsPointerTableEntries = f.readInt(); content.skeletalAnimationsNameOffset = f.readInt(); content.materialAnimationsPointerTableOffset = f.readInt(); content.materialAnimationsPointerTableEntries = f.readInt(); content.materialAnimationsNameOffset = f.readInt(); content.visibilityAnimationsPointerTableOffset = f.readInt(); content.visibilityAnimationsPointerTableEntries = f.readInt(); content.visibilityAnimationsNameOffset = f.readInt(); content.lightAnimationsPointerTableOffset = f.readInt(); content.lightAnimationsPointerTableEntries = f.readInt(); content.lightAnimationsNameOffset = f.readInt(); content.cameraAnimationsPointerTableOffset = f.readInt(); content.cameraAnimationsPointerTableEntries = f.readInt(); content.cameraAnimationsNameOffset = f.readInt(); content.fogAnimationsPointerTableOffset = f.readInt(); content.fogAnimationsPointerTableEntries = f.readInt(); content.fogAnimationsNameOffset = f.readInt(); content.scenePointerTableOffset = f.readInt(); content.scenePointerTableEntries = f.readInt(); content.sceneNameOffset = f.readInt(); } //Shaders (unused for now, until someone wants to add them) for (int index = 0; index < content.shadersPointerTableEntries; index++) { f.seek(content.shadersPointerTableOffset + (index * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); int shaderDataOffset = f.readInt(); int shaderDataLength = f.readInt(); } // Textures // WIP Section for (int index = 0; index < content.texturesPointerTableEntries; index++) { f.seek(content.texturesPointerTableOffset + (index * 4)); int dOffset = f.readInt(); f.seek(dOffset); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); f.seek(f.pos() + 0x14); String textureName = f.readString(f.readInt(), -1); //Debug.WriteLine("gpuCommandOffset: " + header.gpuCommandsOffset.ToString("X")); f.seek(textureCommandsOffset); //Debug.WriteLine("textureCommandOffset: " + textureCommandsOffset.ToString("X")); BCH_Texture tex = new BCH_Texture(); textures.Add(textureName, tex); tex.height = f.readShort(); tex.width = f.readShort(); f.skip(12); int doffset = f.readInt(); //Debug.WriteLine("doffset: " + doffset.ToString("X")); f.skip(4); tex.type = f.readInt(); tex.data = f.getSection(doffset, f.size() - doffset); if (tex.type == 12) { tex.display = NUT.loadImage(Pixel.decodeETC(tex.data, tex.width, tex.height)); } } // Model data for (int modelIndex = 0; modelIndex < content.modelsPointerTableEntries; modelIndex++) { f.seek(content.modelsPointerTableOffset + (modelIndex * 4)); int objectsHeaderOffset = f.readInt(); // Objects f.seek(objectsHeaderOffset); BCH_Model model = new BCH_Model(); models.Add(model); model.flags = f.readByte(); model.skeletonScaleType = f.readByte(); model.silhouetteMaterialEntries = f.readShort(); model.worldTransform = new Matrix4(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , 0, 0, 0, 1); model.materialsTableOffset = f.readInt(); model.materialsTableEntries = f.readInt(); model.materialsNameOffset = f.readInt(); model.verticesTableOffset = f.readInt(); //Debug.WriteLine("Mesh Count: " + f.pos().ToString("X")); model.verticesTableEntries = f.readInt(); f.skip(0x28); model.skeletonOffset = f.readInt(); model.skeletonEntries = f.readInt(); model.skeletonNameOffset = f.readInt(); model.objectsNodeVisibilityOffset = f.readInt(); model.objectsNodeCount = f.readInt(); model.name = f.readString(f.readInt(), -1); model.objectsNodeNameEntries = f.readInt(); model.objectsNodeNameOffset = f.readInt(); f.readInt(); //0x0 model.metaDataPointerOffset = f.readInt(); f.seek(model.objectsNodeVisibilityOffset); int nodeVisibility = f.readInt(); string[] objectName = new string[model.objectsNodeNameEntries]; f.seek(model.objectsNodeNameOffset); int rootReferenceBit = f.readInt(); //Radix tree int rootLeftNode = f.readShort(); int rootRightNode = f.readShort(); int rootNameOffset = f.readInt(); for (int i = 0; i < model.objectsNodeNameEntries; i++) { int referenceBit = f.readInt(); short leftNode = (short)f.readShort(); short rightNode = (short)f.readShort(); objectName[i] = f.readString(f.readInt(), -1); //Debug.WriteLine(objectName[i]); } // Materials // NOTE: MATERIALS AND OBJECT SECTIONS ARE REALLY MESSY ATM String[] materialNames = new String[model.materialsTableEntries]; for (int index = 0; index < model.materialsTableEntries; index++) { f.seek(model.materialsTableOffset + (index * 0x2c)); int materialParametersOffset = f.readInt(); f.readInt(); f.readInt(); f.readInt(); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); int materialMapperOffset = f.readInt(); materialNames[index] = f.readString(f.readInt(), -1); } // Object Descriptions... // Assumes MBN is already loaded for now f.seek(model.verticesTableOffset); List <objDes> objDescriptors = new List <objDes>(); Debug.WriteLine(model.name); if (mbn == null) { mbn = new Smash_Forge.MBN(); for (int index = 0; index < model.verticesTableEntries; index++) { mbn.mesh.Add(new MBN.Mesh()); } mbn.PreRender(); } for (int index = 0; index < mbn.mesh.Count; index++) { int i = f.readShort(); if (index > mbn.mesh.Count) { break; } if (i > materialNames.Length) { break; } mbn.mesh[index].texId = textures[materialNames[i]].display; Console.WriteLine("Tex index" + mbn.mesh[index].texId); f.skip(2); // flags int nameId = f.readShort(); mbn.mesh[index].name = objectName[nameId]; // node visibility TODO: finish... //mbn.mesh[index].isVisible = ((nodeVisibility & (1 << nameId)) > 0); mbn.mesh[index].renderPriority = f.readShort(); objDes des = new objDes(); objDescriptors.Add(des); des.vshAttBufferCommandOffset = f.readInt(); des.vshAttBufferCommandCount = f.readInt(); des.faceOffset = f.readInt(); des.faceCount = f.readInt(); des.vshAttBufferCommandOffsetEx = f.readInt(); des.vshAttBufferCommandCountEx = f.readInt(); f.skip(12); // center vector f.skip(4); // flagsOffset f.skip(4); // 0? f.readInt(); //bbOffsets[i] //Debug.WriteLine(des.vshAttBufferCommandOffset.ToString("X")); } for (int index1 = 0; index1 < content.skeletalAnimationsPointerTableEntries; index1++) { f.seek(content.skeletalAnimationsPointerTableOffset + (index1 * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); string skeletalAnimationName = f.readString(); int animationFlags = f.readInt(); int skeletalAnimationloopMode = f.readByte(); float skeletalAnimationframeSize = f.readFloat(); int boneTableOffset = f.readInt(); int boneTableEntries = f.readInt(); int metaDataPointerOffset = f.readInt(); Console.WriteLine("Animation Name: " + skeletalAnimationName); } //Skeleton f.seek(model.skeletonOffset); for (int index = 0; index < model.skeletonEntries; index++) { Bone bone = new Smash_Forge.Bone(model.skeleton); int boneFlags = f.readInt(); bone.parentIndex = (short)f.readShort(); short boneSpace = (short)f.readShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.readFloat(); bone.scale[1] = f.readFloat(); bone.scale[2] = f.readFloat(); bone.rotation[0] = f.readFloat(); bone.rotation[1] = f.readFloat(); bone.rotation[2] = f.readFloat(); bone.position[0] = f.readFloat(); bone.position[1] = f.readFloat(); bone.position[2] = f.readFloat(); // bone matrix... not really needed to be stored per say f.skip(4 * 4 * 3); bone.Text = f.readString(f.readInt(), -1); f.skip(4); // Meta data model.skeleton.bones.Add(bone); } model.skeleton.reset(); } }
public static Animation readAnim(FileData d, VBN m) { int offset = d.readInt(); int nameoff = d.readInt(); d.skip(4); int fCount = d.readShort(); int animDataCount = d.readShort(); d.skip(8); Animation anim = new Animation("CHR0 Import"); //anim.setModel(m); d.seek(offset); int sectionOffset = d.readInt() + offset; int size = d.readInt(); // size again for (int i = 0; i < size; i++) { // System.out.print(d.readShort()); // id d.skip(4); // id and unknown d.readShort(); //left d.readShort(); //right int nameOffset = d.readInt() + offset; int dataOffset = d.readInt() + offset; if (dataOffset == offset) { i--; continue; // d.skip(8); // nameOffset = d.readInt() + 4; // dataOffset = d.readInt() + offset; } int temp = d.pos(); d.seek(dataOffset); int pos = d.pos(); int nameOff = d.readInt() + sectionOffset + (d.pos() - sectionOffset) - 4; int flags = d.readInt(); int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; Animation.KeyNode node = new Animation.KeyNode(d.readString(nameOff, -1)); anim.Bones.Add(node); node.RotType = Animation.RotationType.EULER; if (hasS == 1) { if (Siso == 1) { float iss = d.readFloat(); node.XSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.YSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.ZSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); } else { if (SXfixed == 1) { node.XSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, s_type, pos, node, "SX", false, anim); } if (SYfixed == 1) { node.YSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, s_type, pos, node, "SY", false, anim); } if (SZfixed == 1) { node.ZSCA.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, s_type, pos, node, "SZ", false, anim); } } } if (hasR == 1) { if (Riso == 1) { float iss = (float)((d.readFloat()) * Math.PI / 180f); node.XROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.YROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.ZROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); } else { if (RXfixed == 1) { node.XROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = (float)(Math.PI / 180f) * (d.readFloat()) }); } else { process(d, r_type, pos, node, "RX", false, anim); } if (RYfixed == 1) { node.YROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = (float)(Math.PI / 180f) * (d.readFloat()) }); } else { process(d, r_type, pos, node, "RY", false, anim); } if (RZfixed == 1) { node.ZROT.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = (float)(Math.PI / 180f) * (d.readFloat()) }); } else { process(d, r_type, pos, node, "RZ", false, anim); } } } if (hasT == 1) { if (Tiso == 1) { float iss = d.readFloat(); node.XPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.YPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); node.ZPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = iss }); } else { if (Xfixed == 1) { node.XPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, t_type, pos, node, "X", false, anim); } if (Yfixed == 1) { node.YPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, t_type, pos, node, "Y", false, anim); } if (Zfixed == 1) { node.ZPOS.Keys.Add(new Animation.KeyFrame() { Frame = 0, Value = d.readFloat() }); } else { process(d, t_type, pos, node, "Z", false, anim); } } } d.seek(temp); } return(anim); }
public override void Read(string filename) { FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(8); int mainHeaderOffset = f.readInt(); int stringTableOffset = f.readInt(); int gpuCommandOffset = f.readInt(); int dataOffset = f.readInt(); int dataExtendOffset = f.readInt(); int relocationTableOffset = f.readInt(); int mainHeaderLength = f.readInt(); int stringTableLength = f.readInt(); int gpuCommandLength = f.readInt(); int dataLength = f.readInt(); int dataExtendLength = f.readInt(); int relocationTableLength = f.readInt(); int datsSecLength = f.readInt(); int desSecLength = f.readInt(); int flags = f.readShort(); int addressCount = f.readShort(); // TODO: Finished Relocation table stuff for (int i = 0; i < relocationTableLength; i += 4) { f.seek(relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + mainHeaderOffset); break; } } // Content Header f.seek(mainHeaderOffset); int modelsPointerTableOffset = f.readInt() + mainHeaderOffset; int modelsPointerTableEntries = f.readInt(); int modelsNameOffset = f.readInt() + mainHeaderOffset; int materialsPointerTableOffset = f.readInt() + mainHeaderOffset; int materialsPointerTableEntries = f.readInt(); int materialsNameOffset = f.readInt() + mainHeaderOffset; int shadersPointerTableOffset = f.readInt() + mainHeaderOffset; int shadersPointerTableEntries = f.readInt(); int shadersNameOffset = f.readInt() + mainHeaderOffset; int texturesPointerTableOffset = f.readInt() + mainHeaderOffset; int texturesPointerTableEntries = f.readInt(); int texturesNameOffset = f.readInt() + mainHeaderOffset; int materialsLUTPointerTableOffset = f.readInt() + mainHeaderOffset; int materialsLUTPointerTableEntries = f.readInt(); int materialsLUTNameOffset = f.readInt() + mainHeaderOffset; int lightsPointerTableOffset = f.readInt() + mainHeaderOffset; int lightsPointerTableEntries = f.readInt(); int lightsNameOffset = f.readInt() + mainHeaderOffset; int camerasPointerTableOffset = f.readInt() + mainHeaderOffset; int camerasPointerTableEntries = f.readInt(); int camerasNameOffset = f.readInt() + mainHeaderOffset; int fogsPointerTableOffset = f.readInt() + mainHeaderOffset; int fogsPointerTableEntries = f.readInt(); int fogsNameOffset = f.readInt() + mainHeaderOffset; int skeletalAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int skeletalAnimationsPointerTableEntries = f.readInt(); int skeletalAnimationsNameOffset = f.readInt() + mainHeaderOffset; int materialAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int materialAnimationsPointerTableEntries = f.readInt(); int materialAnimationsNameOffset = f.readInt() + mainHeaderOffset; int visibilityAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int visibilityAnimationsPointerTableEntries = f.readInt(); int visibilityAnimationsNameOffset = f.readInt() + mainHeaderOffset; int lightAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int lightAnimationsPointerTableEntries = f.readInt(); int lightAnimationsNameOffset = f.readInt() + mainHeaderOffset; int cameraAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int cameraAnimationsPointerTableEntries = f.readInt(); int cameraAnimationsNameOffset = f.readInt() + mainHeaderOffset; int fogAnimationsPointerTableOffset = f.readInt() + mainHeaderOffset; int fogAnimationsPointerTableEntries = f.readInt(); int fogAnimationsNameOffset = f.readInt() + mainHeaderOffset; int scenePointerTableOffset = f.readInt() + mainHeaderOffset; int scenePointerTableEntries = f.readInt(); int sceneNameOffset = f.readInt() + mainHeaderOffset; // Textures // WIP Section for (int index = 0; index < texturesPointerTableEntries; index++) { f.seek(texturesPointerTableOffset + (index * 4)); int dOffset = f.readInt(); f.seek(dOffset + mainHeaderOffset); int textureCommandsOffset = f.readInt() + gpuCommandOffset; int textureCommandsWordCount = f.readInt(); f.seek(f.pos() + 0x14); String textureName = f.readString(f.readInt() + stringTableOffset, -1); f.seek(textureCommandsOffset); BCH_Texture tex = new BCH_Texture(); textures.Add(textureName, tex); tex.height = f.readShort(); tex.width = f.readShort(); f.skip(12); int doffset = f.readInt() + dataOffset; f.skip(4); tex.type = f.readInt(); tex.data = f.getSection(doffset, f.size() - doffset); if (tex.type == 12) { tex.display = NUT.loadImage(Pixel.decodeETC(tex.data, tex.width, tex.height)); } } // Model data for (int modelIndex = 0; modelIndex < modelsPointerTableEntries; modelIndex++) { f.seek(modelsPointerTableOffset + (modelIndex * 4)); int objectsHeaderOffset = f.readInt() + mainHeaderOffset; // Objects f.seek(objectsHeaderOffset); BCH_Model model = new BCH_Model(); models.Add(model); model.flags = f.readByte(); model.skeletonScaleType = f.readByte(); model.silhouetteMaterialEntries = f.readShort(); model.worldTransform = new Matrix4(f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , f.readFloat(), f.readFloat(), f.readFloat(), f.readFloat() , 0, 0, 0, 1); int materialsTableOffset = f.readInt() + mainHeaderOffset; int materialsTableEntries = f.readInt(); int materialsNamesOffset = f.readInt() + mainHeaderOffset; int verticesTableOffset = f.readInt() + mainHeaderOffset; //Debug.WriteLine("Mesh Count: " + f.pos().ToString("X")); int verticesTableEntries = f.readInt(); f.skip(0x28); int skeletonOffset = f.readInt() + mainHeaderOffset; int skeletonEntries = f.readInt(); int skeletonNameOffset = f.readInt() + mainHeaderOffset; int objectsNodeVisibilityOffset = f.readInt() + mainHeaderOffset; int objectsNodeCount = f.readInt(); model.name = f.readString(f.readInt() + stringTableOffset, -1); int objectsNodeNameEntries = f.readInt(); int objectsNodeNameOffset = f.readInt() + mainHeaderOffset; f.readInt(); //0x0 int metaDataPointerOffset = f.readInt() + mainHeaderOffset; f.seek(objectsNodeVisibilityOffset); int nodeVisibility = f.readInt(); string[] objectName = new string[objectsNodeNameEntries]; f.seek(objectsNodeNameOffset); int rootReferenceBit = f.readInt(); //Radix tree int rootLeftNode = f.readShort(); int rootRightNode = f.readShort(); int rootNameOffset = f.readInt() + mainHeaderOffset; for (int i = 0; i < objectsNodeNameEntries; i++) { int referenceBit = f.readInt(); short leftNode = (short)f.readShort(); short rightNode = (short)f.readShort(); objectName[i] = f.readString(f.readInt() + stringTableOffset, -1); //Debug.WriteLine(objectName[i]); } // Materials // NOTE: MATERIALS AND OBJECT SECTIONS ARE REALLY MESSY ATM String[] materialNames = new String[materialsTableEntries]; for (int index = 0; index < materialsTableEntries; index++) { f.seek(materialsTableOffset + (index * 0x2c)); int materialParametersOffset = f.readInt(); f.readInt(); f.readInt(); f.readInt(); int textureCommandsOffset = f.readInt(); int textureCommandsWordCount = f.readInt(); int materialMapperOffset = f.readInt(); materialNames[index] = f.readString(f.readInt() + stringTableOffset, -1); } // Object Descriptions... // Assumes MBN is already loaded for now f.seek(verticesTableOffset); List <objDes> objDescriptors = new List <objDes>(); Debug.WriteLine(model.name); if (mbn == null) { mbn = new Smash_Forge.MBN(); for (int index = 0; index < verticesTableEntries; index++) { mbn.mesh.Add(new MBN.Mesh()); } mbn.PreRender(); } for (int index = 0; index < mbn.mesh.Count; index++) { int i = f.readShort(); if (index > mbn.mesh.Count) { break; } if (i > materialNames.Length) { break; } mbn.mesh[index].texId = textures[materialNames[i]].display; f.skip(2); // flags int nameId = f.readShort(); mbn.mesh[index].name = objectName[nameId]; // node visibility TODO: finish... //mbn.mesh[index].isVisible = ((nodeVisibility & (1 << nameId)) > 0); mbn.mesh[index].renderPriority = f.readShort(); objDes des = new objDes(); objDescriptors.Add(des); des.vshAttBufferCommandOffset = f.readInt() + mainHeaderOffset; des.vshAttBufferCommandCount = f.readInt(); des.faceOffset = f.readInt() + mainHeaderOffset; des.faceCount = f.readInt(); des.vshAttBufferCommandOffsetEx = f.readInt() + mainHeaderOffset; des.vshAttBufferCommandCountEx = f.readInt(); f.skip(12); // center vector f.skip(4); // flagsOffset f.skip(4); // 0? f.readInt(); //bbOffsets[i] = + mainheaderOffset //Debug.WriteLine(des.vshAttBufferCommandOffset.ToString("X")); } //Skeleton f.seek(skeletonOffset); for (int index = 0; index < skeletonEntries; index++) { Bone bone = new Smash_Forge.Bone(model.skeleton); int boneFlags = f.readInt(); bone.parentIndex = (short)f.readShort(); short boneSpace = (short)f.readShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.readFloat(); bone.scale[1] = f.readFloat(); bone.scale[2] = f.readFloat(); bone.rotation[0] = f.readFloat(); bone.rotation[1] = f.readFloat(); bone.rotation[2] = f.readFloat(); bone.position[0] = f.readFloat(); bone.position[1] = f.readFloat(); bone.position[2] = f.readFloat(); // bone matrix... not really needed to be stored per say f.skip(4 * 4 * 3); bone.boneName = f.readString(f.readInt() + stringTableOffset, -1).ToCharArray(); f.skip(4); // Meta data model.skeleton.bones.Add(bone); } model.skeleton.reset(); } }
public static void process(FileData d, int type, int secOff, Animation.KeyNode node, String part, bool debug, Animation a) { int offset = d.readInt() + secOff; int temp = d.pos(); d.seek(offset); int max = 0; int fCount = -1; float scale = 0; float[] frame = null, step = null, tan = null; if (type == 0x1) { fCount = d.readShort(); d.skip(2); scale = d.readFloat(); float stepb = d.readFloat(); float base2 = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readByte(); int th = d.readThree(); step[i] = base2 + ((th >> 12) & 0xfff) * stepb; tan[i] = (FileData.sign12Bit(th & 0xfff) / 32f); if (frame[i] > max) { max = (int)frame[i]; } } } if (type == 0x2) { fCount = d.readShort(); d.skip(2); scale = d.readFloat(); float stepb = d.readFloat(); float base2 = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readShort() / 32f; step[i] = base2 + d.readShort() * stepb; tan[i] = ((short)d.readShort() / 256f); if (frame[i] > max) { max = (int)frame[i]; } } } if (type == 0x3) { //if(debug) //System.out.println(part + "\tInterpolated 12 " + Integer.toHexString(offset)); fCount = d.readShort(); d.skip(2); scale = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readFloat(); step[i] = d.readFloat(); tan[i] = d.readFloat(); if (frame[i] > max) { max = (int)frame[i]; } } } a.FrameCount = max; float degrad = (float)(Math.PI / 180f); if (frame != null) { for (int i = 0; i < frame.Length; i++) { Animation.KeyFrame f = new Animation.KeyFrame(); f.InterType = Animation.InterpolationType.HERMITE; f.Value = step[i]; f.Frame = frame[i] - 1; f.In = tan[i]; switch (part) { case "RX": f.Value = step[i] * degrad; node.XROT.Keys.Add(f); break; case "RY": f.Value = step[i] * degrad; node.YROT.Keys.Add(f); break; case "RZ": f.Value = step[i] * degrad; node.ZROT.Keys.Add(f); break; case "X": node.XPOS.Keys.Add(f); break; case "Y": node.YPOS.Keys.Add(f); break; case "Z": node.ZPOS.Keys.Add(f); break; case "SX": node.XSCA.Keys.Add(f); break; case "SY": node.YSCA.Keys.Add(f); break; case "SZ": node.ZSCA.Keys.Add(f); break; } } } if (type == 0x4) { float stepb = d.readFloat(); float base2 = d.readFloat(); for (int i = 0; i < a.FrameCount; i++) { float v = base2 + stepb * (d.readByte()); Animation.KeyFrame f = new Animation.KeyFrame(); f.InterType = Animation.InterpolationType.LINEAR; f.Value = v; f.Frame = i; switch (part) { case "RX": f.Value = step[i] * degrad; node.XROT.Keys.Add(f); break; case "RY": f.Value = step[i] * degrad; node.YROT.Keys.Add(f); break; case "RZ": f.Value = step[i] * degrad; node.ZROT.Keys.Add(f); break; case "X": node.XPOS.Keys.Add(f); break; case "Y": node.YPOS.Keys.Add(f); break; case "Z": node.ZPOS.Keys.Add(f); break; case "SX": node.XSCA.Keys.Add(f); break; case "SY": node.YSCA.Keys.Add(f); break; case "SZ": node.ZSCA.Keys.Add(f); break; } } } if (type == 0x6) { for (int i = 0; i < a.FrameCount; i++) { float v = d.readFloat(); Animation.KeyFrame f = new Animation.KeyFrame(); f.InterType = Animation.InterpolationType.LINEAR; f.Value = v; f.Frame = i; switch (part) { case "RX": f.Value = step[i] * degrad; node.XROT.Keys.Add(f); break; case "RY": f.Value = step[i] * degrad; node.YROT.Keys.Add(f); break; case "RZ": f.Value = step[i] * degrad; node.ZROT.Keys.Add(f); break; case "X": node.XPOS.Keys.Add(f); break; case "Y": node.YPOS.Keys.Add(f); break; case "Z": node.ZPOS.Keys.Add(f); break; case "SX": node.XSCA.Keys.Add(f); break; case "SY": node.YSCA.Keys.Add(f); break; case "SZ": node.ZSCA.Keys.Add(f); break; } } } d.seek(temp); }
public void ReadNTWU(FileData d) { d.skip(0x02); int count = d.readShort(); d.skip(0x10); int headerPtr = d.pos(); int dataPtr = 0; int gtxHeaderOffset = 0; for (int i = 0; i < count; i++) { NUD_Texture tex = new NUD_Texture(); tex.type = PixelInternalFormat.Rgba32ui; d.seek(headerPtr); int totalSize = d.readInt(); int headerSize = d.readShort(); int numMips = d.readInt(); tex.setPixelFormatFromNutFormat(d.readShort()); tex.width = d.readShort(); tex.height = d.readShort(); d.skip(8); // mipmaps and padding int dataOffset = d.readInt() + dataPtr + 0x10; headerPtr += headerSize; dataPtr += headerSize; d.skip(0x04); if (i == 0) { gtxHeaderOffset = d.readInt() + 0x10; } else { gtxHeaderOffset += 0x80; d.skip(0x04); } d.skip(0x04); // check for cubemap bool cmap = (d.readInt() == d.readInt()); d.seek(d.pos() - 8); if (cmap) { Console.WriteLine("cubemap detected"); } d.skip(headerSize - 0x50); d.skip(0x18); tex.id = d.readInt(); d.seek(gtxHeaderOffset); d.skip(0x04); // dim d.skip(0x04); // width d.skip(0x04); // height d.skip(0x04); // depth d.skip(0x04); // numMips int format = d.readInt(); d.skip(0x04); // aa d.skip(0x04); // use int imageSize = d.readInt(); d.skip(0x04); // imagePtr d.skip(0x04); // mipSize d.skip(0x04); // mipPtr int tileMode = d.readInt(); int swizzle = d.readInt(); d.skip(0x04); // alignment int pitch = d.readInt(); for (int mipLevel = 0; mipLevel < numMips; mipLevel++) { // Maybe this is the problem? int mipSize = imageSize >> (mipLevel * 2); int p = pitch >> mipLevel; //Console.WriteLine(tex.id.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + swizzle); //Console.WriteLine((tex.width >> mipLevel) + " " + (tex.height >> mipLevel)); //if (cmap) tex.height *= 2; int w = (tex.width >> mipLevel); int h = (tex.height >> mipLevel); //if (mipSize % 0x10 != 0) mipSize += mipSize % 0x10; //if (cmap) mipSize /= 6; //if (p <= 16) p = 64; { tex.mipmaps.Add(GTX.swizzleBC( d.getSection(dataOffset, mipSize), w, h, format, tileMode, p, swizzle )); } dataOffset += mipSize; /*if (cmap) * { * for(int k = 0; k < 5; k++) * { * p = pitch >> (mipLevel + k + 1); * tex.mipmaps.Add(GTX.swizzleBC( * d.getSection(dataOffset, mipSize), * w, * h, * format, * tileMode, * p, * swizzle * )); * * dataOffset += mipSize; * } * }*/ //while (dataOffset % 1024 != 0) dataOffset++; //if (mipSize == 0x4000) dataOffset += 0x400; } // fix mipmap swizzle for rgba types if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { Console.WriteLine("Endian swap"); // swap foreach (byte[] mip in tex.mipmaps) { for (int t = 0; t < mip.Length; t += 4) { /*byte t1 = mip[t]; * byte t2 = mip[t+1]; * mip[t] = mip[t + 3]; * mip[t + 1] = mip[t + 2]; * mip[t + 2] = t2; * mip[t + 3] = t1;*/ } } } textures.Add(tex); } foreach (var tex in textures) { if (!draw.ContainsKey(tex.id)) { draw.Add(tex.id, loadImage(tex)); } } }
public static SkelAnimation readAnim(FileData d, VBN m) { int offset = d.readInt(); int nameoff = d.readInt(); d.skip(4); int fCount = d.readShort(); int animDataCount = d.readShort(); d.skip(8); SkelAnimation anim = new SkelAnimation(); //anim.setModel(m); d.seek(offset); int sectionOffset = d.readInt() + offset; int size = d.readInt(); // size again for (int i = 0; i < size; i++) { // System.out.print(d.readShort()); // id d.skip(4); // id and unknown d.readShort(); //left d.readShort(); //right int nameOffset = d.readInt() + offset; int dataOffset = d.readInt() + offset; if (dataOffset == offset) { i--; continue; // d.skip(8); // nameOffset = d.readInt() + 4; // dataOffset = d.readInt() + offset; } int temp = d.pos(); d.seek(dataOffset); int pos = d.pos(); int nameOff = d.readInt() + sectionOffset + (d.pos() - sectionOffset) - 4; int flags = d.readInt(); int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; if (hasS == 1) { if (Siso == 1) { //System.out.println("S is ISO"); int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); node.s_type = 1; float iss = d.readFloat(); node.s = new OpenTK.Vector3(iss, iss, iss); } else { int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); node.s_type = 1; // System.out.println("Scale: " + SXfixed + " " + SYfixed + " " + SZfixed + " " + s_type); node.s = new OpenTK.Vector3(-99, -99, -99); if (SXfixed == 1) { node.s.X = d.readFloat(); } else { process(d, s_type, pos, anim, "SX", nid, false, m); } if (SYfixed == 1) { node.s.Y = d.readFloat(); } else { process(d, s_type, pos, anim, "SY", nid, false, m); } if (SZfixed == 1) { node.s.Z = d.readFloat(); } else { process(d, s_type, pos, anim, "SZ", nid, false, m); } } } if (hasR == 1) { if (Riso == 1) { //System.out.println("R is ISO"); int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); node.r_type = 1; float iss = (float)((d.readFloat()) * Math.PI / 180f); node.r = VBN.FromEulerAngles(iss, iss, iss); } else { int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); // System.out.println("Rot: " + RXfixed + " " + RYfixed + " " + RZfixed); node.r = new OpenTK.Quaternion(-99, -99, -99, 0); if (RXfixed == 1) { node.r.X = (float)(Math.PI / 180f) * (d.readFloat()); } else { process(d, r_type, pos, anim, "RX", nid, false, m); } if (RYfixed == 1) { node.r.Y = (float)(Math.PI / 180f) * (d.readFloat()); } else { process(d, r_type, pos, anim, "RY", nid, false, m); } if (RZfixed == 1) { node.r.Z = (float)(Math.PI / 180f) * (d.readFloat()); } else { process(d, r_type, pos, anim, "RZ", nid, false, m); } } } if (hasT == 1) { if (Tiso == 1) { //System.out.println("T is ISO"); int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); node.t_type = 1; float iss = d.readFloat(); node.t = new OpenTK.Vector3(iss, iss, iss); } else { int nid = anim.getNodeIndex(d.readString(nameOff, -1), m); KeyNode node = anim.getNode(0, nid); node.t_type = 1; // System.out.println("Trans: " + Xfixed + " " + Yfixed + " " + Zfixed); node.t = new OpenTK.Vector3(-99, -99, -99); if (Xfixed == 1) { node.t.X = d.readFloat(); } else { process(d, t_type, pos, anim, "X", nid, false, m); } if (Yfixed == 1) { node.t.Y = d.readFloat(); } else { process(d, t_type, pos, anim, "Y", nid, false, m); } if (Zfixed == 1) { node.t.Z = d.readFloat(); } else { process(d, t_type, pos, anim, "Z", nid, false, m); } } } d.seek(temp); } // keynode rotations need caluclation foreach (KeyFrame f in anim.frames) { foreach (KeyNode n in f.nodes) { n.r = VBN.FromEulerAngles(n.r.Z, n.r.Y, n.r.X); } } //anim.calcMax(); return(anim); }
public void ReadNTWU(FileData d) { d.skip(0x02); int count = d.readShort(); d.skip(0x10); int headerPtr = d.pos(); int dataPtr = 0; int gtxHeaderOffset = 0; for (int i = 0; i < count; i++) { NutTexture tex = new NutTexture(); tex.type = PixelInternalFormat.Rgba32ui; d.seek(headerPtr); int totalSize = d.readInt(); int headerSize = d.readShort(); int numMips = d.readInt(); tex.setPixelFormatFromNutFormat(d.readShort()); tex.Width = d.readShort(); tex.Height = d.readShort(); d.skip(8); // mipmaps and padding int dataOffset = d.readInt() + dataPtr + 0x10; headerPtr += headerSize; dataPtr += headerSize; d.skip(0x04); if (i == 0) { gtxHeaderOffset = d.readInt() + 0x10; } else { gtxHeaderOffset += 0x80; d.skip(0x04); } d.skip(0x04); // check for cubemap bool cmap = (d.readInt() == d.readInt()); d.seek(d.pos() - 8); if (cmap) { Console.WriteLine("cubemap detected"); } d.skip(headerSize - 0x50); d.skip(0x18); tex.HASHID = d.readInt(); Console.WriteLine(gtxHeaderOffset.ToString("x")); d.seek(gtxHeaderOffset); d.skip(0x04); // dim d.skip(0x04); // width d.skip(0x04); // height d.skip(0x04); // depth d.skip(0x04); // numMips int format = d.readInt(); d.skip(0x04); // aa d.skip(0x04); // use int imageSize = d.readInt(); d.skip(0x04); // imagePtr int maxSize = d.readInt(); // mipSize d.skip(0x04); // mipPtr int tileMode = d.readInt(); int swizzle = d.readInt(); d.skip(0x04); // alignment int pitch = d.readInt(); int ds = dataOffset; int s1 = 0; int size = 0; Console.WriteLine(totalSize.ToString("x")); for (int mipLevel = 0; mipLevel < numMips; mipLevel++) { // Maybe this is the problem? int mipSize = imageSize >> (mipLevel * 2); int p = pitch >> mipLevel; size = d.readInt(); //Console.WriteLine("\tMIP: " + size.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + (size == 0 ? ds + totalSize - dataOffset : size)); //Console.WriteLine(tex.id.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + swizzle); //Console.WriteLine((tex.width >> mipLevel) + " " + (tex.height >> mipLevel)); //if (cmap) tex.height *= 2; int w = (tex.Width >> mipLevel); int h = (tex.Height >> mipLevel); { byte[] deswiz = GTX.swizzleBC( d.getSection(dataOffset, d.size() - dataOffset), w, h, format, tileMode, p, swizzle ); tex.mipmaps.Add(new FileData(deswiz).getSection(0, mipSize)); } if (mipLevel == 0) { s1 = size; dataOffset = ds + size; } else { dataOffset = ds + s1 + size; } //dataOffset += mipSize; /*if (cmap) * { * for(int k = 0; k < 5; k++) * { * p = pitch >> (mipLevel + k + 1); * tex.mipmaps.Add(GTX.swizzleBC( * d.getSection(dataOffset, mipSize), * w, * h, * format, * tileMode, * p, * swizzle * )); * * dataOffset += mipSize; * } * }*/ //while (dataOffset % 1024 != 0) dataOffset++; //if (mipSize == 0x4000) dataOffset += 0x400; } Nodes.Add(tex); } foreach (NutTexture tex in Nodes) { if (!draw.ContainsKey(tex.HASHID)) { draw.Add(tex.HASHID, loadImage(tex, false)); } // redo mipmaps /*GL.BindTexture(TextureTarget.Texture2D, draw[tex.id]); * for (int k = 1; k < tex.mipmaps.Count; k++) * { * tex.mipmaps[k] = new byte[tex.mipmaps[k].Length]; * GCHandle pinnedArray = GCHandle.Alloc(tex.mipmaps[k], GCHandleType.Pinned); * IntPtr pointer = pinnedArray.AddrOfPinnedObject(); * GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, pointer); * pinnedArray.Free(); * }*/ } //File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\mip1.bin", bytearray); //Console.WriteLine(GL.GetError()); /*int j = 0; * foreach(byte[] b in textures[0].mipmaps) * { * if (j == 3) * { * for(int w = 3; w < 8; w++) * { * for (int p = 3; p < 6; p++) * { * byte[] deswiz = GTX.swizzleBC( * b, * (int)Math.Pow(2, w), * 64, * 51, * 4, * (int)Math.Pow(2, p), * 197632 * ); * File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\chunk_" + (int)Math.Pow(2, p) + "_" + (int)Math.Pow(2, w), deswiz); * } * } * * } * j++; * }*/ }
public static void process(FileData d, int type, int secOff, SkelAnimation anim, String part, int nid, bool debug, VBN vbn) { int offset = d.readInt() + secOff; int temp = d.pos(); d.seek(offset); // System.out.println(d.pos()); int max = 0; int fCount = -1; float scale = 0; float[] frame = null, step = null, tan = null; if (type == 0x1) { fCount = d.readShort(); d.skip(2); scale = d.readFloat(); float stepb = d.readFloat(); float base2 = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readByte(); int th = d.readThree(); step[i] = base2 + ((th >> 12) & 0xfff) * stepb; tan[i] = (FileData.sign12Bit(th & 0xfff) / 32f); if (frame[i] > max) { max = (int)frame[i]; } } } if (type == 0x2) { //if(debug) //System.out.println(part + "\tInterpolated 6\t" + Integer.toHexString(offset)); fCount = d.readShort(); d.skip(2); scale = d.readFloat(); float stepb = d.readFloat(); float base2 = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readShort() / 32f; step[i] = base2 + d.readShort() * stepb; tan[i] = ((short)d.readShort() / 256f); if (frame[i] > max) { max = (int)frame[i]; } } } if (type == 0x3) { //if(debug) //System.out.println(part + "\tInterpolated 12 " + Integer.toHexString(offset)); fCount = d.readShort(); d.skip(2); scale = d.readFloat(); frame = new float[fCount]; step = new float[fCount]; tan = new float[fCount]; for (int i = 0; i < fCount; i++) { frame[i] = d.readFloat(); step[i] = d.readFloat(); tan[i] = d.readFloat(); if (frame[i] > max) { max = (int)frame[i]; } } } if (frame != null) { generateInter(anim, max, nid, part, frame, tan, step, vbn); } if (type == 0x4) { //if(debug) //System.out.println(part + "\tLkin 1 " + Integer.toHexString(offset) + " " + anim.size()); float stepb = d.readFloat(); float base2 = d.readFloat(); for (int i = 0; i < anim.size(); i++) { KeyNode n = anim.getNode(i, nid); if (part.Contains("R")) { n.r_type = 1; } else if (part.Contains("S")) { n.s_type = 1; } else { n.t_type = 1; } float v = base2 + stepb * (d.readByte()); // float f = d.readFloat(); // System.out.println(stepb + " " + base + " " + (byte)d.readByte()); switch (part) { case "RX": n.r.X = (float)(Math.PI / 180f) * (v); break; case "RY": n.r.Y = (float)(Math.PI / 180f) * (v); break; case "RZ": n.r.Z = (float)(Math.PI / 180f) * (v); break; case "X": n.t.X = v; break; case "Y": n.t.Y = v; break; case "Z": n.t.Z = v; break; case "SX": n.s.X = v; break; case "SY": n.s.Y = v; break; case "SZ": n.s.Z = v; break; } } // System.out.println(d.pos()); } if (type == 0x6) { //if(debug) //System.out.println(part + "\tLin 4"); for (int i = 0; i < anim.size(); i++) { KeyNode n = anim.getNode(i, nid); if (part.Contains("R")) { n.r_type = 1; } else if (part.Contains("S")) { n.s_type = 1; } else { n.t_type = 1; } float v = d.readFloat(); switch (part) { case "RX": n.r.X = (float)(Math.PI / 180) * (v); break; case "RY": n.r.Y = (float)(Math.PI / 180) * (v); break; case "RZ": n.r.Z = (float)(Math.PI / 180) * (v); break; case "X": n.t.X = v; break; case "Y": n.t.Y = v; break; case "Z": n.t.Z = v; break; case "SX": n.s.X = v; break; case "SY": n.s.Y = v; break; case "SZ": n.s.Z = v; break; } } } d.seek(temp); }
public void Read(FileData d) { d.Endian = System.IO.Endianness.Big; d.seek(4); // skip filesize int dataSize = d.readInt(); int offsetTableCount = d.readInt(); int rootA = d.readInt(); int headerSize = 0x20; int rootOffset = headerSize + dataSize + offsetTableCount * 4; d.seek(rootOffset); int figtree = d.readInt() + headerSize; d.skip(4); String name = d.readString(d.pos(), -1); this.Name = name; d.seek(figtree); d.skip(8); float frameCount = d.readFloat(); int keyOffset = d.readInt(); if (Debug) { Console.WriteLine(name + "\tCount: " + frameCount); } this.frameCount = (int)frameCount; int temp = d.pos(); d.seek(keyOffset + 0x20); //int boneCount = 0x2E; // TODO: Use actual bone count 0x35 List <int> keyFrameCount = new List <int>(); int bid = d.readByte(); while (bid != 0xFF) { keyFrameCount.Add(bid); bid = d.readByte(); nodes.Add(new List <DATAnimTrack>()); } int boneCount = keyFrameCount.Count; if (Debug) { Console.WriteLine(boneCount); } d.seek(temp); int animDataOffset = 0; int[] trackcount = new int[offsetTableCount]; for (int i = 0; i < offsetTableCount; i++) { trackcount[i] = d.readInt(); if (i == 0) { animDataOffset = trackcount[i]; } } d.seek(animDataOffset + 0x20); for (int i = 0; i < boneCount; i++) { // bonecount if (Debug) { Console.WriteLine("Bone " + i + ": " + keyFrameCount[i] + "\t" + d.pos().ToString("x")); } for (int j = 0; j < keyFrameCount[i]; j++) { int length = d.readShort(); d.skip(2); int trackType = d.readByte(); int valueFormat = d.readByte(); int tanFormat = d.readByte(); d.skip(1); int dataoff = d.readInt() + 0x20; if (Debug) { Console.WriteLine((AnimType)trackType + "\tLength: " + length + "\tOffset: " + dataoff.ToString("x") + " " + valueFormat.ToString("x") + " " + tanFormat.ToString("x")); } // System.out.println(valueFormat + " " + tanFormat); readKeyFrame(d, length, dataoff, valueFormat, tanFormat, keyFrameCount[i], i, trackType); } } }
public static SkelAnimation read(FileData d) { d.Endian = Endianness.Big; d.skip(4); // header OMO d.skip(4); // two shorts, idk d.skip(4); //flags? d.skip(2); int numOfBones = d.readShort(); int frameSize = d.readShort(); int frameStart = d.readShort(); int offset1 = d.readInt(); int offset2 = d.readInt(); int offset3 = d.readInt(); SkelAnimation anim = new SkelAnimation(); anim.Tag = d; //anim.setModel(m); // base frames // These are linked to bones somehow, hash?? d.seek(offset1); // int[] framekey = new int[numOfBones]; KeyNode[] baseNode = new KeyNode[numOfBones]; for (int i = 0; i < numOfBones; i++) { flagsused = flagsused | d.readInt(); d.seek(d.pos() - 4); //Console.WriteLine(flagsused.ToString("x")); int flags = d.readByte(); int tFlag = d.readByte(); int rFlag = d.readByte(); int sFlag = d.readByte(); int hash = d.readInt(); // used to find the identifying bone int off1 = d.readInt() + offset2; framekey[i] = d.readInt(); bool hasTrans = (flags & 0x01) == 0x01; bool hasScale = (flags & 0x04) == 0x04; bool hasRot = (flags & 0x02) == 0x02; KeyNode node = new KeyNode(); baseNode[i] = node; node.hash = (uint)hash; int temp = d.pos(); d.seek(off1); if (hasTrans) { if (tFlag == 0x8) { // interpolated node.t_type = KeyNode.INTERPOLATED; node.t = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.t2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } else if (tFlag == 0x20) { node.t_type = KeyNode.CONSTANT; node.t = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } } if (hasRot) { if ((rFlag & 0xF) != 0x50 && (rFlag & 0xF0) != 0x70 && (rFlag & 0xF0) != 0x60 && (rFlag & 0xF0) != 0xA0) { //Console.WriteLine(rFlag); } if ((rFlag & 0xF0) == 0xA0) { node.r_type = 3; } if ((rFlag & 0xF0) == 0x50) { // interpolated node.r_type = KeyNode.INTERPOLATED; node.rv = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.rv2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } if ((rFlag & 0xF0) == 0x70 || (rFlag & 0xF0) == 0x60) { // constant node.r_type = KeyNode.CONSTANT; node.rv = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); if ((rFlag & 0xF0) == 0x60) { d.skip(4); } } } if (hasScale) { if ((sFlag & 0xF0) == 0x80) { // interpolated node.s_type = KeyNode.INTERPOLATED; node.s = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.s2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } if ((rFlag & 0x0F) == 0x02 || (rFlag & 0x0F) == 0x03) { // constant node.s_type = KeyNode.CONSTANT; node.s = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } } d.seek(temp); } d.seek(offset3); for (int i = 0; i < frameSize; i++) { KeyFrame key = new KeyFrame(); key.frame = i; int off = d.pos(); for (int j = 0; j < numOfBones; j++) { KeyNode node = new KeyNode(); node.t_type = baseNode[j].t_type; node.r_type = baseNode[j].r_type; node.s_type = baseNode[j].s_type; node.id = baseNode[j].id; node.hash = baseNode[j].hash; d.seek(off + framekey[j]); if (baseNode[j].t_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / 0xffff); float i2 = ((float)d.readShort() / 0xffff); float i3 = ((float)d.readShort() / 0xffff); float x = baseNode[j].t.X + (baseNode[j].t2.X * (i1)); float y = baseNode[j].t.Y + (baseNode[j].t2.Y * (i2)); float z = baseNode[j].t.Z + (baseNode[j].t2.Z * (i3)); node.t = new Vector3(x, y, z); } else { node.t = baseNode[j].t; } if (baseNode[j].r_type == 3) { int v = short.MaxValue; float i1 = ((float)((short)d.readShort()) / v); float i2 = ((float)((short)d.readShort()) / v); float i3 = ((float)((short)d.readShort()) / v); float i4 = ((float)((short)d.readShort()) / v); node.r = new Quaternion(new Vector3(i1, i2, i3), i4); //Console.WriteLine(node.r.ToString()); //node.r = VBN.FromEulerAngles(i4 * i1, i4 * i2, i4 * i3); node.r_type = KeyNode.INTERPOLATED; //node.r.Normalize(); } else if (baseNode[j].r_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / (0xffff)); float i2 = ((float)d.readShort() / (0xffff)); float i3 = ((float)d.readShort() / (0xffff)); float x = baseNode[j].rv.X + (baseNode[j].rv2.X * (i1)); float y = baseNode[j].rv.Y + (baseNode[j].rv2.Y * (i2)); float z = baseNode[j].rv.Z + (baseNode[j].rv2.Z * (i3)); float w = (float)Math.Sqrt(Math.Abs(1 - (x * x + y * y + z * z))); node.r = new Quaternion(new Vector3(x, y, z), w); node.r.Normalize(); } else { float x = baseNode[j].rv.X; float y = baseNode[j].rv.Y; float z = baseNode[j].rv.Z; float w = (float)Math.Sqrt(1 - (x * x + y * y + z * z)); node.r = new Quaternion(baseNode[j].rv, w); } if (baseNode[j].s_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / (0xffff)); float i2 = ((float)d.readShort() / (0xffff)); float i3 = ((float)d.readShort() / (0xffff)); float x = baseNode[j].s.X + (baseNode[j].s2.X * (i1)); float y = baseNode[j].s.Y + (baseNode[j].s2.Y * (i2)); float z = baseNode[j].s.Z + (baseNode[j].s2.Z * (i3)); node.s = new Vector3(x, y, z); } else { node.s = baseNode[j].s; } key.addNode(node); } d.seek(off + frameStart); anim.addKeyframe(key); } return(anim); }
public static Animation read(FileData d) { d.Endian = Endianness.Big; d.skip(4); // header OMO d.skip(4); // two shorts, idk d.skip(4); //flags? d.skip(2); int boneCount = d.readShort(); int frameCount = d.readShort(); int frameSize = d.readShort(); int offset1 = d.readInt(); // nodeOffset int offset2 = d.readInt(); // interOffset int offset3 = d.readInt(); // keyOffset SkelAnimation anim = new SkelAnimation(); anim.Tag = d; if (boneCount > offset2 / 0x10) { boneCount = offset2 / 0x10; anim.Tag = null; } // base frames // These are linked to bones via hashes d.seek(offset1); // int[] framekey = new int[boneCount]; KeyNode[] baseNode = new KeyNode[boneCount]; // Start positions for bones/nodes for (int i = 0; i < boneCount; i++) { flagsused = flagsused | d.readInt(); d.seek(d.pos() - 4); //Console.WriteLine(flagsused.ToString("x")); int flags = d.readByte(); int tFlag = d.readByte(); int rFlag = d.readByte(); int sFlag = d.readByte(); int hash = d.readInt(); // used to find the identifying bone int off1 = d.readInt() + offset2; framekey[i] = d.readInt(); bool hasTrans = (flags & 0x01) == 0x01; bool hasScale = (flags & 0x04) == 0x04; bool hasRot = (flags & 0x02) == 0x02; KeyNode node = new KeyNode(); baseNode[i] = node; node.hash = (uint)hash; int temp = d.pos(); d.seek(off1); if (hasTrans) { if (tFlag == 0x8) { // interpolated node.t_type = KeyNode.INTERPOLATED; node.t = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.t2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } else if (tFlag == 0x20) { node.t_type = KeyNode.CONSTANT; node.t = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } else if (tFlag == 0x4) { // entire Vector3 provided in keyframe data i.e. KEYFRAME type node.t_type = KeyNode.KEYFRAME; } } if (hasRot) { if ((rFlag & 0xF0) != 0x50 && (rFlag & 0xF0) != 0x70 && (rFlag & 0xF0) != 0x60 && (rFlag & 0xF0) != 0xA0) { //Console.WriteLine(rFlag); } if ((rFlag & 0xF0) == 0xA0) { // All data is in the keyframe for this type node.r_type = KeyNode.COMPRESSED; } if ((rFlag & 0xF0) == 0x50) { // interpolated node.r_type = KeyNode.INTERPOLATED; node.rv = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.rv2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } if ((rFlag & 0xF0) == 0x60) { node.r_type = KeyNode.KEYFRAME; node.rv = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.r_extra = d.readFloat() / 65535; } if ((rFlag & 0xF0) == 0x70) { node.r_type = KeyNode.CONSTANT; node.rv = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } } if (hasScale) { if ((sFlag & 0xF0) == 0x80) { // interpolated node.s_type = KeyNode.INTERPOLATED; node.s = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); node.s2 = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } // TODO: investigate the difference between these if ((rFlag & 0x0F) == 0x02 || (rFlag & 0x0F) == 0x03) { // constant node.s_type = KeyNode.CONSTANT; node.s = new Vector3(d.readFloat(), d.readFloat(), d.readFloat()); } } d.seek(temp); } // Interpolated type below here is always a set translation/rotation/scale // from the coords specified with the bone node above Animation a = new Animation("Anim"); a.Tag = anim.Tag; a.FrameCount = frameCount; d.seek(offset3); for (int j = 0; j < boneCount; j++) { string bid = ""; int hash = -1; if (!MainForm.Hashes.ids.TryGetValue(baseNode[j].hash, out bid)) { hash = (int)baseNode[j].hash; } Animation.KeyNode n = new Animation.KeyNode(bid); n.Hash = hash; a.Bones.Add(n); n.Type = Animation.BoneType.NORMAL; /*foreach (ModelContainer con in Runtime.ModelContainers) * if (con.VBN != null) * bid = con.VBN.getBone(baseNode[j].hash) == null ? "" : con.VBN.getBone(baseNode[j].hash).Text;*/ for (int i = 0; i < a.FrameCount; i++) { d.seek(offset3 + frameSize * i + framekey[j]); if (baseNode[j].t_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / 0xffff); float i2 = ((float)d.readShort() / 0xffff); float i3 = ((float)d.readShort() / 0xffff); float x = baseNode[j].t.X + (baseNode[j].t2.X * (i1)); float y = baseNode[j].t.Y + (baseNode[j].t2.Y * (i2)); float z = baseNode[j].t.Z + (baseNode[j].t2.Z * (i3)); //node.t = new Vector3(x, y, z); // Translation n.XPOS.Keys.Add(new Animation.KeyFrame(x, i)); n.YPOS.Keys.Add(new Animation.KeyFrame(y, i)); n.ZPOS.Keys.Add(new Animation.KeyFrame(z, i)); } else if (baseNode[j].t_type == KeyNode.CONSTANT) { //node.t = baseNode[j].t; n.XPOS.Keys.Add(new Animation.KeyFrame(baseNode[j].t.X, i)); n.YPOS.Keys.Add(new Animation.KeyFrame(baseNode[j].t.Y, i)); n.ZPOS.Keys.Add(new Animation.KeyFrame(baseNode[j].t.Z, i)); } else if (baseNode[j].t_type == 2) { float x = d.readFloat(); float y = d.readFloat(); float z = d.readFloat(); //node.t = new Vector3(x, y, z); n.XPOS.Keys.Add(new Animation.KeyFrame(x, i)); n.YPOS.Keys.Add(new Animation.KeyFrame(y, i)); n.ZPOS.Keys.Add(new Animation.KeyFrame(z, i)); } if (baseNode[j].r_type == KeyNode.COMPRESSED) { // There are 64 bits present for each node of this rot type // The format is: 20bits * 3 of encoded floats, and 4 bits of flags // The flags describe which 3 components of the quaternion are being presented int b1 = d.readByte(); int b2 = d.readByte(); int b3 = d.readByte(); int b4 = d.readByte(); int b5 = d.readByte(); int b6 = d.readByte(); int b7 = d.readByte(); int b8 = d.readByte(); // Capture 20 bits at a time of the raw data int f1 = (b1 << 12) | (b2 << 4) | ((b3 & 0xF0) >> 4); int f2 = ((b3 & 0xF) << 16) | (b4 << 8) | b5; int f3 = (b6 << 12) | (b7 << 4) | ((b8 & 0xF0) >> 4); int flags = b8 & 0xF; Quaternion r = new Quaternion(); switch (flags) { case 0: // y, z, w provided r.Y = encodedRot10ToQuaternionComponent(f1); r.Z = encodedRot10ToQuaternionComponent(f2); r.W = encodedRot10ToQuaternionComponent(f3); r.X = (float)Math.Sqrt(Math.Abs(1 - (r.Y * r.Y + r.Z * r.Z + r.W * r.W))); break; case 1: // x, z, w provided r.X = encodedRot10ToQuaternionComponent(f1); r.Z = encodedRot10ToQuaternionComponent(f2); r.W = encodedRot10ToQuaternionComponent(f3); r.Y = (float)Math.Sqrt(Math.Abs(1 - (r.X * r.X + r.Z * r.Z + r.W * r.W))); break; case 2: // x, y, w provided r.X = encodedRot10ToQuaternionComponent(f1); r.Y = encodedRot10ToQuaternionComponent(f2); r.W = encodedRot10ToQuaternionComponent(f3); r.Z = (float)Math.Sqrt(Math.Abs(1 - (r.X * r.X + r.Y * r.Y + r.W * r.W))); break; case 3: // x, y, z, provided r.X = encodedRot10ToQuaternionComponent(f1); r.Y = encodedRot10ToQuaternionComponent(f2); r.Z = encodedRot10ToQuaternionComponent(f3); r.W = (float)Math.Sqrt(Math.Abs(1 - (r.X * r.X + r.Y * r.Y + r.Z * r.Z))); break; default: Console.WriteLine("Unknown rotation type3 flags: " + flags); break; } n.RotType = Animation.RotationType.QUATERNION; n.XROT.Keys.Add(new Animation.KeyFrame(r.X, i)); n.YROT.Keys.Add(new Animation.KeyFrame(r.Y, i)); n.ZROT.Keys.Add(new Animation.KeyFrame(r.Z, i)); n.WROT.Keys.Add(new Animation.KeyFrame(r.W, i)); } else if (baseNode[j].r_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / (0xffff)); float i2 = ((float)d.readShort() / (0xffff)); float i3 = ((float)d.readShort() / (0xffff)); float x = baseNode[j].rv.X + (baseNode[j].rv2.X * (i1)); float y = baseNode[j].rv.Y + (baseNode[j].rv2.Y * (i2)); float z = baseNode[j].rv.Z + (baseNode[j].rv2.Z * (i3)); float w = (float)Math.Sqrt(Math.Abs(1 - (x * x + y * y + z * z))); Quaternion r = new Quaternion(new Vector3(x, y, z), w); r.Normalize(); n.RotType = Animation.RotationType.QUATERNION; n.XROT.Keys.Add(new Animation.KeyFrame(r.X, i)); n.YROT.Keys.Add(new Animation.KeyFrame(r.Y, i)); n.ZROT.Keys.Add(new Animation.KeyFrame(r.Z, i)); n.WROT.Keys.Add(new Animation.KeyFrame(r.W, i)); } else if (baseNode[j].r_type == KeyNode.KEYFRAME) { float scale = d.readShort() * baseNode[j].r_extra; float x = baseNode[j].rv.X; float y = baseNode[j].rv.Y; float z = baseNode[j].rv.Z + scale; float w = rot6CalculateW(x, y, z); Quaternion r = new Quaternion(x, y, z, w); n.RotType = Animation.RotationType.QUATERNION; n.XROT.Keys.Add(new Animation.KeyFrame(r.X, i)); n.YROT.Keys.Add(new Animation.KeyFrame(r.Y, i)); n.ZROT.Keys.Add(new Animation.KeyFrame(r.Z, i)); n.WROT.Keys.Add(new Animation.KeyFrame(r.W, i)); } else { float x = baseNode[j].rv.X; float y = baseNode[j].rv.Y; float z = baseNode[j].rv.Z; float w = (float)Math.Sqrt(Math.Abs(1 - (x * x + y * y + z * z))); Quaternion r = new Quaternion(baseNode[j].rv, w); r.Normalize(); n.RotType = Animation.RotationType.QUATERNION; n.XROT.Keys.Add(new Animation.KeyFrame(r.X, i)); n.YROT.Keys.Add(new Animation.KeyFrame(r.Y, i)); n.ZROT.Keys.Add(new Animation.KeyFrame(r.Z, i)); n.WROT.Keys.Add(new Animation.KeyFrame(r.W, i)); } if (baseNode[j].s_type == KeyNode.INTERPOLATED) { float i1 = ((float)d.readShort() / (0xffff)); float i2 = ((float)d.readShort() / (0xffff)); float i3 = ((float)d.readShort() / (0xffff)); float x = baseNode[j].s.X + (baseNode[j].s2.X * (i1)); float y = baseNode[j].s.Y + (baseNode[j].s2.Y * (i2)); float z = baseNode[j].s.Z + (baseNode[j].s2.Z * (i3)); //node.s = new Vector3(x, y, z); n.XSCA.Keys.Add(new Animation.KeyFrame(x, i)); n.YSCA.Keys.Add(new Animation.KeyFrame(y, i)); n.ZSCA.Keys.Add(new Animation.KeyFrame(z, i)); } else { //node.s = baseNode[j].s; n.XSCA.Keys.Add(new Animation.KeyFrame(baseNode[j].s.X, i)); n.YSCA.Keys.Add(new Animation.KeyFrame(baseNode[j].s.Y, i)); n.ZSCA.Keys.Add(new Animation.KeyFrame(baseNode[j].s.Z, i)); } } } return(a); }
public static AnimationGroupNode Read(string filename) { bchHeader header = new bchHeader(); FileData f = new FileData(filename); f.Endian = System.IO.Endianness.Little; f.skip(4); header.backwardCompatibility = f.readByte(); header.forwardCompatibility = f.readByte(); header.version = f.readUShort(); header.mainHeaderOffset = f.readInt(); header.stringTableOffset = f.readInt(); header.gpuCommandsOffset = f.readInt(); header.dataOffset = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedOffset = f.readInt(); } header.relocationTableOffset = f.readInt(); header.mainHeaderLength = f.readInt(); header.stringTableLength = f.readInt(); header.gpuCommandsLength = f.readInt(); header.dataLength = f.readInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedLength = f.readInt(); } header.relocationTableLength = f.readInt(); header.uninitializedDataSectionLength = f.readInt(); header.uninitializedDescriptionSectionLength = f.readInt(); if (header.backwardCompatibility > 7) { header.flags = f.readUShort(); header.addressCount = f.readUShort(); } // Relocation table for (int i = 0; i < header.relocationTableLength; i += 4) { f.seek(header.relocationTableOffset + i); int val = f.readInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.mainHeaderOffset); break; case 1: f.seek(off + header.mainHeaderOffset); f.writeInt((off) + header.mainHeaderOffset, f.readInt() + header.stringTableOffset); break; case 2: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.gpuCommandsOffset); break; case 0xc: f.seek((off * 4) + header.mainHeaderOffset); f.writeInt((off * 4) + header.mainHeaderOffset, f.readInt() + header.dataOffset); break; } } // Content Header f.seek(header.mainHeaderOffset); bchContentHeader content = new bchContentHeader(); { content.modelsPointerTableOffset = f.readInt(); content.modelsPointerTableEntries = f.readInt(); content.modelsNameOffset = f.readInt(); content.materialsPointerTableOffset = f.readInt(); content.materialsPointerTableEntries = f.readInt(); content.materialsNameOffset = f.readInt(); content.shadersPointerTableOffset = f.readInt(); content.shadersPointerTableEntries = f.readInt(); content.shadersNameOffset = f.readInt(); content.texturesPointerTableOffset = f.readInt(); content.texturesPointerTableEntries = f.readInt(); content.texturesNameOffset = f.readInt(); content.materialsLUTPointerTableOffset = f.readInt(); content.materialsLUTPointerTableEntries = f.readInt(); content.materialsLUTNameOffset = f.readInt(); content.lightsPointerTableOffset = f.readInt(); content.lightsPointerTableEntries = f.readInt(); content.lightsNameOffset = f.readInt(); content.camerasPointerTableOffset = f.readInt(); content.camerasPointerTableEntries = f.readInt(); content.camerasNameOffset = f.readInt(); content.fogsPointerTableOffset = f.readInt(); content.fogsPointerTableEntries = f.readInt(); content.fogsNameOffset = f.readInt(); content.skeletalAnimationsPointerTableOffset = f.readInt(); content.skeletalAnimationsPointerTableEntries = f.readInt(); content.skeletalAnimationsNameOffset = f.readInt(); content.materialAnimationsPointerTableOffset = f.readInt(); content.materialAnimationsPointerTableEntries = f.readInt(); content.materialAnimationsNameOffset = f.readInt(); content.visibilityAnimationsPointerTableOffset = f.readInt(); content.visibilityAnimationsPointerTableEntries = f.readInt(); content.visibilityAnimationsNameOffset = f.readInt(); content.lightAnimationsPointerTableOffset = f.readInt(); content.lightAnimationsPointerTableEntries = f.readInt(); content.lightAnimationsNameOffset = f.readInt(); content.cameraAnimationsPointerTableOffset = f.readInt(); content.cameraAnimationsPointerTableEntries = f.readInt(); content.cameraAnimationsNameOffset = f.readInt(); content.fogAnimationsPointerTableOffset = f.readInt(); content.fogAnimationsPointerTableEntries = f.readInt(); content.fogAnimationsNameOffset = f.readInt(); content.scenePointerTableOffset = f.readInt(); content.scenePointerTableEntries = f.readInt(); content.sceneNameOffset = f.readInt(); } //Skeletal animation AnimationGroupNode ThisAnimation = new AnimationGroupNode() { Text = filename }; for (int index1 = 0; index1 < content.skeletalAnimationsPointerTableEntries; index1++)// { f.seek(content.skeletalAnimationsPointerTableOffset + (index1 * 4)); int dataOffset = f.readInt(); f.seek(dataOffset); string skeletalAnimationName = f.readString(f.readInt(), -1); int animationFlags = f.readInt(); //int skeletalAnimationloopMode = f.readByte(); //pas ça du tout float skeletalAnimationframeSize = f.readFloat(); int boneTableOffset = f.readInt(); int boneTableEntries = f.readInt(); int metaDataPointerOffset = f.readInt(); //Runtime.Animations.Add(skeletalAnimationName, a); //MainForm.animNode.Nodes.Add(skeletalAnimationName); Animation a = new Animation(skeletalAnimationName); ThisAnimation.Nodes.Add(a); for (int i = 0; i < boneTableEntries; i++) { f.seek(boneTableOffset + (i * 4)); int offset = f.readInt(); Animation.KeyNode bone = new Animation.KeyNode(""); a.Bones.Add(bone); f.seek(offset); bone.Text = f.readString(f.readInt(), -1); //Console.WriteLine("Bone Name: " + bone.name); int animationTypeFlags = f.readInt(); uint flags = (uint)f.readInt(); OSegmentType segmentType = (OSegmentType)((animationTypeFlags >> 16) & 0xf); //Debug.WriteLine(bone.Text + " " + flags.ToString("x")); switch (segmentType) { case OSegmentType.transform: f.seek(offset + 0xC); //Console.WriteLine(f.pos().ToString("x") + " " + flags.ToString("x")); uint notExistMask = 0x10000; uint constantMask = 0x40; for (int j = 0; j < 3; j++) { for (int axis = 0; axis < 3; axis++) { bool notExist = (flags & notExistMask) > 0; bool constant = (flags & constantMask) > 0; //Console.WriteLine(notExist + " " + constant); Animation.KeyGroup group = new Animation.KeyGroup(); //frame.exists = !notExist; if (!notExist) { if (constant) { Animation.KeyFrame frame = new Animation.KeyFrame(); frame.InterType = Animation.InterpolationType.LINEAR; frame.Value = f.readFloat(); frame.Frame = 0; group.Keys.Add(frame); } else { int frameOffset = f.readInt(); int position = f.pos(); f.seek(frameOffset); float c = 0; //Debug.WriteLine(j + " " + axis + " " + bone.Text); getAnimationKeyFrame(f, group, out c); if (c > a.FrameCount) { a.FrameCount = (int)c; } f.seek(position); } } else { f.seek(f.pos() + 0x04); } bone.RotType = Animation.RotationType.EULER; if (j == 0) { switch (axis) { case 0: bone.XSCA = group; break; case 1: bone.YSCA = group; break; case 2: bone.ZSCA = group; break; } } else if (j == 1) { switch (axis) { case 0: bone.XROT = group; break; case 1: bone.YROT = group; break; case 2: bone.ZROT = group; break; } } else if (j == 2) { switch (axis) { case 0: bone.XPOS = group; break; case 1: bone.YPOS = group; break; case 2: bone.ZPOS = group; break; } } notExistMask <<= 1; constantMask <<= 1; } if (j == 1) { constantMask <<= 1; } } break; /*case OSegmentType.transformQuaternion: * bone.isFrameFormat = true; * * int scaleOffset = f.readInt(); * int rotationOffset = f.readInt(); * int translationOffset = f.readInt(); * * if ((flags & 0x20) == 0) * { * bone.scale.exists = true; * f.seek(scaleOffset); * * if ((flags & 4) > 0) * { * bone.scale.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * 0)); * } * else * { * bone.scale.startFrame = f.readFloat(); * bone.scale.endFrame = f.readFloat(); * * int scaleFlags = f.readInt(); * int scaleDataOffset = f.readInt(); * int scaleEntries = f.readInt(); * * f.seek(scaleDataOffset); * for (int j = 0; j < scaleEntries; j++) * { * bone.scale.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * 0)); * } * } * } * * if ((flags & 0x10) == 0) * { * bone.rotationQuaternion.exists = true; * f.seek(rotationOffset); * * if ((flags & 2) > 0) * { * bone.rotationQuaternion.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * f.readFloat())); * } * else * { * bone.rotationQuaternion.startFrame = f.readFloat(); * bone.rotationQuaternion.endFrame = f.readFloat(); * * int rotationFlags = f.readInt(); * int rotationDataOffset = f.readInt(); * int rotationEntries = f.readInt(); * * f.seek(rotationDataOffset); * for (int j = 0; j < rotationEntries; j++) * { * bone.rotationQuaternion.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * f.readFloat())); * } * } * } * * if ((flags & 8) == 0) * { * bone.translation.exists = true; * f.seek(translationOffset); * * if ((flags & 1) > 0) * { * bone.translation.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * 0)); * } * else * { * bone.translation.startFrame = f.readFloat(); * bone.translation.endFrame = f.readFloat(); * * int translationFlags = f.readInt(); * int translationDataOffset = f.readInt(); * int translationEntries = f.readInt(); * * f.seek(translationDataOffset); * for (int j = 0; j < translationEntries; j++) * { * bone.translation.vector.Add(new Vector4( * f.readFloat(), * f.readFloat(), * f.readFloat(), * 0)); * } * } * } * * break; * case OSegmentType.transformMatrix: * bone.isFullBakedFormat = true; * * f.readInt(); * f.readInt(); * int matrixOffset = f.readInt(); * int entries = f.readInt(); * * f.seek(matrixOffset); * for (int j = 0; j < entries; j++) * { * OMatrix transform = new OMatrix(); * transform.M11 = f.readFloat(); * transform.M21 = f.readFloat(); * transform.M31 = f.readFloat(); * transform.M41 = f.readFloat(); * * transform.M12 = f.readFloat(); * transform.M22 = f.readFloat(); * transform.M32 = f.readFloat(); * transform.M42 = f.readFloat(); * * transform.M13 = f.readFloat(); * transform.M23 = f.readFloat(); * transform.M33 = f.readFloat(); * transform.M43 = f.readFloat(); * * bone.transform.Add(transform); * } * * break;*/ default: throw new Exception(string.Format("BCH: Unknow Segment Type {0} on Skeletal Animation bone {1}! STOP!", segmentType, bone.Text)); } //skeletalAnimation.bone.Add(bone); } } //return a; return(ThisAnimation); }
public int readOffset(FileData f) { return(f.pos() + f.readInt()); }
public override void Read(string filename) { FileData file = new FileData(filename); if (file != null) { file.Endian = Endianness.Little; Endian = Endianness.Little; string magic = file.readString(0, 4); if (magic == "VBN ") { file.Endian = Endianness.Big; Endian = Endianness.Big; } file.seek(4); unk_1 = file.readShort(); unk_2 = file.readShort(); totalBoneCount = (UInt32)file.readInt(); boneCountPerType[0] = (UInt32)file.readInt(); boneCountPerType[1] = (UInt32)file.readInt(); boneCountPerType[2] = (UInt32)file.readInt(); boneCountPerType[3] = (UInt32)file.readInt(); int[] pi = new int[totalBoneCount]; for (int i = 0; i < totalBoneCount; i++) { Bone temp = new Bone(this); temp.Text = file.readString(file.pos(), -1); file.skip(64); temp.boneType = (UInt32)file.readInt(); pi[i] = file.readInt(); temp.boneId = (UInt32)file.readInt(); temp.position = new float[3]; temp.rotation = new float[3]; temp.scale = new float[3]; //temp.isSwingBone = temp.Text.Contains("__swing"); bones.Add(temp); } for (int i = 0; i < bones.Count; i++) { bones[i].position[0] = file.readFloat(); bones[i].position[1] = file.readFloat(); bones[i].position[2] = file.readFloat(); bones[i].rotation[0] = file.readFloat(); bones[i].rotation[1] = file.readFloat(); bones[i].rotation[2] = file.readFloat(); bones[i].scale[0] = file.readFloat(); bones[i].scale[1] = file.readFloat(); bones[i].scale[2] = file.readFloat(); Bone temp = bones[i]; temp.parentIndex = pi[i]; //Debug.Write(temp.parentIndex); //if (temp.parentIndex != 0x0FFFFFFF && temp.parentIndex > -1) // bones[temp.parentIndex].children.Add(i); bones[i] = temp; } reset(); } }
public void Read(FileData f) { f.Endian = Endianness.Little; f.seek(4); int count = f.readInt(); f.skip(12); int dataCount = f.readInt(); int boneCount = f.readInt(); int hashCount = f.readInt(); int hashOffset = f.readInt() + 0x28; f.skip(4); int pos = f.pos(); f.seek(hashOffset); csvHashes csv = new csvHashes(Path.Combine(MainForm.executableDir, "hashTable.csv")); List <string> bonename = new List <string>(); for (int i = 0; i < hashCount; i++) { uint hash = (uint)f.readInt(); Console.WriteLine(csv.ids[hash]); bonename.Add(csv.ids[hash]); } f.seek(pos); Console.WriteLine("Count " + count); for (int i = 0; i < dataCount; i++) { Console.WriteLine("Bone " + i + " start at " + f.pos().ToString("x")); // 3 sections int secLength = f.readInt(); int someCount = f.readInt(); // usually 2? for (int sec = 0; sec < 5; sec++) { int size = f.readInt(); int id = f.readInt(); Console.WriteLine(id + ":\t" + size.ToString("x")); for (int j = 0; j < ((size - 1) / 4) - 1; j++) { if (id == 4) { short b1 = f.readShort(); short b2 = f.readShort(); Console.Write("\t" + (b1 == -1 ? b1 + "" : bonename[b1]) + " " + b2 + "\t"); } else if (id == 5) { short b1 = f.readShort(); short b2 = f.readShort(); Console.Write("\t" + (b1 == -1 ? b1 + "" : bonename[b1]) + " " + (b2 == -1 ? b2 + "" : bonename[b2]) + "\t"); } else { Console.Write("\t" + (f.readUShort() / (id == 7 ? (float)0xffff : 1)) + " " + (f.readUShort() / (id == 7 ? (float)0xffff : 1)) + "\t"); } } Console.WriteLine(); } f.skip(8); } Console.WriteLine("0x" + f.pos().ToString("X")); f.skip(8); int hashSize = f.readInt(); int unk = f.readInt(); }
public void read(FileData f) { f.skip(0xD); name = f.readString(f.pos(), 0x38); f.skip(0x38); f.skip(1);//Seperation char subname = f.readString(f.pos(), 0x40); f.skip(0x40); f.skip(1);//Seperation char startPos[0] = f.readFloat(); startPos[1] = f.readFloat(); startPos[2] = f.readFloat(); useStartPos = (f.readByte() != 0); f.skip(1);//Seperation char unk2 = f.readInt(); f.skip(1); unk3 = f.read(0xC); f.skip(4); //FF FF FF FF f.skip(1); //Seperation char unk4 = new char[0x40]; for (int i = 0; i < 0x40; i++) { unk4[i] = (char)f.readByte(); } flag1 = Convert.ToBoolean(f.readByte()); flag2 = Convert.ToBoolean(f.readByte()); flag3 = Convert.ToBoolean(f.readByte()); flag4 = Convert.ToBoolean(f.readByte()); f.skip(1);//Seperation char //f.skip(0xAA); //Console.WriteLine(f.pos()); int vertCount = f.readInt(); for (int i = 0; i < vertCount; i++) { f.skip(1);//Seperation char Vector2D temp = new Vector2D(); temp.x = f.readFloat(); temp.y = f.readFloat(); verts.Add(temp); } f.skip(1);//Seperation char int normalCount = f.readInt(); for (int i = 0; i < normalCount; i++) { f.skip(1);//Seperation char Vector2D temp = new Vector2D(); temp.x = f.readFloat(); temp.y = f.readFloat(); normals.Add(temp); } f.skip(1); //Seperation char int cliffCount = f.readInt(); //CLIFFS tend to be useless f.skip(0xFC * cliffCount); //Standard CLIFFS are 0xFC in length, just skip em all f.skip(1); //Seperation char int materialCount = f.readInt(); for (int i = 0; i < materialCount; i++) { f.skip(1); //Seperation char CollisionMat temp = new CollisionMat(); temp.material = f.read(0xC); //Temporary, will work on fleshing out material more later materials.Add(temp); } }