/// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
            }
        }