override public void decode(EndianBinaryReader binReader) { actorId = binReader.ReadInt16(); m_byte = binReader.ReadSByte(); m_date = binReader.ReadDate(); m_float = binReader.ReadFloat(); testStruct = new sendLogin_testStructVO(); testStruct.decode(binReader); var len_playerList = binReader.ReadUInt16(); playerList = new sendLogin_playerListVO[len_playerList]; for (int i = 0; i < len_playerList; i++) { playerList[i] = new sendLogin_playerListVO(); playerList[i].decode(binReader); } }
public void decode(EndianBinaryReader binReader) { battleId = binReader.ReadInt16(); teamId = binReader.ReadInt16(); actorId = binReader.ReadInt16(); curX = binReader.ReadInt16(); curY = binReader.ReadInt16(); fast = binReader.ReadBoolean(); }
public void modelOpen() { string path = textBox1.Text; EndianBinaryReader readModel = new EndianBinaryReader(File.OpenRead(path), Endianness.LittleEndian); nsbmd = new NSBMD_File(); if (readModel.ReadString(Encoding.ASCII, 4) != "BMD0") { readModel.Close(); return; } else { nsbmd.Header.ID = "BMD0"; nsbmd.Header.Magic = readModel.ReadBytes(4); nsbmd.Header.file_size = readModel.ReadInt32(); nsbmd.Header.header_size = readModel.ReadInt16(); nsbmd.Header.nSection = readModel.ReadInt16(); nsbmd.Header.Section_Offset = new Int32[nsbmd.Header.nSection]; for (int i = 0; i < nsbmd.Header.nSection; i++) { nsbmd.Header.Section_Offset[i] = readModel.ReadInt32(); } nsbmd.MDL0.ID = readModel.ReadString(Encoding.ASCII, 4); if (nsbmd.MDL0.ID != "MDL0") { readModel.Close(); return; } nsbmd.MDL0.Section_size = readModel.ReadInt32(); nsbmd.MDL0.Padding1 = readModel.ReadByte(); nsbmd.MDL0.Model_count = readModel.ReadByte(); nsbmd.MDL0.Section_size = readModel.ReadInt16(); nsbmd.MDL0.Constant = readModel.ReadInt16(); nsbmd.MDL0.Subsection_size = readModel.ReadInt16(); nsbmd.MDL0.Constant2 = readModel.ReadInt32(); nsbmd.MDL0.Unknown = new int[nsbmd.MDL0.Model_count]; for (int i = 0; i < nsbmd.MDL0.Model_count; i++) { nsbmd.MDL0.Unknown[i] = readModel.ReadInt32(); } nsbmd.MDL0.Constant3 = readModel.ReadInt16(); nsbmd.MDL0.Section2_size = readModel.ReadInt16(); nsbmd.MDL0.Model_offset = new int[nsbmd.MDL0.Model_count]; for (int i = 0; i < nsbmd.MDL0.Model_count; i++) { nsbmd.MDL0.Model_offset[i] = readModel.ReadInt32(); } nsbmd.MDL0.Model_name = new string[nsbmd.MDL0.Model_count]; for (int i = 0; i < nsbmd.MDL0.Model_count; i++) { nsbmd.MDL0.Model_name[i] = readModel.ReadString(Encoding.ASCII, 16); } readModel.Close(); } }
override public void decode(EndianBinaryReader binReader) { battleId = binReader.ReadInt16(); var len_damageList = binReader.ReadUInt16(); damageList = new CommonStructVO[len_damageList]; for (int i = 0; i < len_damageList; i++) { damageList[i] = new CommonStructVO(); damageList[i].decode(binReader); } }
/* * I've been studying the NSBCA format heavily over the last few days trying to figure it out. * I've determined that the first offset in a joint animation contains Pivoting data, and the second section contains Rotation data. * Rotation keyframes are called when the second byte equals 0 and Pivot keyframes are called when it equals 128, however the data itself is definitely stored a little differently to how it is stored in NSBMD files. * Scaling keyframes hold two scaling values for whatever reason, with Translation keyframes being just straight values that can be a signed word/dword. * Each animation has a frame length, however each object in an animation seems to have a start and end position that typically don't match up with the total number of frames. * Now I haven't had much experience with model animations, but I'm guessing this might have like a decay effect on the animation if anyone has ever played around with animations in Maya? * The trickiest part is calculating the right number of keyframes stored in each object as there isn't an actual value written down anywhere. * From what I can tell it's calculated based on a bunch of things including the difference in object frame length over animation frame length, the rate in which the object (and possibly the animation) plays back as well as rounding to the upper whole number. * This looks a bit funky and overcomplicated but so far all the animations I've been working with calculate the correct number of keyframes, so I'm assuming I'm on the right track. * Am yet to get to the point of loading animations into a model, but hopefully I won't get some spastic result :S Object Flag: --zyx-Sr-RZYX-T- > found in the header of each object of an animation =========================== T - has Translation keyframes (0 Yes| 1 No) XYZ - flags for Translation attributes R - has Rotation/Pivot keyframes (0 Yes| 1 No) r - flag for Rotation/Pivot attribute S - has Scale keyframes (0 Yes| 1 No) xyz - flags for Scale attributes =========================== if T-XYZ = 1 > Fixed Translation value (signed dword) if R-r = 1 > Fixed Rotation/Pivot value (dword/2*word?) if S-xyz = 1 > Fixed Scale value (2*dword) Note: The below is only done when the bit flag equals 0 for that attribute (TX, TY, TZ, R/P, SX, SY, SZ) a|b = datasize = playback speed > a & b are flags stored in the object header for each attribute Translate ----------------------------------------------------------- 2|0 = word = 1/1 2|1 = word = 1/2 2|2 = word = 1/3 0|1 = dword = 1/2 Rotate ----------------------------------------------------------- 0|0 = 2*byte = 1/1 0|1 = 2*byte = 1/2 0|2 = 2*byte = 1/3 > byte0 = index > byte1 = 0 Rotation | 128 Pivot > not completely sure on rotation yet Scale ----------------------------------------------------------- 2|1 = 2*word = 1/1 2|1 = 2*word = 1/2 ----------------------------------------------------------- Attribute [animation flag|start|end|a|b] bytes/keyframes - animation length > bytes - the actual size of the data stored > keyframes - bytes/datasize(see above) Basabasa - 0 Pivot - 33 Rotation =========================================================== Translate [3|0|34|2|1] 38/19 - 36 Frames Rotate [3|0|34|0|1] 38/19 - 36 Frames Scale [3|0|34|2|1] 76/19 - 36 Frames =========================================================== Basabasa2 - 1 Pivot - 20 Rotation =========================================================== Rotate [3|0|78|0|1] 82/41 - 80 Frames =========================================================== Bilikyu - 31 Pivot =========================================================== Translate [3|0|58|2|1] 62/31 - 60 Frames Rotate [3|0|58|0|1] 62/31 - 60 Frames =========================================================== Donketu - 12 Pivot / 20 Rotation =========================================================== Translate [3|0|10|0|1] 24/06 - 11 Frames (dword) Translate [3|0|10|2|1] 12/06 - 11 Frames Translate [1|0|02|2|0] 04/02 - 02 Frames Rotate [3|0|10|0|1] 14/07 - 11 Frames =========================================================== Gesso - 39 Pivot =========================================================== Translate [0|0|16|2|2] 14/07 - 19 Frames Translate [0|0|16|2|2] 12/06 - 18 Frames Translate [0|0|12|2|2] 10/05 - 14 Frames Scale [0|0|16|2|2] 28/07 - 19 Frames Scale [0|0|16|2|2] 24/06 - 18 Frames Rotate [0|0|16|0|2] 16/08 - 19 Frames Rotate [0|0|16|0|2] 16/08 - 18 Frames Rotate [0|0|12|0|2] 14/07 - 14 Frames =========================================================== TTL Bird =========================================================== Translate [1|0|05|2|0] 10/05 - 05 Frames Rotate [1|0|05|0|0] 10/05 - 05 Frames =========================================================== Gamaguchi - 11 Pivot - 52 Rotation =========================================================== Translate [3|0|08|2|0] 16/08 - 08 Frames Translate [3|0|07|2|0] 14/07 - 07 Frames Translate [3|0|16|2|0] 32/16 - 16 Frames Rotate [3|0|08|0|0] 16/08 - 08 Frames Rotate [1|0|07|0|0] 14/07 - 07 Frames Rotate [3|0|16|0|0] 32/16 - 16 Frames Scale [3|0|08|2|0] 32/08 - 08 Frames Scale [1|0|07|2|0] 28/07 - 07 Frames =========================================================== */ public static NSBCA_File Read(string Filename) { byte[] file_ = File.ReadAllBytes(Filename); if (file_[0] == 76 && file_[1] == 90 && file_[2] == 55 && file_[3] == 55) { } EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(file_), Endianness.LittleEndian); NSBCA_File ns = new NSBCA_File(); ns.Header.ID = er.ReadString(Encoding.ASCII, 4); if (ns.Header.ID == "BCA0") { ns.Header.Magic = er.ReadBytes(4); ns.Header.file_size = er.ReadInt32(); ns.Header.header_size = er.ReadInt16(); ns.Header.nSection = er.ReadInt16(); ns.Header.Section_Offset = new Int32[ns.Header.nSection]; for (int i = 0; i < ns.Header.nSection; i++) { ns.Header.Section_Offset[i] = er.ReadInt32(); } ns.JNT0.ID = er.ReadString(Encoding.ASCII, 4); if (ns.JNT0.ID == "JNT0") { ns.JNT0.Size = er.ReadInt32(); //3D Info Structure ns.JNT0.dummy = er.ReadByte(); ns.JNT0.num_objs = er.ReadByte(); ns.JNT0.section_size = er.ReadInt16(); ns.JNT0.unknownBlock.header_size = er.ReadInt16(); ns.JNT0.unknownBlock.section_size = er.ReadInt16(); ns.JNT0.unknownBlock.constant = er.ReadInt32(); ns.JNT0.unknownBlock.unknown1 = new short[ns.JNT0.num_objs]; ns.JNT0.unknownBlock.unknown2 = new short[ns.JNT0.num_objs]; for (int i = 0; i < ns.JNT0.num_objs; i++) { ns.JNT0.unknownBlock.unknown1[i] = er.ReadInt16(); ns.JNT0.unknownBlock.unknown2[i] = er.ReadInt16(); } ns.JNT0.infoBlock.header_size = er.ReadInt16(); ns.JNT0.infoBlock.data_size = er.ReadInt16(); ns.JNT0.infoBlock.Data = new NSBCA_File.jnt0.Info.info[ns.JNT0.num_objs]; for (int i = 0; i < ns.JNT0.num_objs; i++) { ns.JNT0.infoBlock.Data[i].Objectoffset = er.ReadInt32(); } ns.JNT0.names = new string[ns.JNT0.num_objs]; for (int i = 0; i < ns.JNT0.num_objs; i++) { ns.JNT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", ""); } ns.JAC = new NSBCA_File.J_AC[ns.JNT0.num_objs]; for (int i = 0; i < ns.JNT0.num_objs; i++) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset; ns.JAC[i].ID = er.ReadString(Encoding.ASCII, 4); if (ns.JAC[i].ID == "J" + (char)0x00 + "AC") { ns.JAC[i].NrFrames = er.ReadInt16(); ns.JAC[i].NrObjects = er.ReadInt16(); ns.JAC[i].Unknown1 = er.ReadInt32(); ns.JAC[i].Offset1 = er.ReadInt32(); ns.JAC[i].Offset2 = er.ReadInt32(); long curposs = er.BaseStream.Position; if (ns.JAC[i].Offset2 != ns.JAC[i].Offset1) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].Offset1; ns.JAC[i].JointData = er.ReadBytes(ns.JAC[i].Offset2 - ns.JAC[i].Offset1); er.BaseStream.Position = curposs; } long dataoffset = 0; ns.JAC[i].ObjInfoOffset = new Int32[ns.JAC[i].NrObjects]; for (int j = 0; j < ns.JAC[i].NrObjects; j++) { ns.JAC[i].ObjInfoOffset[j] = er.ReadInt16(); } ns.JAC[i].ObjInfo = new NSBCA_File.J_AC.objInfo[ns.JAC[i].NrObjects]; for (int j = 0; j < ns.JAC[i].NrObjects; j++) { er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].ObjInfoOffset[j];// + 8; ns.JAC[i].ObjInfo[j].Flag = er.ReadInt16(); ns.JAC[i].ObjInfo[j].Unknown1 = er.ReadByte(); ns.JAC[i].ObjInfo[j].ID = er.ReadByte(); ns.JAC[i].ObjInfo[j].translate = new List<float>[3]; ns.JAC[i].ObjInfo[j].translate[0] = new List<float>(); ns.JAC[i].ObjInfo[j].translate[1] = new List<float>(); ns.JAC[i].ObjInfo[j].translate[2] = new List<float>(); ns.JAC[i].ObjInfo[j].translate_keyframes = new List<float>[3]; ns.JAC[i].ObjInfo[j].translate_keyframes[0] = new List<float>(); ns.JAC[i].ObjInfo[j].translate_keyframes[1] = new List<float>(); ns.JAC[i].ObjInfo[j].translate_keyframes[2] = new List<float>(); ns.JAC[i].ObjInfo[j].rotate = new List<float>(); ns.JAC[i].ObjInfo[j].rotate_keyframes = new List<float>[2]; ns.JAC[i].ObjInfo[j].rotate_keyframes[0] = new List<float>(); ns.JAC[i].ObjInfo[j].rotate_keyframes[1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale = new List<float>[3][]; ns.JAC[i].ObjInfo[j].scale[0] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale[1] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale[2] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale[0][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale[0][1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale[1][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale[1][1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale[2][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale[2][1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes = new List<float>[3][]; ns.JAC[i].ObjInfo[j].scale_keyframes[0] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale_keyframes[1] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale_keyframes[2] = new List<float>[2]; ns.JAC[i].ObjInfo[j].scale_keyframes[0][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes[0][1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes[1][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes[1][1] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes[2][0] = new List<float>(); ns.JAC[i].ObjInfo[j].scale_keyframes[2][1] = new List<float>(); double[] speed = { 1.0D, 0.5D, 0.33333333333333331D }; if (((ns.JAC[i].ObjInfo[j].Flag >> 1) & 1) == 0) { //struct.DModelAnimation.MTransformAni trans[] = new struct.DModelAnimation.MTransformAni[3]; //string msg = new StringBuilder().Append(msg).Append("\n -> Translate: ").ToString(); //string[] type = { "X", "Y", "Z" }; for (int k = 0; k < 3; k++) { //trans[k] = new struct.DModelAnimation.MTransformAni(this); int tflag = ns.JAC[i].ObjInfo[j].Flag >> 3 + k & 1; //msg = new StringBuilder().Append(msg).Append("\n -> T").Append(type[k]).Append(tflag).Append("[").ToString(); if (tflag == 1) { int tvar = er.ReadInt32(); //trans[k].setFrame((float)tvar / divide); ns.JAC[i].ObjInfo[j].translate[k].Add((float)tvar / 4096f); //msg = (new StringBuilder()).Append(msg).Append(tvar).ToString(); continue; } else { int param2 = er.ReadInt32(); int startFrame = param2 & 0xffff; ns.JAC[i].ObjInfo[j].tStart = startFrame; int endFrame = param2 >> 16 & 0xfff; ns.JAC[i].ObjInfo[j].tEnd = endFrame; int var2 = param2 >> 28 & 3; int speedId = param2 >> 30 & 3; int toffset = er.ReadInt32(); int width = var2 != 0 ? 2 : 4; int extra = (ns.JAC[i].Unknown1 != 3 ? 0 : ns.JAC[i].NrFrames - endFrame); int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames + extra) * speed[speedId]); long curpos = er.BaseStream.Position; for (int t = 0; t < length; t++) { er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + toffset + (t * width); if (dataoffset == 0) { dataoffset = toffset; } float keyFrame = (width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16()); ns.JAC[i].ObjInfo[j].translate_keyframes[k].Add((float)LibNDSFormats.NSBMD.NsbmdGlRenderer.sign((int)keyFrame, (width != 2 ? 32 : 16)) / 4096f); //m = (new StringBuilder()).append(m).append("\n -> #").append(t).append(": ").append(keyFrame).toString(); } er.BaseStream.Position = curpos; } } } if (((ns.JAC[i].ObjInfo[j].Flag >> 6) & 1) == 0) { int rflag = ns.JAC[i].ObjInfo[j].Flag >> 8 & 1; if (rflag == 1) { //dataParser _tmp14 = pa; int rvar = er.ReadInt32(); //dataParser.getInt(data, jump, 4); ns.JAC[i].ObjInfo[j].rotate.Add((float)rvar); //msg = (new StringBuilder()).append(msg).append(rvar).toString(); //jump += 4; } else { int param2 = er.ReadInt32(); int startFrame = param2 & 0xffff; ns.JAC[i].ObjInfo[j].rStart = startFrame; int endFrame = param2 >> 16 & 0xfff; ns.JAC[i].ObjInfo[j].rEnd = endFrame; int var2 = param2 >> 28 & 3; int speedId = param2 >> 30 & 3; int roffset = er.ReadInt32(); int width = 2;//var2 != 0 ? 2 : 4; int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames) * speed[speedId]); long curpos = er.BaseStream.Position; for (int r = 0; r < length; r++) { er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + roffset + (r * width); if (dataoffset == 0) { dataoffset = roffset; } int rvar6 = er.ReadInt16(); int rindex = rvar6 & 0x7fff; int mode = rvar6 >> 15 & 1; ns.JAC[i].ObjInfo[j].rotate_keyframes[0].Add(rindex); ns.JAC[i].ObjInfo[j].rotate_keyframes[1].Add(mode); } er.BaseStream.Position = curpos; } } if ((ns.JAC[i].ObjInfo[j].Flag >> 9 & 1) == 0) { //struct.DModelAnimation.MScaleAni scale[] = new struct.DModelAnimation.MScaleAni[3]; //msg = (new StringBuilder()).append(msg).append("\n -> Scale: ").toString(); for (int k = 0; k < 3; k++) { //scale[k] = new struct.DModelAnimation.MScaleAni(this); int sflag = ns.JAC[i].ObjInfo[j].Flag >> 11 + k & 1; //msg = (new StringBuilder()).append(msg).append("\n -> S").append(type[k]).append(sflag).append("[").toString(); if (sflag == 1) { //dataParser _tmp19 = pa; int svar1 = er.ReadInt32();//dataParser.getInt(data, jump, 4); ns.JAC[i].ObjInfo[j].scale[k][0].Add((float)svar1 / 4096f); //dataParser _tmp20 = pa; int svar2 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4); ns.JAC[i].ObjInfo[j].scale[k][1].Add((float)svar2 / 4096f); //int svar3 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4); //int svar4 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4); //ns.JAC[i].ObjInfo[j].scale[k][1].Add((float)svar2 / 4096f); //scale[k].setFrame(new float[] { // (float)svar1 / divide, (float)svar2 / divide //}); //msg = (new StringBuilder()).append(msg).append(svar1).append("|").append(svar2).toString(); //jump += 8; continue; } else { int param2 = er.ReadInt32(); int startFrame = param2 & 0xffff; ns.JAC[i].ObjInfo[j].sStart = startFrame; int endFrame = param2 >> 16 & 0xfff; ns.JAC[i].ObjInfo[j].sEnd = endFrame; int var2 = param2 >> 28 & 3; int speedId = param2 >> 30 & 3; int soffset = er.ReadInt32(); int width = var2 != 0 ? 2 : 4; int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames) * speed[speedId]); long curpos = er.BaseStream.Position; for (int s = 0; s < length; s++) { er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + soffset + (s * width * 2); if (dataoffset == 0) { dataoffset = soffset; } ns.JAC[i].ObjInfo[j].scale_keyframes[k][0].Add((float)(width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16()) / 4096f); ns.JAC[i].ObjInfo[j].scale_keyframes[k][1].Add((float)(width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16()) / 4096f); } er.BaseStream.Position = curpos; } } } } if (dataoffset != 0) { curposs = er.BaseStream.Position; er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].Offset2; ns.JAC[i].RotationData = er.ReadBytes((int)dataoffset - ns.JAC[i].Offset2); er.BaseStream.Position = curposs; } } else { //MessageBox.Show("Error"); er.Close(); return ns; } } } else { //MessageBox.Show("Error"); er.Close(); return ns; } } else { //MessageBox.Show("Error"); er.Close(); return ns; } er.Close(); return ns; }
public NodeData(EndianBinaryReader er) { flag = er.ReadUInt16(); _00 = er.ReadInt16(); if ((flag & NNS_G3D_SRTFLAG_TRANS_ZERO) == 0) { Tx = er.ReadFx32(); Ty = er.ReadFx32(); Tz = er.ReadFx32(); } if ((flag & NNS_G3D_SRTFLAG_ROT_ZERO) == 0 && (flag & NNS_G3D_SRTFLAG_PIVOT_EXIST) == 0) { _01 = er.ReadFx16(); _02 = er.ReadFx16(); _10 = er.ReadFx16(); _11 = er.ReadFx16(); _12 = er.ReadFx16(); _20 = er.ReadFx16(); _21 = er.ReadFx16(); _22 = er.ReadFx16(); } if ((flag & NNS_G3D_SRTFLAG_ROT_ZERO) == 0 && (flag & NNS_G3D_SRTFLAG_PIVOT_EXIST) != 0) { A = er.ReadFx16(); B = er.ReadFx16(); } if ((flag & NNS_G3D_SRTFLAG_SCALE_ONE) == 0) { Sx = er.ReadFx32(); Sy = er.ReadFx32(); Sz = er.ReadFx32(); InvSx = er.ReadFx32(); InvSy = er.ReadFx32(); InvSz = er.ReadFx32(); } }
public static NSBTP_File Read(string Filename) { EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(Filename), Endianness.LittleEndian); NSBTP_File ns = new NSBTP_File(); ns.Header.ID = er.ReadString(Encoding.ASCII, 4); if (ns.Header.ID == "BTP0") { ns.Header.Magic = er.ReadBytes(4); ns.Header.file_size = er.ReadInt32(); ns.Header.header_size = er.ReadInt16(); ns.Header.nSection = er.ReadInt16(); ns.Header.Section_Offset = new Int32[ns.Header.nSection]; for (int i = 0; i < ns.Header.nSection; i++) { ns.Header.Section_Offset[i] = er.ReadInt32(); } ns.PAT0.ID = er.ReadString(Encoding.ASCII, 4); if (ns.PAT0.ID == "PAT0") { ns.PAT0.Size = er.ReadInt32(); //3D Info Structure ns.PAT0.dummy = er.ReadByte(); ns.PAT0.num_objs = er.ReadByte(); ns.PAT0.section_size = er.ReadInt16(); ns.PAT0.unknownBlock.header_size = er.ReadInt16(); ns.PAT0.unknownBlock.section_size = er.ReadInt16(); ns.PAT0.unknownBlock.constant = er.ReadInt32(); ns.PAT0.unknownBlock.unknown1 = new short[ns.PAT0.num_objs]; ns.PAT0.unknownBlock.unknown2 = new short[ns.PAT0.num_objs]; for (int i = 0; i < ns.PAT0.num_objs; i++) { ns.PAT0.unknownBlock.unknown1[i] = er.ReadInt16(); ns.PAT0.unknownBlock.unknown2[i] = er.ReadInt16(); } ns.PAT0.infoBlock.header_size = er.ReadInt16(); ns.PAT0.infoBlock.data_size = er.ReadInt16(); ns.PAT0.infoBlock.Data = new NSBTP_File.pat0.Info.info[ns.PAT0.num_objs]; for (int i = 0; i < ns.PAT0.num_objs; i++) { ns.PAT0.infoBlock.Data[i].MPToffset = er.ReadInt32(); } ns.PAT0.names = new string[ns.PAT0.num_objs]; for (int i = 0; i < ns.PAT0.num_objs; i++) { ns.PAT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", ""); } ns.MPT.ID = er.ReadString(Encoding.ASCII, 4); if (ns.MPT.ID == "M" + (char)0x00 + "PT") { ns.MPT.NoFrames = er.ReadInt16(); ns.MPT.NoTex = er.ReadByte(); ns.MPT.NoPal = er.ReadByte(); ns.MPT.Texoffset = er.ReadInt16(); ns.MPT.Paloffset = er.ReadInt16(); //3D Info Structure ns.MPT.dummy = er.ReadByte(); ns.MPT.num_objs = er.ReadByte(); ns.MPT.section_size = er.ReadInt16(); ns.MPT.unknownBlock.header_size = er.ReadInt16(); ns.MPT.unknownBlock.section_size = er.ReadInt16(); ns.MPT.unknownBlock.constant = er.ReadInt32(); ns.MPT.unknownBlock.unknown1 = new short[ns.MPT.num_objs]; ns.MPT.unknownBlock.unknown2 = new short[ns.MPT.num_objs]; for (int i = 0; i < ns.MPT.num_objs; i++) { ns.MPT.unknownBlock.unknown1[i] = er.ReadInt16(); ns.MPT.unknownBlock.unknown2[i] = er.ReadInt16(); } ns.MPT.infoBlock.header_size = er.ReadInt16(); ns.MPT.infoBlock.data_size = er.ReadInt16(); ns.MPT.infoBlock.Data = new NSBTP_File.M_PT.Info.info[ns.MPT.num_objs]; ns.AnimData = new NSBTP_File.animData[ns.MPT.num_objs]; for (int i = 0; i < ns.MPT.num_objs; i++) { ns.MPT.infoBlock.Data[i].KeyFrames = er.ReadInt32(); ns.MPT.infoBlock.Data[i].Unknown1 = er.ReadInt16(); ns.MPT.infoBlock.Data[i].Offset = er.ReadInt16(); ns.AnimData[i].KeyFrames = new NSBTP_File.animData.keyFrame[ns.MPT.infoBlock.Data[i].KeyFrames]; for (int j = 0; j < ns.MPT.infoBlock.Data[i].KeyFrames; j++) { long curpos = er.BaseStream.Position; er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.infoBlock.Data[i].Offset + j*4 + 8; ns.AnimData[i].KeyFrames[j].Start = er.ReadInt16(); ns.AnimData[i].KeyFrames[j].texId = er.ReadByte(); ns.AnimData[i].KeyFrames[j].palId = er.ReadByte(); er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Texoffset + ns.AnimData[i].KeyFrames[j].texId * 16 + 8; ns.AnimData[i].KeyFrames[j].texName = LibNDSFormats.Utils.ReadNSBMDString(er); er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Paloffset + ns.AnimData[i].KeyFrames[j].palId * 16 + 8; ns.AnimData[i].KeyFrames[j].palName = LibNDSFormats.Utils.ReadNSBMDString(er); er.BaseStream.Position = curpos; } } ns.MPT.names = new string[ns.MPT.num_objs]; for (int i = 0; i < ns.MPT.num_objs; i++) { ns.MPT.names[i] = LibNDSFormats.Utils.ReadNSBMDString(er); } } else { MessageBox.Show("NSBTP Error"); er.Close(); return ns; } } else { MessageBox.Show("NSBTP Error"); er.Close(); return ns; } } else { MessageBox.Show("NSBTP Error"); er.Close(); return ns; } er.Close(); return ns; }
public static NSBTA_File Read(string Filename) { EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(Filename), Endianness.LittleEndian); NSBTA_File ns = new NSBTA_File(); ns.Header.ID = er.ReadString(Encoding.ASCII, 4); if (ns.Header.ID == "BTA0") { ns.Header.Magic = er.ReadBytes(4); ns.Header.file_size = er.ReadInt32(); ns.Header.header_size = er.ReadInt16(); ns.Header.nSection = er.ReadInt16(); ns.Header.Section_Offset = new Int32[ns.Header.nSection]; for (int i = 0; i < ns.Header.nSection; i++) { ns.Header.Section_Offset[i] = er.ReadInt32(); } ns.SRT0.ID = er.ReadString(Encoding.ASCII, 4); if (ns.SRT0.ID == "SRT0") { ns.SRT0.Size = er.ReadInt32(); //3D Info Structure ns.SRT0.dummy = er.ReadByte(); ns.SRT0.num_objs = er.ReadByte(); ns.SRT0.section_size = er.ReadInt16(); ns.SRT0.unknownBlock.header_size = er.ReadInt16(); ns.SRT0.unknownBlock.section_size = er.ReadInt16(); ns.SRT0.unknownBlock.constant = er.ReadInt32(); ns.SRT0.unknownBlock.unknown1 = new short[ns.SRT0.num_objs]; ns.SRT0.unknownBlock.unknown2 = new short[ns.SRT0.num_objs]; for (int i = 0; i < ns.SRT0.num_objs; i++) { ns.SRT0.unknownBlock.unknown1[i] = er.ReadInt16(); ns.SRT0.unknownBlock.unknown2[i] = er.ReadInt16(); } ns.SRT0.infoBlock.header_size = er.ReadInt16(); ns.SRT0.infoBlock.data_size = er.ReadInt16(); ns.SRT0.infoBlock.Data = new NSBTA_File.srt0.Info.info[ns.SRT0.num_objs]; for (int i = 0; i < ns.SRT0.num_objs; i++) { ns.SRT0.infoBlock.Data[i].MAToffset = er.ReadInt32(); } ns.SRT0.names = new string[ns.SRT0.num_objs]; for (int i = 0; i < ns.SRT0.num_objs; i++) { ns.SRT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", ""); } ns.MAT.ID = er.ReadString(Encoding.ASCII, 4); if (ns.MAT.ID == "M"+(char)0x00+"AT") { ns.MAT.Unknown1 = er.ReadInt16(); ns.MAT.Unknown2 = er.ReadByte(); ns.MAT.Unknown3 = er.ReadByte(); //3D Info Structure ns.MAT.dummy = er.ReadByte(); ns.MAT.num_objs = er.ReadByte(); ns.MAT.section_size = er.ReadInt16(); ns.MAT.unknownBlock.header_size = er.ReadInt16(); ns.MAT.unknownBlock.section_size = er.ReadInt16(); ns.MAT.unknownBlock.constant = er.ReadInt32(); ns.MAT.unknownBlock.unknown1 = new short[ns.MAT.num_objs]; ns.MAT.unknownBlock.unknown2 = new short[ns.MAT.num_objs]; for (int i = 0; i < ns.MAT.num_objs; i++) { ns.MAT.unknownBlock.unknown1[i] = er.ReadInt16(); ns.MAT.unknownBlock.unknown2[i] = er.ReadInt16(); } ns.MAT.infoBlock.header_size = er.ReadInt16(); ns.MAT.infoBlock.data_size = er.ReadInt16(); ns.MAT.infoBlock.Data = new NSBTA_File.M_AT.Info.info[ns.MAT.num_objs]; ns.SRTData = new NSBTA_File.srtData[ns.MAT.num_objs]; for (int i = 0; i < ns.MAT.num_objs; i++) { ns.MAT.infoBlock.Data[i].frame = new short[5]; ns.MAT.infoBlock.Data[i].var1 = new short[5]; ns.MAT.infoBlock.Data[i].var2 = new short[5]; ns.MAT.infoBlock.Data[i].var3 = new short[5]; ns.MAT.infoBlock.Data[i].frameStep = new int[5]; for (int j = 0; j < 5; j++) { ns.MAT.infoBlock.Data[i].frame[j] = er.ReadInt16(); ns.MAT.infoBlock.Data[i].var1[j] = (short)(er.ReadInt16() / 4096); ns.MAT.infoBlock.Data[i].var2[j] = er.ReadInt16(); ns.MAT.infoBlock.Data[i].var3[j] = (short)(er.ReadInt16() / 4096); } if (ns.MAT.infoBlock.Data[i].var1[0] > 1) { ns.SRTData[i].scaleS = new decimal[1]; ns.SRTData[i].scaleS[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[0] / 4096); } else { ns.SRTData[i].scaleS = new decimal[ns.MAT.infoBlock.Data[i].frame[0]]; } if (ns.MAT.infoBlock.Data[i].var1[1] > 1) { ns.SRTData[i].scaleT = new decimal[1]; ns.SRTData[i].scaleT[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[1] / 4096); } else { ns.SRTData[i].scaleT = new decimal[ns.MAT.infoBlock.Data[i].frame[1]]; } if (ns.MAT.infoBlock.Data[i].var1[2] > 1) { ns.SRTData[i].rotate = new decimal[2]; ns.SRTData[i].rotate[0] = ns.MAT.infoBlock.Data[i].var2[2]; ns.SRTData[i].rotate[1] = ns.MAT.infoBlock.Data[i].var3[2]; } else { ns.SRTData[i].rotate = new decimal[ns.MAT.infoBlock.Data[i].frame[2] * 2]; } if (ns.MAT.infoBlock.Data[i].var1[3] > 1) { ns.SRTData[i].translateS = new decimal[1]; ns.SRTData[i].translateS[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[3] / 4096); } else { ns.SRTData[i].translateS = new decimal[ns.MAT.infoBlock.Data[i].frame[3]]; ns.MAT.infoBlock.Data[i].frameStep[3] = Math.Abs(ns.MAT.infoBlock.Data[i].var1[3] >> 1); } if (ns.MAT.infoBlock.Data[i].var1[4] > 1) { ns.SRTData[i].translateT = new decimal[1]; ns.SRTData[i].translateT[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[4] / 4096); } else { ns.SRTData[i].translateT = new decimal[ns.MAT.infoBlock.Data[i].frame[4]]; ns.MAT.infoBlock.Data[i].frameStep[4] = Math.Abs(ns.MAT.infoBlock.Data[i].var1[4] >> 1); } //ns.SRTData[i].scaleS = new decimal[ns.MAT.infoBlock.Data[i].var1[0] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[0]]; //ns.SRTData[i].scaleT = new decimal[ns.MAT.infoBlock.Data[i].var1[1] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[1]]; //ns.SRTData[i].rotate = new decimal[ns.MAT.infoBlock.Data[i].var1[2] == 2 ? ns.MAT.infoBlock.Data[i].var1[2] == 3 ? 2 : 1 : ns.MAT.infoBlock.Data[i].frame[2]]; //ns.SRTData[i].translateS = new decimal[ns.MAT.infoBlock.Data[i].var1[3] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[3]]; //ns.SRTData[i].translateT = new decimal[ns.MAT.infoBlock.Data[i].var1[4] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[4]]; } ns.MAT.names = new string[ns.MAT.num_objs]; for (int i = 0; i < ns.MAT.num_objs; i++) { ns.MAT.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", ""); } for (int i = 0; i < ns.MAT.num_objs; i++) { if (ns.SRTData[i].scaleS.Length != 1) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[0] + 8; for (int j = 0; j < ns.SRTData[i].scaleS.Length; j++) { ns.SRTData[i].scaleS[j] = (decimal)(er.ReadInt16() / 4096d); } } if (ns.SRTData[i].scaleT.Length != 1) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[1] + 8; for (int j = 0; j < ns.SRTData[i].scaleT.Length; j++) { ns.SRTData[i].scaleT[j] = (decimal)(er.ReadInt16() / 4096d); } } if (ns.SRTData[i].rotate.Length != 2) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[2] + 8; for (int j = 0; j < ns.SRTData[i].rotate.Length; j++) { ns.SRTData[i].rotate[j] = (decimal)(er.ReadInt16() / 4096d); } } if (ns.SRTData[i].translateS.Length != 1) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[3] + 8; for (int j = 0; j < ns.SRTData[i].translateS.Length; j += (ns.MAT.infoBlock.Data[i].frameStep[3] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[3])) { decimal value = (decimal)(er.ReadInt16() / 4096d); for (int k = 0; k < (ns.MAT.infoBlock.Data[i].frameStep[3] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[3]); k++) { ns.SRTData[i].translateS[j + k] = value; } } } if (ns.SRTData[i].translateT.Length != 1) { er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[4] + 8; for (int j = 0; j < ns.SRTData[i].translateT.Length; j +=( ns.MAT.infoBlock.Data[i].frameStep[4] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[4])) { decimal value = (decimal)(er.ReadInt16() / 4096d); for (int k = 0; k < (ns.MAT.infoBlock.Data[i].frameStep[4] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[4]); k++) { ns.SRTData[i].translateT[j + k] = value; } } } } } else { MessageBox.Show("Error"); er.Close(); return ns; } } else { MessageBox.Show("Error"); er.Close(); return ns; } } else { MessageBox.Show("Error"); er.Close(); return ns; } er.Close(); return ns; }
/// <summary> /// ReadMld0. /// </summary> private static NsbmdModel[] ReadMdl0(Stream stream, int blockoffset) { var reader = new EndianBinaryReader(stream, Endianness.LittleEndian); int blocksize; int blockptr; int blocklimit; byte num; uint r; List<NsbmdModel> model = new List<NsbmdModel>(); //////////////////////////////////////////////// // model blockptr = blockoffset + 4; // already read the ID, skip 4 bytes blocksize = reader.ReadInt32(); // block size blocklimit = blocksize + blockoffset; stream.Skip(1); // skip dummy '0' num = reader.ReadByte(); // no of model if (num <= 0) throw new Exception(); for (var i = 0; i < num; ++i) model.Add(new NsbmdModel()); var modelOffset = new UInt32[num]; stream.Skip(10 + 4 + (num * 4)); // skip [char xyz], useless, go straight to model data offset blockptr += 10 + 4; //////////////////////////////////////////////// // copy model dataoffset for (var i = 0; i < num; i++) modelOffset[i] = (uint)(reader.ReadUInt32() + blockoffset); //////////////////////////////////////////////// // copy model names for (var i = 0; i < num; i++) model[i].Name = Utils.ReadNSBMDString(reader); //////////////////////////////////////////////// // parse model data uint totalsize_base = reader.ReadUInt32(); uint codeoffset_base = reader.ReadUInt32(); uint texpaloffset_base = reader.ReadUInt32(); uint polyoffset_base = reader.ReadUInt32(); uint polyend_base = reader.ReadUInt32(); stream.Skip(4); uint matnum = reader.ReadByte(); // no. of material uint polynum = reader.ReadByte(); // no. of polygon byte laststack = reader.ReadByte(); byte unknown1m = reader.ReadByte(); float modelscale = (float)reader.ReadInt32() / 4096f; float boundscale = (float)reader.ReadInt32();// / 4096f; int vertexcount = reader.ReadInt16(); int surfacecount = reader.ReadInt16(); int trianglecount = reader.ReadInt16(); int quadcount = reader.ReadInt16(); model[0].laststackid = laststack; model[0].modelScale = modelscale; model[0].boundScale = boundscale; model[0].boundXmin = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; model[0].boundYmin = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; model[0].boundZmin = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; model[0].boundXmax = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; model[0].boundYmax = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; model[0].boundZmax = (float)NsbmdGlRenderer.sign(reader.ReadInt16(), 16) / 4096f; var polyOffsets = new UInt32[polynum]; var polyDataSize = new UInt32[polynum]; for (var i = 0; i < 1; i++) { var mod = model[i]; stream.Seek(modelOffset[i], SeekOrigin.Begin); // the following variables are all offset values long totalsize; uint codeoffset; UInt32 texpaloffset; UInt32 polyoffset; long polyend; long texoffset; long paloffset; uint modoffset = modelOffset[i]; totalsize = totalsize_base + modoffset; codeoffset = codeoffset_base + modoffset; // additional model data, bone definition etc., just follow NsbmdObject section texpaloffset = texpaloffset_base + modoffset; polyoffset = polyoffset_base + modoffset; polyend = polyend_base + modoffset; stream.Skip(5 * 4 + 4 + 2 + 38); // go straight to NsbmdObject //////////////////////////////////////////////// // NsbmdObject section UInt32 objnum; int objdatabase; UInt32[] objdataoffset; UInt32[] objdatasize; objdatabase = (int)stream.Position; stream.Skip(1); // skip dummy '0' objnum = reader.ReadByte(); // no of NsbmdObject stream.Skip(14 + (objnum * 4)); // skip bytes, go striaght to NsbmdObject data offset for (i = 0; i < objnum; ++i) mod.Objects.Add(new NsbmdObject()); objdataoffset = new UInt32[objnum]; objdatasize = new UInt32[objnum]; for (var j = 0; j < objnum; j++) objdataoffset[j] = (UInt32)(reader.ReadUInt32() + objdatabase); for (var j = 0; j < objnum - 1; j++) objdatasize[j] = objdataoffset[j + 1] - objdataoffset[j]; objdatasize[objnum - 1] = (UInt32)(codeoffset - objdataoffset[objnum - 1]); //////////////////////////////////////////////// // copy NsbmdObject names for (var j = 0; j < objnum; j++) { mod.Objects[j].Name = Utils.ReadNSBMDString(reader); // TO DEBUG Console.WriteLine(mod.Objects[j].Name); } //////////////////////////////////////////////// // parse NsbmdObject information for (var j = 0; j < objnum; j++) { if (objdatasize[j] <= 4) continue; stream.Seek(objdataoffset[j], SeekOrigin.Begin); ParseNsbmdObject(reader, mod.Objects[j], modelscale); } //////////////////////////////////////////////// // material section stream.Seek(texpaloffset, SeekOrigin.Begin); // now get the texture and palette offset texoffset = reader.ReadUInt16() + texpaloffset; paloffset = reader.ReadUInt16() + texpaloffset; // allocate memory for material for (var j = 0; j <= matnum; j++)//i <= matnum; ++i) mod.Materials.Add(new NsbmdMaterial()); //////////////////////////////////////////////// // parse material definition // defines RotA material by pairing texture and palette stream.Seek(16 + (matnum * 4), SeekOrigin.Current); // go straight to material data offset for (var j = 0; j < matnum; j++) // TODO: BAD! { mod.Materials[j] = new NsbmdMaterial(); blockptr = (int)stream.Position; r = reader.ReadUInt32() + texpaloffset/* + 4 + 12*/;// skip 18 bytes (+ 2 bytes for texoffset, 2 bytes for paloffset) stream.Seek(r, SeekOrigin.Begin); //mod.Materials[j].repeat = reader.ReadByte(); //reader.BaseStream.Position -= 1; int dummy = reader.ReadInt16(); int sectionSize = reader.ReadInt16(); int unknown1 = reader.ReadInt32();//DifAmbColors int unknown2 = reader.ReadInt32();//SpeEmiColors int unknown3 = reader.ReadInt32();//PolyAttrib int constant2 = reader.ReadInt32();//PolyAttrib Mask int texVramOffset = reader.ReadInt16(); int texImageParam = reader.ReadInt16(); int constant3 = reader.ReadInt32();//texImageParam Mask int constant4 = reader.ReadInt32(); int matWidth = reader.ReadInt16(); int matHeight = reader.ReadInt16(); int unknown4 = reader.ReadInt16(); int unknown5 = reader.ReadInt16(); int unknown6 = reader.ReadInt32(); //int unknown7 = reader.ReadInt32();//if srt S Scale //int unknown8 = reader.ReadInt32();//if srt T Scale //int unknown9 = reader.ReadInt16();//if srt & 60 Rot //int unknownA = reader.ReadInt16();//if srt & 60 S Trans //int unknownB = reader.ReadInt16();//if srt & 60 T Trans //uint polyParam = reader.ReadUInt32(); //reader.ReadInt16(); //ushort texImageParam = reader.ReadUInt16(); mod.Materials[j].repeatS = texImageParam & 1; mod.Materials[j].repeatT = texImageParam >> 1 & 1; mod.Materials[j].flipS = texImageParam >> 2 & 1; mod.Materials[j].flipT = texImageParam >> 3 & 1; /*if ((texImageParam >> 14 & 0x03) == 1) { mod.Materials[j].scaleS = /*1 << /(texImageParam >> 12 & 2) + 1; mod.Materials[j].scaleT = /*1 << /(texImageParam >> 14 & 2) + 1; } else { mod.Materials[j].scaleS = 1; mod.Materials[j].scaleT = 1; }*/ switch (texImageParam >> 14 & 0x03) { case 0: mod.Materials[j].scaleS = 1; mod.Materials[j].scaleT = 1; mod.Materials[j].transS = 0; mod.Materials[j].transT = 0; break; case 1: { int sscale = (int)reader.ReadInt32();// >> 0 & 0xFFFFFFFF; sscale = NsbmdGlRenderer.sign(sscale, 32); int tscale = (int)reader.ReadInt32();// >> 0 & 0xFFFFFFFF; tscale = NsbmdGlRenderer.sign(tscale, 32); //int strans = (int)unknown2 >> 0 & 0xFFFF; //int ttrans = (int)unknown2 >> 16 & 0xFFFF; mod.Materials[j].scaleS = (float)sscale / 4096f; mod.Materials[j].scaleT = (float)tscale / 4096f; if (sectionSize >= 60) { mod.Materials[j].rot = (float)reader.ReadInt16() / 4096f; mod.Materials[j].transS = (float)reader.ReadInt16() / 4096f; mod.Materials[j].transT = (float)reader.ReadInt16() / 4096f; } else { } break; } case 2: case 3: mod.Materials[j].mtx = new float[16]; for (int k = 0; k < 16; k++) { mod.Materials[j].mtx[k] = reader.ReadInt32(); } break; default: break; // throw new Exception(String.Format("BMD: unsupported texture coord transform mode {0}", matgroup.m_TexParams >> 30)); } mod.Materials[j].width = matWidth; mod.Materials[j].height = matHeight; int width = 8 << (texImageParam >> 4 & 7); int height = 8 << (texImageParam >> 7 & 7); //int m_DifAmbColors = reader.ReadInt32(); //int m_SpeEmiColors = reader.ReadInt32(); mod.Materials[j].DiffuseColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown1 & 0x7FFF)); mod.Materials[j].AmbientColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown1 >> 16 & 0x7FFF)); mod.Materials[j].SpecularColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown2 & 0x7FFF)); mod.Materials[j].EmissionColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown2 >> 16 & 0x7FFF)); int a = (int)((unknown3 >> 16) & 31); mod.Materials[j].Alpha = a;//a * 2 + 1;//a * 2 + (a + 31) / 32; mod.Materials[j].PolyAttrib = (uint)unknown3; mod.Materials[j].diffuseColor = (unknown1 >> 15 & 1) == 1; mod.Materials[j].shine = (unknown2 >> 15 & 1) == 1; stream.Seek(blockptr + 4, SeekOrigin.Begin); } for (var j = 0; j < matnum; j++) { mod.Materials[j].MaterialName = Utils.ReadNSBMDString(reader); } //////////////////////////////////////////////// // now go to read the texture definition stream.Seek(texoffset, SeekOrigin.Begin); stream.Skip(1); // skip dummy '0' int texnum = reader.ReadByte(); Debug.Assert(texnum <= matnum); Console.WriteLine(String.Format("texnum: {0}", texnum)); if (texnum > 0) { stream.Seek(14 + (texnum * 4), SeekOrigin.Current); // go straight to data offsets for (var j = 0; j < texnum; j++) { Int32 flags = reader.ReadInt32(); int numPairs = flags >> 16 & 0xf; int dummy = flags >> 24 & 0xf; blockptr = (int)stream.Position; stream.Seek((flags & 0xffff) + texpaloffset, SeekOrigin.Begin); NSBMDTexture t = new NSBMDTexture(); for (int k = 0; k < numPairs; k++) { uint texmatid = reader.ReadByte(); mod.tex_mat.Add((int)texmatid); mod.Materials[j].texmatid.Add(texmatid); t.texmatid.Add(texmatid); } mod.Textures.Add(t); stream.Seek(blockptr, SeekOrigin.Begin); } for (var j = 0; j < texnum; j++) // copy texture names { NsbmdMaterial mat = mod.Materials[j]; mat.texname = Utils.ReadNSBMDString(reader); reader.BaseStream.Position -= 16; mod.Textures[j].texname = Utils.ReadNSBMDString(reader); Console.WriteLine("tex (matid={0}): {1}", mat.texmatid, mat.texname); } } //////////////////////////////////////////////// // now go to read the palette definition stream.Seek(paloffset, SeekOrigin.Begin); stream.Skip(1); // skip dummy '0' int palnum = reader.ReadByte(); // no of palette definition Debug.Assert(palnum <= matnum); // may not always hold? Console.WriteLine("DEBUG: palnum = {0}", palnum); if (palnum > 0) { stream.Seek(14 + (palnum * 4), SeekOrigin.Current); // go straight to data offsets for (var j = 0; j < palnum; j++) // matching palette with material { Int32 flags = reader.ReadInt32(); int numPairs = flags >> 16 & 0xf; int dummy = flags >> 24 & 0xf; blockptr = (int)stream.Position; stream.Seek((flags & 0xffff) + texpaloffset, SeekOrigin.Begin); NSBMDPalette t = new NSBMDPalette(); for (int k = 0; k < numPairs; k++) { uint texmatid = reader.ReadByte(); mod.tex_mat.Add((int)texmatid); mod.Materials[j].texmatid.Add(texmatid); t.palmatid.Add(texmatid); } mod.Palettes.Add(t); stream.Seek(blockptr, SeekOrigin.Begin); } for (var j = 0; j < palnum; j++) // copy palette names { int palmatid = (int)mod.Materials[j].palmatid; mod.Materials[palmatid].palname = Utils.ReadNSBMDString(reader); reader.BaseStream.Position -= 16; mod.Palettes[j].palname = Utils.ReadNSBMDString(reader); // TO DEBUG Console.WriteLine("pal (matid={0}): {1}", palmatid, mod.Materials[palmatid].palname); } } //////////////////////////////////////////////// // Polygon stream.Seek(polyoffset, SeekOrigin.Begin); stream.Skip(1); // skip dummy '0' r = reader.ReadByte(); // no of polygon Console.WriteLine("DEBUG: polynum = {0}", polynum); for (var j = 0; j <= polynum; j++) { mod.Polygons.Add(new NsbmdPolygon()); } stream.Skip(14 + (polynum * 4)); // skip bytes, go straight to data offset for (var j = 0; j < polynum; j++) polyOffsets[j] = reader.ReadUInt32() + polyoffset; try { for (var j = 0; j < polynum; j++) // copy polygon names { mod.Polygons[j].Name = Utils.ReadNSBMDString(reader); Console.WriteLine(mod.Polygons[j].Name); } } catch { } //////////////////////////////////////////////// // now go to the polygon data, there is RotA 16-byte-header before geometry commands for (var j = 0; j < polynum; j++) { var poly = mod.Polygons[j]; ////////////////////////////////////////////////////////// poly.MatId = -1; // DEFAULT: indicate no associated material ////////////////////////////////////////////////////////// //stream.Seek(polyOffsets[j] + 8, SeekOrigin.Begin); // skip 8 unknown bytes short dummy = reader.ReadInt16(); short headerSize = reader.ReadInt16(); int unknown2 = reader.ReadInt32(); polyOffsets[j] += reader.ReadUInt32(); polyDataSize[j] = reader.ReadUInt32(); //printf( "poly %2d '%-16s': dataoffset: %08x datasize %08x\n", j, poly->polyname, poly->dataoffset, poly->datasize ); } //} //////////////////////////////////////////////// // read the polygon data into memory for (var j = 0; j < polynum; j++) { var poly = mod.Polygons[j]; stream.Seek(polyOffsets[j], SeekOrigin.Begin); poly.PolyData = reader.ReadBytes((int)polyDataSize[j]); } //} //////////////////////////////////////////////// // decode the additional model data DecodeCode(stream, codeoffset, texpaloffset, mod, laststack); } //modelnum = num; return model.ToArray(); }
/// <summary> /// Parse single NSBMD object. /// </summary> private static void ParseNsbmdObject(EndianBinaryReader reader, NsbmdObject nsbmdObject, float modelscale) { UInt16 v = reader.ReadUInt16(); Int16 divide = reader.ReadInt16(); divide = (short)NsbmdGlRenderer.sign(divide, 16); int unknown = v >> 12 & 0xf; nsbmdObject.StackID = unknown; //nsbmdObject.isBillboard = ((v >> 12 & 0xf) == 1?true:false); float[] s = NsbmdGlRenderer.loadIdentity(); float[] r = NsbmdGlRenderer.loadIdentity(); float[] t = NsbmdGlRenderer.loadIdentity(); if ((v & 1) == 0) { nsbmdObject.Trans = true; nsbmdObject.X = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f; //(float)(reader.ReadDouble() / 4096d);//.ReadUInt32() / 4096; nsbmdObject.Y = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f;//(float)(reader.ReadDouble() / 4096d); nsbmdObject.Z = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f;//(float)(reader.ReadDouble() / 4096d); t = NsbmdGlRenderer.translate(t, nsbmdObject.X, nsbmdObject.Y, nsbmdObject.Z); } if ((v >> 3 & 0x1) == 0x1) { nsbmdObject.IsRotated = true; float a = reader.ReadInt16(); a = NsbmdGlRenderer.sign((int)a, 16) / 4096f; float b = reader.ReadInt16(); b = NsbmdGlRenderer.sign((int)b, 16) / 4096f; nsbmdObject.Pivot = (int)(v >> 4) & 0x0f; nsbmdObject.Neg = (int)(v >> 8) & 0x0f; nsbmdObject.RotA = a; nsbmdObject.RotB = b; nsbmdObject.rotate_mtx = mtxPivot(new float[] { nsbmdObject.RotA, nsbmdObject.RotB }, nsbmdObject.Pivot, nsbmdObject.Neg); r = NsbmdGlRenderer.multMatrix(r, nsbmdObject.rotate_mtx); } if ((v >> 1 & 1) == 0 && (v >> 3 & 1) == 0) { float[] a = new float[16]; a[0] = 1.0F; a[5] = 1.0F; a[10] = 1.0F; a[15] = 1.0F; float[] rotate = new float[8]; //msg = (new StringBuilder()).append(msg).append(" | R: ").toString(); for (int j = 0; j < rotate.Length; j++) { //dataParser _tmp4 = pa; int value = NsbmdGlRenderer.sign(reader.ReadInt16(),16); //dataParser.getSign(data, offset + 4 + j * 2 + jump, 2); rotate[j] = (float)value / 4096f; //msg = (new StringBuilder()).append(msg).append(pad(Integer.valueOf(value), 4)).toString(); //if(j + 1 < rotate.length) // msg = (new StringBuilder()).append(msg).append(", ").toString(); } a[0] = (float)divide / 4096f; a[1] = rotate[0]; a[2] = rotate[1]; a[4] = rotate[2]; a[5] = rotate[3]; a[6] = rotate[4]; a[8] = rotate[5]; a[9] = rotate[6]; a[10] = rotate[7]; nsbmdObject.rotate_mtx = a; nsbmdObject.IsRotated = true; r = NsbmdGlRenderer.multMatrix(r, nsbmdObject.rotate_mtx); } if ((v >> 2 & 1) == 0) { float[] scale = new float[3]; for (int j = 0; j < scale.Length; j++) { int value = reader.ReadInt32(); scale[j] = (float)value / 4096f; } nsbmdObject.scale = scale; nsbmdObject.IsScaled = true; s = NsbmdGlRenderer.scale(s, scale[0], scale[1], scale[2]); } nsbmdObject.materix = NsbmdGlRenderer.loadIdentity(); nsbmdObject.materix = NsbmdGlRenderer.multMatrix(nsbmdObject.materix, t); nsbmdObject.materix = NsbmdGlRenderer.multMatrix(nsbmdObject.materix, r); nsbmdObject.materix = NsbmdGlRenderer.multMatrix(nsbmdObject.materix, s); }
// Gen V private void listBox6_SelectedIndexChanged(object sender, EventArgs e) { listBox5.Items.Clear(); listBox4.Items.Clear(); if (radioButton18.Checked == true) { editorTileset = workingFolder + @"data\a\0\1\tilesets"; } else if (radioButton17.Checked == true) { editorTileset = workingFolder + @"data\a\1\7\bldtilesets"; } else { editorTileset = workingFolder + @"data\a\1\7\bld2tilesets"; } EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(editorTileset + "\\" + listBox6.SelectedIndex.ToString("D4")), Endianness.LittleEndian); nsbtx = new NSBTX_File(); if (er.ReadString(Encoding.ASCII, 4) != "BTX0") { MessageBox.Show(rm.GetString("tilesetError"), null, MessageBoxButtons.OK, MessageBoxIcon.Stop); er.Close(); return; } else { nsbtx.Header.ID = "BTX0"; nsbtx.Header.Magic = er.ReadBytes(4); nsbtx.Header.file_size = er.ReadInt32(); nsbtx.Header.header_size = er.ReadInt16(); nsbtx.Header.nSection = er.ReadInt16(); nsbtx.Header.Section_Offset = new Int32[nsbtx.Header.nSection]; for (int i = 0; i < nsbtx.Header.nSection; i++) { nsbtx.Header.Section_Offset[i] = er.ReadInt32(); } nsbtx.TEX0.ID = er.ReadString(Encoding.ASCII, 4); if (nsbtx.TEX0.ID != "TEX0") { MessageBox.Show(rm.GetString("tilesetError")); er.Close(); return; } } nsbtx.TEX0.Section_size = er.ReadInt32(); nsbtx.TEX0.Padding1 = er.ReadInt32(); nsbtx.TEX0.Texture_Data_Size = (er.ReadInt16() << 3); nsbtx.TEX0.Texture_Info_Offset = er.ReadInt16(); nsbtx.TEX0.Padding2 = er.ReadInt32(); nsbtx.TEX0.Texture_Data_Offset = er.ReadInt32(); nsbtx.TEX0.Padding3 = er.ReadInt32(); nsbtx.TEX0.Compressed_Texture_Data_Size = (er.ReadInt16() << 3); nsbtx.TEX0.Compressed_Texture_Info_Offset = er.ReadInt16(); nsbtx.TEX0.Padding4 = er.ReadInt32(); nsbtx.TEX0.Compressed_Texture_Data_Offset = er.ReadInt32(); nsbtx.TEX0.Compressed_Texture_Info_Data_Offset = er.ReadInt32(); nsbtx.TEX0.Padding5 = er.ReadInt32(); nsbtx.TEX0.Palette_Data_Size = (er.ReadInt32() << 3); nsbtx.TEX0.Palette_Info_Offset = er.ReadInt32(); nsbtx.TEX0.Palette_Data_Offset = er.ReadInt32(); nsbtx.TexInfo.dummy = er.ReadByte(); nsbtx.TexInfo.num_objs = er.ReadByte(); nsbtx.TexInfo.section_size = er.ReadInt16(); nsbtx.TexInfo.unknownBlock.header_size = er.ReadInt16(); nsbtx.TexInfo.unknownBlock.section_size = er.ReadInt16(); nsbtx.TexInfo.unknownBlock.constant = er.ReadInt32(); nsbtx.TexInfo.unknownBlock.unknown1 = new List<short>(); nsbtx.TexInfo.unknownBlock.unknown2 = new List<short>(); for (int i = 0; i < nsbtx.TexInfo.num_objs; i++) { nsbtx.TexInfo.unknownBlock.unknown1.Add(er.ReadInt16()); nsbtx.TexInfo.unknownBlock.unknown2.Add(er.ReadInt16()); } nsbtx.TexInfo.infoBlock.header_size = er.ReadInt16(); nsbtx.TexInfo.infoBlock.data_size = er.ReadInt16(); nsbtx.TexInfo.infoBlock.TexInfo = new NSBTX_File.texInfo.Info.texInfo[nsbtx.TexInfo.num_objs]; //long compressedStartOffset = 0x00; for (int i = 0; i < nsbtx.TexInfo.num_objs; i++) { nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset = (er.ReadInt16() << 3); nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = er.ReadInt16(); nsbtx.TexInfo.infoBlock.TexInfo[i].Width = er.ReadByte(); nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 = er.ReadByte(); nsbtx.TexInfo.infoBlock.TexInfo[i].Height = er.ReadByte(); nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown2 = er.ReadByte(); nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 14); nsbtx.TexInfo.infoBlock.TexInfo[i].color0 = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 13) & 1); nsbtx.TexInfo.infoBlock.TexInfo[i].format = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 10) & 7); nsbtx.TexInfo.infoBlock.TexInfo[i].height = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 7) & 7)); nsbtx.TexInfo.infoBlock.TexInfo[i].width = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 4) & 7)); nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 3) & 1); nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 2) & 1); nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 1) & 1); nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 1); nsbtx.TexInfo.infoBlock.TexInfo[i].depth = (byte)bpp[nsbtx.TexInfo.infoBlock.TexInfo[i].format]; if (nsbtx.TexInfo.infoBlock.TexInfo[i].width == 0x00) switch (nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 & 0x3) { case 2: nsbtx.TexInfo.infoBlock.TexInfo[i].width = 0x200; break; default: nsbtx.TexInfo.infoBlock.TexInfo[i].width = 0x100; break; } if (nsbtx.TexInfo.infoBlock.TexInfo[i].height == 0x00) switch ((nsbtx.TexInfo.infoBlock.TexInfo[i].Height >> 3) & 0x3) { case 2: nsbtx.TexInfo.infoBlock.TexInfo[i].height = 0x200; break; default: nsbtx.TexInfo.infoBlock.TexInfo[i].height = 0x100; break; } int imgsize = (nsbtx.TexInfo.infoBlock.TexInfo[i].width * nsbtx.TexInfo.infoBlock.TexInfo[i].height * nsbtx.TexInfo.infoBlock.TexInfo[i].depth) / 8; long curpos = er.BaseStream.Position; if (nsbtx.TexInfo.infoBlock.TexInfo[i].format != 5) { er.BaseStream.Seek(nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset + nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Texture_Data_Offset, SeekOrigin.Begin); } else { er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Compressed_Texture_Data_Offset + nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset, SeekOrigin.Begin); } nsbtx.TexInfo.infoBlock.TexInfo[i].Image = er.ReadBytes(imgsize); er.BaseStream.Seek(curpos, SeekOrigin.Begin); if (nsbtx.TexInfo.infoBlock.TexInfo[i].format == 5) { //nsbtx.TexInfo.infoBlock.TexInfo[i].compressedDataStart = (uint)compressedStartOffset; //compressedStartOffset += imgsize / 2; curpos = er.BaseStream.Position; er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Compressed_Texture_Info_Data_Offset + nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset / 2, SeekOrigin.Begin); nsbtx.TexInfo.infoBlock.TexInfo[i].spData = er.ReadBytes(imgsize / 2); er.BaseStream.Seek(curpos, SeekOrigin.Begin); } } nsbtx.TexInfo.names = new List<string>(); for (int i = 0; i < nsbtx.TexInfo.num_objs; i++) { nsbtx.TexInfo.names.Add(er.ReadString(Encoding.ASCII, 16).Replace("\0", "")); listBox5.Items.Add(nsbtx.TexInfo.names[i]); } nsbtx.PalInfo.dummy = er.ReadByte(); nsbtx.PalInfo.num_objs = er.ReadByte(); nsbtx.PalInfo.section_size = er.ReadInt16(); nsbtx.PalInfo.unknownBlock.header_size = er.ReadInt16(); nsbtx.PalInfo.unknownBlock.section_size = er.ReadInt16(); nsbtx.PalInfo.unknownBlock.constant = er.ReadInt32(); nsbtx.PalInfo.unknownBlock.unknown1 = new List<short>(); nsbtx.PalInfo.unknownBlock.unknown2 = new List<short>(); for (int i = 0; i < nsbtx.PalInfo.num_objs; i++) { nsbtx.PalInfo.unknownBlock.unknown1.Add(er.ReadInt16()); nsbtx.PalInfo.unknownBlock.unknown2.Add(er.ReadInt16()); } nsbtx.PalInfo.infoBlock.header_size = er.ReadInt16(); nsbtx.PalInfo.infoBlock.data_size = er.ReadInt16(); nsbtx.PalInfo.infoBlock.PalInfo = new NSBTX_File.palInfo.Info.palInfo[nsbtx.PalInfo.num_objs]; for (int i = 0; i < nsbtx.PalInfo.num_objs; i++) { nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset = (er.ReadInt16() << 3); nsbtx.PalInfo.infoBlock.PalInfo[i].Color0 = er.ReadInt16(); er.BaseStream.Position -= 4; int palBase = er.ReadInt32(); int palAddr = palBase & 0xfff; long curpos = er.BaseStream.Position; er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Palette_Data_Offset, SeekOrigin.Begin); er.BaseStream.Seek(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset, SeekOrigin.Current); nsbtx.PalInfo.infoBlock.PalInfo[i].pal = Tinke.Convertir.BGR555(er.ReadBytes(nsbtx.TEX0.Palette_Data_Size - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset)); er.BaseStream.Seek(curpos, SeekOrigin.Begin); } nsbtx.PalInfo.names = new List<string>(); for (int i = 0; i < nsbtx.PalInfo.num_objs; i++) { nsbtx.PalInfo.names.Add(er.ReadString(Encoding.ASCII, 16).Replace("\0", "")); listBox4.Items.Add(nsbtx.PalInfo.names[i]); } List<int> offsets = new List<int>(); for (int i = 0; i < nsbtx.PalInfo.num_objs; i++) { //if(!offsets.Contains(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset)) //{ offsets.Add(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset); //} } offsets.Add((int)er.BaseStream.Length); offsets.Sort(); for (int i = 0; i < nsbtx.PalInfo.num_objs; i++) { int pallength; int j = -1; do { j++; } while (offsets[j] - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset <= 0);//nsbtx.PalInfo.infoBlock.PalInfo[i + j].Palette_Offset - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset == 0) pallength = offsets[j] - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset; Color[] c_ = nsbtx.PalInfo.infoBlock.PalInfo[i].pal; List<Color> c = new List<Color>(); c.AddRange(nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Take(pallength / 2)); nsbtx.PalInfo.infoBlock.PalInfo[i].pal = c.ToArray(); } er.Close(); listBox5.SelectedIndex = 0; if (nsbtx.PalInfo.num_objs != 0) { listBox4.SelectedIndex = 0; } }