/// <summary> /// Serializes the data /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { if (FileType == Type.World) { // Serialize header BG1 = s.Serialize <ushort>(BG1, name: nameof(BG1)); BG2 = s.Serialize <ushort>(BG2, name: nameof(BG2)); Plan0NumPcxCount = s.Serialize <byte>(Plan0NumPcxCount, name: nameof(Plan0NumPcxCount)); s.DoXOR(0x19, () => Plan0NumPcxFiles = s.SerializeStringArray(Plan0NumPcxFiles, Plan0NumPcxCount, 8, name: nameof(Plan0NumPcxFiles))); // Serialize counts DESCount = s.Serialize <ushort>(DESCount, name: nameof(DESCount)); ETACount = s.Serialize <byte>(ETACount, name: nameof(ETACount)); DESBlockLength = s.Serialize <uint>(DESBlockLength, name: nameof(DESBlockLength)); } else { // Serialize header ETACount = s.Serialize <byte>(ETACount, name: nameof(ETACount)); DESCount = s.Serialize <ushort>(DESCount, name: nameof(DESCount)); } // Serialize DES data DESData = s.SerializeObjectArray <R1_PS1Edu_DESData>(DESData, DESCount, name: nameof(DESData)); if (FileType == Type.World) { WorldDefine = WorldDefine = s.SerializeObject <R1_PC_WorldDefine>(WorldDefine, name: nameof(WorldDefine)); } // Serialize main data block length MainDataBlockLength = s.Serialize <uint>(MainDataBlockLength, name: nameof(MainDataBlockLength)); // We parse the main data block later... MainDataBlockPointer = s.CurrentPointer; s.Goto(MainDataBlockPointer + MainDataBlockLength); if (FileType == Type.Allfix) { DESDataIndices = s.SerializeArray <uint>(DESDataIndices, 8, name: nameof(DESDataIndices)); } // Serialize ETA tables if (FileType == Type.World) { ETAStateCountTableCount = s.Serialize <byte>(ETAStateCountTableCount, name: nameof(ETAStateCountTableCount)); ETAStateCountTable = s.SerializeArray <byte>(ETAStateCountTable, ETAStateCountTableCount, name: nameof(ETAStateCountTable)); } else { ETAStateCountTable = s.SerializeArray <byte>(ETAStateCountTable, ETACount, name: nameof(ETAStateCountTable)); } ETASubStateCountTableCount = s.Serialize <byte>(ETASubStateCountTableCount, name: nameof(ETASubStateCountTableCount)); ETASubStateCountTable = s.SerializeArray <byte>(ETASubStateCountTable, ETASubStateCountTableCount, name: nameof(ETASubStateCountTable)); // Serialize animation descriptor layer table AnimationDescriptorLayersBlockSizeTableCount = s.Serialize <uint>(AnimationDescriptorLayersBlockSizeTableCount, name: nameof(AnimationDescriptorLayersBlockSizeTableCount)); AnimationDescriptorLayersBlockSizeTable = s.SerializeArray <ushort>(AnimationDescriptorLayersBlockSizeTable, AnimationDescriptorLayersBlockSizeTableCount, name: nameof(AnimationDescriptorLayersBlockSizeTable)); // Serialize animation layers AnimationLayers = s.SerializeObjectArray <R1_AnimationLayer>(AnimationLayers, 0xFE, name: nameof(AnimationLayers)); // Serialize the main data block s.DoAt(MainDataBlockPointer, () => { if (FileType == Type.World) { SerializeDES(); SerializeETA(); } else { SerializeETA(); SerializeDES(); } // Helper method for serializing the DES void SerializeDES() { if (ImageDescriptors == null) { ImageDescriptors = new R1_ImageDescriptor[DESCount][]; } if (AnimationDescriptors == null) { AnimationDescriptors = new R1_PS1Edu_AnimationDescriptor[DESCount][]; } int curAnimDesc = 0; // Serialize data for every DES for (int i = 0; i < DESCount; i++) { // Serialize image descriptors ImageDescriptors[i] = s.SerializeObjectArray <R1_ImageDescriptor>(ImageDescriptors[i], DESData[i].ImageDescriptorsCount, name: $"{nameof(ImageDescriptors)}[{i}]"); // Serialize animation descriptors AnimationDescriptors[i] = s.SerializeObjectArray <R1_PS1Edu_AnimationDescriptor>(AnimationDescriptors[i], DESData[i].AnimationDescriptorsCount, name: $"{nameof(AnimationDescriptors)}[{i}]"); // Serialize animation descriptor data for (int j = 0; j < AnimationDescriptors[i].Length; j++) { var descriptor = AnimationDescriptors[i][j]; if (descriptor.FrameCount <= 0) { curAnimDesc++; continue; } // Serialize layer data descriptor.LayersData = s.SerializeArray <byte>(descriptor.LayersData, AnimationDescriptorLayersBlockSizeTable[curAnimDesc], name: nameof(descriptor.LayersData)); // Padding... if (AnimationDescriptorLayersBlockSizeTable[curAnimDesc] % 4 != 0) { // Padding seems to contain garbage data in this case instead of 0xCD? int paddingLength = 4 - AnimationDescriptorLayersBlockSizeTable[curAnimDesc] % 4; s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, paddingLength).ToArray(), paddingLength, name: "Padding"); } // Serialize frames if (descriptor.AnimFramesPointer != 0xFFFFFFFF) { descriptor.Frames = s.SerializeObjectArray <R1_AnimationFrame>(descriptor.Frames, descriptor.FrameCount, name: nameof(descriptor.Frames)); } // Parse layers if (descriptor.Layers == null) { var layers = new List <R1_AnimationLayer>(); var offset = 0; while (offset < descriptor.LayersData.Length) { if (descriptor.LayersData[offset] < 2) { layers.Add(new R1_AnimationLayer() { IsFlippedHorizontally = descriptor.LayersData[offset + 0] == 1, XPosition = descriptor.LayersData[offset + 1], YPosition = descriptor.LayersData[offset + 2], ImageIndex = descriptor.LayersData[offset + 3], }); offset += 4; } else { layers.Add(AnimationLayers[descriptor.LayersData[offset] - 2]); offset++; } } descriptor.Layers = layers.ToArray(); } curAnimDesc++; } } } // Helper method for serializing the ETA void SerializeETA() { if (ETA == null) { ETA = new R1_EventState[ETACount][][]; } var stateIndex = 0; // Serialize every ETA for (int i = 0; i < ETA.Length; i++) { if (ETA[i] == null) { ETA[i] = new R1_EventState[ETAStateCountTable[i]][]; } // EDU serializes the pointer structs, but the pointers are invalid. They can be anything as they're overwritten with valid memory pointers upon load uint[] pointerStructs = Enumerable.Repeat((uint)1, ETA[i].Length).ToArray(); _ = s.SerializeArray <uint>(pointerStructs, pointerStructs.Length, name: $"ETAPointers[{i}]"); // Serialize every state for (int j = 0; j < ETA[i].Length; j++) { // Serialize sub-states ETA[i][j] = s.SerializeObjectArray <R1_EventState>(ETA[i][j], ETASubStateCountTable[stateIndex], name: $"{nameof(ETA)}[{i}][{j}]"); stateIndex++; } } } }); }
/// <summary> /// Gets the sprite texture for an event /// </summary> /// <param name="context">The context</param> /// <param name="imgBuffer">The image buffer, if available</param> /// <param name="s">The image descriptor to use</param> /// <returns>The texture</returns> public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor img) { if (img.ImageType != 2 && img.ImageType != 3) { return(null); } if (img.Unknown2 == 0) { return(null); } ImageBuffer buf = context.GetStoredObject <ImageBuffer>("vram"); // Get the image properties var width = img.Width; var height = img.Height; var offset = img.ImageBufferOffset; Texture2D tex = TextureHelpers.CreateTexture2D(width, height); var palette = FileFactory.Read <R1_PS1_Executable>(ExeFilePath, context).Saturn_Palettes; var paletteOffset = img.PaletteInfo; var isBigRay = img.Offset.file.filePath == GetBigRayFilePath(); var isFont = context.GetStoredObject <R1_PS1_FontData[]>("Font")?.SelectMany(x => x.ImageDescriptors).Contains(img) == true; //paletteOffset = (ushort)(256 * (img.Unknown2 >> 4)); if (img.ImageType == 3) { //paletteOffset = 20 * 256; paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256)); } else { paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256) + ((img.PaletteInfo >> 8)) * 16); //paletteOffset = (ushort)((GetPaletteIndex(context) * 256) + ((img.Unknown2 >> 4) - 1) * 16); //paletteOffset = (ushort)(19 * 256 + ((img.Unknown2 >> 4) - 1) * 16); } // Set every pixel if (img.ImageType == 3) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = buf.GetPixel8((uint)(offset + width * y + x)); // Set the pixel var color = palette[paletteOffset + paletteIndex].GetColor(); if (paletteIndex == 0) { color = new Color(color.r, color.g, color.b, 0f); } else { color = new Color(color.r, color.g, color.b, 1f); } tex.SetPixel(x, height - 1 - y, color); } } } else if (img.ImageType == 2) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = buf.GetPixel8((uint)(offset + (width * y + x) / 2)); if (x % 2 == 0) { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4); } else { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0); } // Set the pixel var color = palette[paletteOffset + paletteIndex].GetColor(); if (paletteIndex == 0) { color = new Color(color.r, color.g, color.b, 0f); } else { color = new Color(color.r, color.g, color.b, 1f); } tex.SetPixel(x, height - 1 - y, color); } } } //tex.SetPixels(Enumerable.Repeat(Color.blue, tex.width * tex.height).ToArray()); tex.Apply(); return(tex); }
/// <summary> /// Gets the sprite texture for an event /// </summary> /// <param name="context">The context</param> /// <param name="imgBuffer">The image buffer, if available</param> /// <param name="s">The image descriptor to use</param> /// <returns>The texture</returns> public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor s) { if (s.ImageType != 2 && s.ImageType != 3) { return(null); } // Ignore dummy sprites if (s.IsDummySprite()) { return(null); } // Get the image properties var width = s.Width; var height = s.Height; var offset = s.ImageBufferOffset; var pal4 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 4), context, (y, x) => x.Length = 256); var pal8 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 8), context, (y, x) => x.Length = 256); // Select correct palette var palette = s.ImageType == 3 ? pal8.Value : pal4.Value; var paletteOffset = 16 * s.Unknown1; // Create the texture Texture2D tex = TextureHelpers.CreateTexture2D(width, height); // Set every pixel if (s.ImageType == 3) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = imgBuffer[offset + width * y + x]; // Set the pixel tex.SetPixel(x, height - 1 - y, palette[paletteIndex].GetColor()); } } } else if (s.ImageType == 2) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int actualX = (s.ImageOffsetInPageX + x) / 2; var paletteIndex = imgBuffer[offset + (width * y + x) / 2]; if (x % 2 == 0) { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0); } else { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4); } // Set the pixel tex.SetPixel(x, height - 1 - y, palette[paletteOffset + paletteIndex].GetColor()); } } } // Apply the changes tex.Apply(); // Return the texture return(tex); }