/// <summary> /// TEMP: Creates super-atlas populated with all archives in array. /// Currently does not support animated textures, normal map, or emission map. /// TODO: Integrate this feature fully with material system. /// </summary> /// <param name="archives">Archive array.</param> /// <param name="borderSize">Number of pixels border to add around image.</param> /// <param name="dilate">Blend texture into surrounding empty pixels. Requires border.</param> /// <param name="maxAtlasSize">Maximum atlas size.</param> /// <param name="alphaTextureFormat">Alpha TextureFormat.</param> /// <param name="nonAlphaFormat">Non-alpha TextureFormat.</param> /// <returns>TextureAtlasBuilder.</returns> public TextureAtlasBuilder CreateTextureAtlasBuilder( int[] archives, int borderSize = 0, bool dilate = false, int maxAtlasSize = 2048, SupportedAlphaTextureFormats alphaTextureFormat = SupportedAlphaTextureFormats.RGBA32, SupportedNonAlphaTextureFormats nonAlphaFormat = SupportedNonAlphaTextureFormats.RGB24) { // Iterate archives TextureFile textureFile = new TextureFile(); TextureAtlasBuilder builder = new TextureAtlasBuilder(); GetTextureSettings settings = TextureReader.CreateTextureSettings(0, 0, 0, 0, borderSize, dilate, maxAtlasSize); settings.stayReadable = true; for (int i = 0; i < archives.Length; i++) { // Load texture file settings.archive = archives[i]; textureFile.Load(Path.Combine(Arena2Path, TextureFile.IndexToFileName(settings.archive)), FileUsage.UseMemory, true); // Add all records for this archive - single frame only for (int record = 0; record < textureFile.RecordCount; record++) { settings.record = record; GetTextureResults results = GetTexture2D(settings, alphaTextureFormat, nonAlphaFormat); DFSize size = textureFile.GetSize(record); DFSize scale = textureFile.GetScale(record); builder.AddTextureItem( results.albedoMap, settings.archive, settings.record, 0, 1, new Vector2(size.Width, size.Height), new Vector2(scale.Width, scale.Height)); } } // Apply the builder builder.Rebuild(borderSize); return builder; }
/// <summary> /// Reads any Daggerfall image file to ImageData package. /// </summary> /// <param name="filename">Name of standalone file as it appears in arena2 folder.</param> /// <param name="record">Which image record to read for multi-image files.</param> /// <param name="frame">Which frame to read for multi-frame images.</param> /// <param name="hasAlpha">Enable this for image cutouts.</param> /// <param name="createTexture">Create a Texture2D.</param> /// <returns>ImageData. If result.type == ImageTypes.None then read failed.</returns> public static ImageData GetImageData(string filename, int record = 0, int frame = 0, bool hasAlpha = false, bool createTexture = true) { // Check API ready DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) return new ImageData(); // Parse image file type ImageTypes fileType; try { fileType = ParseFileType(filename); } catch { return new ImageData(); } // Create base image data ImageData imageData = new ImageData(); imageData.type = fileType; imageData.filename = filename; imageData.record = record; imageData.frame = frame; imageData.hasAlpha = hasAlpha; // Read supported image files DFBitmap dfBitmap = null; switch (fileType) { case ImageTypes.TEXTURE: TextureFile textureFile = new TextureFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); textureFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, textureFile.PaletteName)); dfBitmap = textureFile.GetDFBitmap(record, frame); imageData.offset = textureFile.GetOffset(record); imageData.scale = textureFile.GetScale(record); imageData.size = textureFile.GetSize(record); break; case ImageTypes.IMG: ImgFile imgFile = new ImgFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); imgFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, imgFile.PaletteName)); dfBitmap = imgFile.GetDFBitmap(); imageData.offset = imgFile.ImageOffset; imageData.scale = new DFSize(); imageData.size = imgFile.GetSize(0); break; case ImageTypes.CIF: case ImageTypes.RCI: CifRciFile cifFile = new CifRciFile(Path.Combine(dfUnity.Arena2Path, filename), FileUsage.UseMemory, true); cifFile.LoadPalette(Path.Combine(dfUnity.Arena2Path, cifFile.PaletteName)); dfBitmap = cifFile.GetDFBitmap(record, frame); imageData.offset = cifFile.GetOffset(record); imageData.scale = new DFSize(); imageData.size = cifFile.GetSize(record); break; default: return new ImageData(); } // Store bitmap imageData.dfBitmap = dfBitmap; imageData.width = dfBitmap.Width; imageData.height = dfBitmap.Height; // Create Texture2D if (createTexture) { // Get colors array Color32[] colors = GetColors(imageData); if (colors == null) return new ImageData(); // Create new Texture2D imageData.texture = GetTexture(colors, imageData.width, imageData.height); } return imageData; }
/// <summary> /// Precalculate and cache billboard scale for every record. /// This will change based on animation state and orientation. /// Cache this to array so it only needs to be calculated once. /// Also store number of frames for state animations. /// </summary> /// <param name="dfUnity">DaggerfallUnity singleton. Required for content readers and settings.</param> /// <param name="archive">Texture archive index derived from type and gender.</param> private void CacheRecordSizesAndFrames(DaggerfallUnity dfUnity, int archive) { // Open texture file string path = Path.Combine(dfUnity.Arena2Path, TextureFile.IndexToFileName(archive)); TextureFile textureFile = new TextureFile(path, FileUsage.UseMemory, true); // Cache size and scale for each record summary.RecordSizes = new Vector2[textureFile.RecordCount]; summary.RecordFrames = new int[textureFile.RecordCount]; for (int i = 0; i < textureFile.RecordCount; i++) { // Get size and scale of this texture DFSize size = textureFile.GetSize(i); DFSize scale = textureFile.GetScale(i); // Set start size Vector2 startSize; startSize.x = size.Width; startSize.y = size.Height; // Apply scale Vector2 finalSize; int xChange = (int)(size.Width * (scale.Width / BlocksFile.ScaleDivisor)); int yChange = (int)(size.Height * (scale.Height / BlocksFile.ScaleDivisor)); finalSize.x = (size.Width + xChange); finalSize.y = (size.Height + yChange); // Store final size and frame count summary.RecordSizes[i] = finalSize * MeshReader.GlobalScale; summary.RecordFrames[i] = textureFile.GetFrameCount(i); } }