/// <summary> /// Gets Unity Texture2D from Daggerfall texture with more options. /// </summary> /// <param name="archive">Archive index.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index.</param> /// <param name="alphaIndex">Index to receive transparent alpha.</param> /// <param name="rectOut">Receives UV rect for texture inside border.</param> /// <param name="border">Number of pixels border to add around image.</param> /// <param name="dilate">Blend texture into surrounding empty pixels. Requires border.</param> /// <param name="copyToOppositeBorder">Copy texture edges to opposite border. Requires border, will overwrite dilate.</param> /// <returns>Texture2D or null.</returns> public Texture2D GetTexture2D( int archive, int record, int frame, int alphaIndex, out Rect rectOut, int border = 0, bool dilate = false, bool copyToOppositeBorder = false, bool makeNoLongerReadable = true) { // Ready check if (!ReadyCheck()) { rectOut = new Rect(); return(null); } // Load texture file textureFile.Load(Path.Combine(Arena2Path, TextureFile.IndexToFileName(archive)), FileUsage.UseMemory, true); // Get Color32 array DFSize sz; Color32[] colors = textureFile.GetColors32(record, frame, alphaIndex, border, out sz); // Dilate edges if (border > 0 && dilate && !copyToOppositeBorder) { ImageProcessing.DilateColors(ref colors, sz); } // Copy to opposite border if (border > 0 && copyToOppositeBorder) { ImageProcessing.WrapBorder(ref colors, sz, border); } // Create Texture2D Texture2D texture; if (alphaIndex < 0) { texture = new Texture2D(sz.Width, sz.Height, TextureFormat.RGB24, MipMaps); } else { texture = new Texture2D(sz.Width, sz.Height, TextureFormat.RGBA32, MipMaps); } texture.SetPixels32(colors); texture.Apply(true, makeNoLongerReadable); // Shrink UV rect to compensate for internal border float ru = 1f / sz.Width; float rv = 1f / sz.Height; rectOut = new Rect(border * ru, border * rv, (sz.Width - border * 2) * ru, (sz.Height - border * 2) * rv); return(texture); }
/// <summary> /// Exports texture images and add references to the dae file. /// </summary> /// <param name="root">Root element.</param> /// <param name="dfMesh">DFMesh.</param> /// <returns>True if successful.</returns> private bool AddImages(ref _daeElement root, ref DFMesh dfMesh) { // Create <library_images> _daeElement imageLib = root.add("library_images"); // Export all textures. foreach (var subMesh in dfMesh.SubMeshes) { // Construct string string materialName = MakeMaterialName(subMesh.TextureArchive, subMesh.TextureRecord); string inputFilename = TextureFile.IndexToFileName(subMesh.TextureArchive); string outputFilename = materialName + "." + imageFormat.ToString().ToLower(); // Export texture string outputPath = Path.Combine(modelOutputPath, imageOutputRelativePath); string outputFilePath = Path.Combine(outputPath, outputFilename); if (!File.Exists(outputFilePath)) { // Load texture file textureFile.Load( Path.Combine(arena2Path, inputFilename), FileUsage.UseDisk, true); // Export image Bitmap bm = textureFile.GetManagedBitmap( subMesh.TextureRecord, 0, false, true); bm.Save(outputFilePath, imageFormat); } // Add <image> string relativeOutputPath = Path.Combine(imageOutputRelativePath, outputFilename); relativeOutputPath = relativeOutputPath.Replace("\\", "/"); _daeElement image = imageLib.add("image"); image.setAttribute("id", materialName + "-image"); image.add("init_from").setCharData(relativeOutputPath); } return(true); }
/// <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> /// 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(); // Might be updated later through texture replacement if (!textureFile.Load(path, FileUsage.UseMemory, true)) { return; } // 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); // Set optional scale TextureReplacement.SetBillboardScale(archive, i, ref finalSize); // Store final size and frame count summary.RecordSizes[i] = finalSize * MeshReader.GlobalScale; summary.RecordFrames[i] = textureFile.GetFrameCount(i); } }