using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using LibNDSFormats.NSBMD; namespace LibNDSFormats.NSBCA { /// /// Loader for NSBCA files & data. /// public static class NSBCALoader { #region Methods (2) // Public Methods (2) /// /// Load NSBTX from stream. /// /// Stream to use. /// Material definitions. public static IEnumerable LoadNsbca(Stream stream) { List animation = new List(); var reader = new EndianBinaryReader(stream, Endianness.LittleEndian); byte[] id = reader.ReadBytes(4); if (id == new byte[] { 0x42, 0x43, 0x41, 0x30 }) { throw new Exception(); } int i = reader.ReadInt32(); if (i == NSBMD.NSBMD.NDS_TYPE_MAGIC1) { i = reader.ReadInt32(); if (i == stream.Length) { int numblock = reader.ReadInt32(); numblock >>= 16; int r = reader.ReadInt32(); id = reader.ReadBytes(4); if (numblock == 1 && r == 0x14) { animation.AddRange(ReadJnt0(stream, 0x14)); } } } reader.Close(); return animation; } /// /// Load NSBTX from file. /// /// File to use. /// Material definitions. public static IEnumerable LoadNsbca(FileInfo fileInfo) { IEnumerable result = null; using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open)) { result = LoadNsbca(fileStream); } return result; } /// /// Load materials in stream. /// /// Stream to use. /// Material definitions. public static IEnumerable ReadJnt0(Stream stream, int blockoffset) { EndianBinaryReader reader = new EndianBinaryReader(stream, Endianness.LittleEndian); int blocksize, blockptr, blocklimit; int num, objnum, i, j, r; List dataoffset = new List(); int sec1offset, sec2offset; NSBMDAnimation[] animation = new NSBMDAnimation[1]; List animlen = new List(); //////////////////////////////////////////////// // joint blockptr = blockoffset + 4; // already read the ID, skip 4 bytes blocksize = reader.ReadInt32(); // block size blocklimit = blocksize + blockoffset; reader.ReadByte(); // skip dummy 0 num = reader.ReadByte(); //assert(num > 0); // no of joint must == 1 Console.WriteLine("No. of Joint = %02x\n", num); //dataoffset = (int*)malloc(sizeof(int)); //if (!dataoffset) return NULL; reader.BaseStream.Seek(10 + (num << 2), SeekOrigin.Current); // skip [char xyz], useless blockptr += 10; reader.BaseStream.Seek(4, SeekOrigin.Current); // go straight to joint data offset blockptr += 4; for (i = 0; i < num; i++) dataoffset.Add(getdword(reader.ReadBytes(4)) + blockoffset); //fseek( fnsbca, 16 * num, SEEK_CUR ); // skip names blockptr += 16 * num; for (i = 0; i < num; i++) { reader.BaseStream.Seek(dataoffset[i], SeekOrigin.Begin); //j = getdword(); if (reader.ReadBytes(4) == new byte[] {0x4A,0x00,0x41,0x43 }) return null; blockptr += 4; animlen.Add(getword(reader.ReadBytes(2))); objnum = getword(reader.ReadBytes(2)); //if (objnum != g_model[0].objnum) return NULL; blockptr += 4; //animation = (ANIMATION*)calloc(sizeof(ANIMATION), objnum); //if (!animation) return NULL; animation = new NSBMDAnimation[objnum]; reader.BaseStream.Seek(4, SeekOrigin.Current); // skip 4 zeros blockptr += 4; sec1offset = getdword(reader.ReadBytes(4)) + dataoffset[i]; sec2offset = getdword(reader.ReadBytes(4)) + dataoffset[i]; blockptr += 8; for (j = 0; j < objnum; j++) { animation[j] = new NSBMDAnimation(); animation[j].dataoffset = getword(reader.ReadBytes(2)) + dataoffset[i]; } for (j = 0; j < objnum; j++) { NSBMD.NSBMDAnimation anim = animation[j]; r = getdword(reader.ReadBytes(4)); anim.flag = r; // if ((r >> 1 & 1) == 0) //{ // any transformation? if ((r >> 1 & 1) == 0) { // translation if ((r & 4) == 1) { // use Base T } else { if ((r & 8) == 1) { // consTX anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } if ((r & 0x10) == 1) { // consTY anim.m_trans[1] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } if ((r & 0x20) == 1) { // consTZ anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } } } if ((r >> 6 & 1) == 0) { // rotation if ((r & 0x100) == 1) { // constR anim.a = ((float)getword(reader.ReadBytes(2))) / 4096.0f; anim.b = ((float)getword(reader.ReadBytes(2))) / 4096.0f; } else { } } if ((r >> 9 & 1) == 0) { // scale if ((r & 0x400) == 1) { // use Base S } else { if ((r & 0x800) == 1) { // consSX anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } if ((r & 0x1000) == 1) {// consSY anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } if ((r & 0x2000) == 1) {// consSZ anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; } else { } } // } } animation[j] = anim; } } reader.Close(); //free(dataoffset); return animation; } static Int32 getdword(byte[] b) { Int32 v; v = b[0]; v |= b[1] << 8; v |= b[2] << 16; v |= b[3] << 24; return v; } static Int32 getword(byte[] b) { Int32 v; v = b[0]; v |= b[1] << 8; return v; } #endregion Methods } }