public static SpriteInfo GetSpriteInfo(GMFileContent content, uint id, Dictionary <uint, uint> toil = null) { if (id >= content.Sprites->Count) { throw new ArgumentOutOfRangeException(nameof(id)); } var se = (SpriteEntry *)GMFile.PtrFromOffset(content, (&content.Sprites->Offsets)[id]); var ret = new SpriteInfo(); ret.Name = StringFromOffset(content, se->Name); ret.Size = se->Size; ret.Bounding = se->Bounding; ret.BBoxMode = se->BBoxMode; ret.Origin = se->Origin; ret.Version = 1; ret.SeparateColMasks = se->SeparateColMasks.IsTrue(); var tex = &se->Textures; if (tex->Count == ~(uint)0) { var se2 = (SpriteEntry2 *)GMFile.PtrFromOffset(content, (&content.Sprites->Offsets)[id]); tex = &se2->Textures; ret.Version = 2; ret.UnknownFloat = se2->funk; } if (tex->Count == ~(uint)0) { Console.Error.WriteLine($"Warning: texture count of sprite {id} ({((ulong)se-(ulong)content.RawData.BPtr).ToString(SR.HEX_FM8)}) is -1."); return(ret); } ret.TextureIndices = new uint[tex->Count]; for (uint i = 0; i < tex->Count; i++) { if (toil == null) { for (uint j = 0; j < content.TexturePages->Count; j++) { if ((&tex->Offsets)[i] == (&content.TexturePages->Offsets)[j]) { ret.TextureIndices[i] = j; break; } } } else { ret.TextureIndices[i] = toil[(&tex->Offsets)[i]]; } } SpriteCollisionMask *masks = (SpriteCollisionMask *)((ulong)&tex->Offsets + sizeof(uint) * tex->Count); // TODO: store this in a different way. this is wasteful as f**k. uint amt = ret.SeparateColMasks ? masks->MaskCount : 1; //Console.WriteLine("amt="+amt.ToString(SR.HEX_FM8) + " at " + ((ulong)&masks->MaskCount - (ulong)content.RawData.BPtr).ToString(SR.HEX_FM8)); if (amt < 0x100) // guesstimate { ret.CollisionMasks = new bool[amt][, ]; byte *maskData = &masks->MaskData; uint w = (uint)(ret.Size.X & 0x7FFFFFFF); uint h = (uint)(ret.Size.Y & 0x7FFFFFFF); uint wPad = (((w & 7) == 0) ? w : (w - (w & 7) + 8)) / 8; for (uint i = 0; i < amt; i++) { bool[,] stuff = new bool[wPad * 8, h]; for (uint y = 0; y < h; y++) { for (uint x = 0; x < wPad * 8; x++) { uint rown = y * wPad; uint byten = x >> 3; byte bitn = (byte)(x & 7); byte *curptr = maskData + rown + byten; byte curbyte = *curptr; byte curbit = (byte)(curbyte & (byte)(1 << bitn)); stuff[x, y] = curbit != 0; } } ret.CollisionMasks[i] = stuff; maskData += wPad * h; } } else { Console.Error.WriteLine($"Warning: collision mask of sprite {id} ({((ulong)se - (ulong)content.RawData.BPtr).ToString(SR.HEX_FM8)}) is bogus ({amt.ToString(SR.HEX_FM8)}), ignoring..."); } return(ret); }
public static SpriteInfo GetSpriteInfo(GMFileContent content, uint id) { if (id >= content.Sprites->Count) { throw new ArgumentOutOfRangeException(nameof(id)); } var se = (SpriteEntry *)GMFile.PtrFromOffset(content, (&content.Sprites->Offsets)[id]); var ret = new SpriteInfo(); ret.Name = StringFromOffset(content, se->Name); ret.Size = se->Size; ret.Bounding = se->Bounding; ret.BBoxMode = se->BBoxMode; ret.Origin = se->Origin; ret.SeparateColMasks = se->SeparateColMasks.IsTrue(); ret.TextureIndices = new uint[se->Textures.Count]; for (uint i = 0; i < se->Textures.Count; i++) { for (uint j = 0; j < content.TexturePages->Count; j++) { if ((&se->Textures.Offsets)[i] == (&content.TexturePages->Offsets)[j]) { ret.TextureIndices[i] = j; break; } } } SpriteCollisionMask *masks = (SpriteCollisionMask *)&se->Textures + sizeof(uint) * se->Textures.Count; uint amt = ret.SeparateColMasks ? masks->MaskCount : 1; //Console.WriteLine("amt="+amt.ToString(SR.HEX_FM8) + " at " + ((ulong)&masks->MaskCount - (ulong)content.RawData.BPtr).ToString(SR.HEX_FM8)); if (amt < 0x100) // guesstimate { ret.CollisionMasks = new bool[amt][, ]; byte *maskData = &masks->MaskData; uint w = (uint)(ret.Size.X & 0x7FFFFFFF); uint h = (uint)(ret.Size.Y & 0x7FFFFFFF); uint wPad = ((w & 7) == 0) ? w : (w - (w & 7) + 8); for (uint i = 0; i < amt; i++) { bool[,] stuff = new bool[w, h]; for (uint y = 0; y < h; y++) { for (uint x = 0; x < w; x++) { uint rown = y * wPad; uint byten = x >> 3; byte bitn = (byte)(x & 7); byte *curptr = maskData + rown + byten; byte curbyte = *curptr; byte curbit = (byte)(curbyte & (byte)(1 << bitn)); stuff[x, y] = curbit != 0; } } ret.CollisionMasks[i] = stuff; maskData += wPad * h; } } else { Console.WriteLine($"Warning: collision mask of sprite {id} ({((ulong)se - (ulong)content.RawData.BPtr).ToString(SR.HEX_FM8)}) is bogus ({amt.ToString(SR.HEX_FM8)}), ignoring..."); } return(ret); }