Exemple #1
0
        /// <summary>
        /// Get a new Material based on climate.
        /// </summary>
        /// <param name="key">Material key.</param>
        /// <param name="climate">New climate base.</param>
        /// <param name="season">New season.</param>
        /// <param name="windowStyle">New window style.</param>
        /// <returns>New material.</returns>
        public Material ChangeClimate(int key, ClimateBases climate, ClimateSeason season, WindowStyle windowStyle)
        {
            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Reverse key and apply climate
            int archive, record, frame;

            ReverseTextureKey(key, out archive, out record, out frame);
            archive = ClimateSwaps.ApplyClimate(archive, record, climate, season);

            // Get new material
            Material       material;
            CachedMaterial cm = GetMaterialFromCache(archive, record, out material);

            // Handle windows
            if (cm.isWindow)
            {
                ChangeWindowEmissionColor(material, windowStyle);
            }

            return(material);
        }
Exemple #2
0
        /// <summary>
        /// Gets Unity Material from Daggerfall terrain tilemap texture.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <returns>Material or null.</returns>
        public Material GetTerrainTilesetMaterial(int archive)
        {
            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Return from cache if present
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, TileMapKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = GetMaterialFromCache(key);
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            //// TODO: Attempt to load prebuilt atlas asset, otherwise create one in memory
            //Texture2D texture = TerrainAtlasBuilder.LoadTerrainAtlasTextureResource(archive, CreateTextureAssetResourcesPath);
            //if (texture == null)

            // Generate atlas
            // Not currently generating normals as very slow on such a large texture
            // and results are not very noticeable
            GetTextureResults results = textureReader.GetTerrainTilesetTexture(archive);

            results.albedoMap.filterMode = MainFilterMode;

            Shader   shader   = Shader.Find(_DaggerfallTilemapShaderName);
            Material material = new Material(shader);

            material.name = string.Format("TEXTURE.{0:000} [Tilemap]", archive);
            material.SetTexture("_TileAtlasTex", results.albedoMap);

            CachedMaterial newcm = new CachedMaterial()
            {
                key        = key,
                keyGroup   = TileMapKeyGroup,
                material   = material,
                filterMode = MainFilterMode,
            };

            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #3
0
        /// <summary>
        /// Gets CachedMaterial properties for a billboard with custom material.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        /// <param name="cachedMaterialOut">CachedMaterial out</param>
        /// <returns>True if CachedMaterial found.</returns>
        public bool GetCachedMaterialCustomBillboard(int archive, int record, int frame, out CachedMaterial cachedMaterialOut)
        {
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame, CustomBillboardKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                cachedMaterialOut = GetMaterialFromCache(key);
                return(true);
            }

            cachedMaterialOut = new CachedMaterial();
            return(false);
        }
Exemple #4
0
        /// <summary>
        /// Gets CachedMaterial properties for an atlased material.
        /// Atlas material will not be loaded automatically if not found in cache.
        /// </summary>
        /// <param name="archive">Atlas archive index.</param>
        /// <param name="cachedMaterialOut">CachedMaterial out</param>
        /// <returns>True if CachedMaterial found.</returns>
        public bool GetCachedMaterialAtlas(int archive, out CachedMaterial cachedMaterialOut)
        {
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, AtlasKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                cachedMaterialOut = GetMaterialFromCache(key);
                return(true);
            }

            cachedMaterialOut = new CachedMaterial();
            return(false);
        }
Exemple #5
0
        /// <summary>
        /// Gets Unity Material from Daggerfall terrain tilemap texture.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <returns>Material or null.</returns>
        public Material GetTerrainTilesetMaterial(int archive)
        {
            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Return from cache if present
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, TileMapKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            //// TODO: Attempt to load prebuilt atlas asset, otherwise create one in memory
            //Texture2D texture = TerrainAtlasBuilder.LoadTerrainAtlasTextureResource(archive, CreateTextureAssetResourcesPath);
            //if (texture == null)
            Texture2D texture = textureReader.GetTerrainTilesetTexture(archive);

            texture.filterMode = MainFilterMode;

            Shader   shader   = Shader.Find(_DaggerfallTilemapShaderName);
            Material material = new Material(shader);

            material.name        = string.Format("TEXTURE.{0:000} [Tilemap]", archive);
            material.mainTexture = texture;

            CachedMaterial newcm = new CachedMaterial()
            {
                key        = key,
                keyGroup   = TileMapKeyGroup,
                material   = material,
                filterMode = MainFilterMode,
            };

            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #6
0
        /// <summary>
        /// Sets CachedMaterial properties.
        /// existing Material will be updated in cache with cachedMaterialIn.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        /// <param name="frame">Frame index.</param>
        /// <param name="cachedMaterialIn">the CachedMaterial used to update the cache.</param>
        /// <returns>True if CachedMaterial was found and updated successfully.</returns>
        public bool SetCachedMaterial(int archive, int record, int frame, CachedMaterial cachedMaterialIn)
        {
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                materialDict[key] = cachedMaterialIn;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #7
0
        private CachedMaterial GetMaterialFromCache(int key)
        {
            CachedMaterial cachedMaterial = materialDict[key];

            // Update timestamp of last access, but only if difference is
            // significant to limit the number of reassignment to dictionary.
            float time = Time.realtimeSinceStartup;

            if (time - cachedMaterial.timeStamp > 59)
            {
                cachedMaterial.timeStamp = time;
                materialDict[key]        = cachedMaterial;
            }

            return(cachedMaterial);
        }
Exemple #8
0
        /// <summary>
        /// Gets CachedMaterial properties.
        /// Material will be loaded into cache if not present already.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        /// <param name="frame">Frame index.</param>
        /// <param name="cachedMaterialOut">CachedMaterial out.</param>
        /// <param name="alphaIndex">Alpha index used if material needs to be loaded.</param>
        /// <returns>True if CachedMaterial found or loaded successfully.</returns>
        public bool GetCachedMaterial(int archive, int record, int frame, out CachedMaterial cachedMaterialOut, int alphaIndex = -1)
        {
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                cachedMaterialOut = GetMaterialFromCache(key);
                return(true);
            }
            else
            {
                // Not in cache - try to load material
                if (GetMaterial(archive, record, frame, alphaIndex) == null)
                {
                    cachedMaterialOut = new CachedMaterial();
                    return(false);
                }
            }

            cachedMaterialOut = materialDict[key];

            return(true);
        }
Exemple #9
0
        /// <summary>
        /// Gets Unity Material atlas from Daggerfall texture archive.
        /// </summary>
        /// <param name="archive">Archive index to create atlas from.</param>
        /// <param name="alphaIndex">Index to receive transparent alpha.</param>
        /// <param name="padding">Number of pixels each sub-texture.</param>
        /// <param name="maxAtlasSize">Max size of atlas.</param>
        /// <param name="rectsOut">Array of rects, one for each record sub-texture and frame.</param>
        /// <param name="indicesOut">Array of record indices into rect array, accounting for animation frames.</param>
        /// <param name="border">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="shrinkUVs">Number of pixels to shrink UV rect.</param>
        /// <param name="copyToOppositeBorder">Copy texture edges to opposite border. Requires border, will overwrite dilate.</param>
        /// <param name="isBillboard">Set true when creating atlas material for simple billboards.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterialAtlas(
            int archive,
            int alphaIndex,
            int padding,
            int maxAtlasSize,
            out Rect[] rectsOut,
            out RecordIndex[] indicesOut,
            int border                = 0,
            bool dilate               = false,
            int shrinkUVs             = 0,
            bool copyToOppositeBorder = false,
            bool isBillboard          = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectsOut   = null;
                indicesOut = null;
                return(null);
            }

            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, AtlasKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = GetMaterialFromCache(key);
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    rectsOut   = cm.atlasRects;
                    indicesOut = cm.atlasIndices;
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            // Create material
            Material material;

            if (isBillboard)
            {
                material = CreateStandardMaterial(CustomBlendMode.Cutout);
            }
            else
            {
                material = CreateStandardMaterial();
            }

            // Create settings
            GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, 0, 0, alphaIndex, border, dilate);

            settings.createNormalMap      = GenerateNormals;
            settings.autoEmission         = true;
            settings.atlasShrinkUVs       = shrinkUVs;
            settings.atlasPadding         = padding;
            settings.atlasMaxSize         = maxAtlasSize;
            settings.copyToOppositeBorder = copyToOppositeBorder;

            // Setup material
            material.name = string.Format("TEXTURE.{0:000} [Atlas]", archive);
            GetTextureResults results = textureReader.GetTexture2DAtlas(settings, AlphaTextureFormat);

            material.mainTexture            = results.albedoMap;
            material.mainTexture.filterMode = MainFilterMode;

            // Setup normal map
            if (GenerateNormals && results.normalMap != null)
            {
                results.normalMap.filterMode = MainFilterMode;
                material.SetTexture(Uniforms.BumpMap, results.normalMap);
                material.EnableKeyword(KeyWords.NormalMap);
            }

            // Setup emission map
            if (results.isEmissive && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture(Uniforms.EmissionMap, results.emissionMap);
                material.SetColor(Uniforms.EmissionColor, Color.white);
                material.EnableKeyword(KeyWords.Emission);
            }

            // TEMP: Bridging between legacy material out params and GetTextureResults for now
            Vector2[] sizesOut, scalesOut, offsetsOut;
            sizesOut   = results.atlasSizes.ToArray();
            scalesOut  = results.atlasScales.ToArray();
            offsetsOut = results.atlasOffsets.ToArray();
            rectsOut   = results.atlasRects.ToArray();
            indicesOut = results.atlasIndices.ToArray();

            // Setup cached material
            CachedMaterial newcm = new CachedMaterial();

            newcm.key              = key;
            newcm.keyGroup         = AtlasKeyGroup;
            newcm.atlasRects       = rectsOut;
            newcm.atlasIndices     = indicesOut;
            newcm.material         = material;
            newcm.filterMode       = MainFilterMode;
            newcm.recordSizes      = sizesOut;
            newcm.recordScales     = scalesOut;
            newcm.recordOffsets    = offsetsOut;
            newcm.atlasFrameCounts = results.atlasFrameCounts.ToArray();
            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #10
0
        /// <summary>
        /// Gets Unity Material 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="rectOut">Receives UV rect for texture inside border.</param>
        /// <param name="borderSize">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="isBillboard">Set true when creating atlas material for simple billboards.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterial(
            int archive,
            int record,
            int frame,
            int alphaIndex,
            out Rect rectOut,
            int borderSize   = 0,
            bool dilate      = false,
            bool isBillboard = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectOut = new Rect();
                return(null);
            }

            // Try to retrieve from cache
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = GetMaterialFromCache(key);
                rectOut = cm.singleRect;
                return(cm.material);
            }

            Material          material;
            GetTextureResults results;

            // Try to import a material from mods, otherwise create a standard material
            // and import textures from Daggerfall files and loose files.
            if (!TextureReplacement.TextureExistsAmongLooseFiles(archive, record, frame) &&
                TextureReplacement.TryImportMaterial(archive, record, frame, out material))
            {
                results = TextureReplacement.MakeResults(material, archive, record);
                TextureReplacement.AssignFiltermode(material);
            }
            else
            {
                // Create new texture settings
                GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, record, frame, alphaIndex, borderSize, dilate);
                settings.autoEmissionForWindows = true;
                settings.sharpen = Sharpen;
                if (GenerateNormals)
                {
                    settings.createNormalMap = true;
                    settings.normalStrength  = NormalTextureStrength;
                }

                // Set emissive for self-illuminated textures
                if (textureReader.IsEmissive(archive, record))
                {
                    settings.createEmissionMap = true;
                    settings.emissionIndex     = -1;
                }

                // Get texture
                results = textureReader.GetTexture2D(settings, AlphaTextureFormat, TextureImport.LooseFiles);

                // Create material
                if (isBillboard)
                {
                    material = CreateStandardMaterial(CustomBlendMode.Cutout);
                }
                else
                {
                    material = CreateStandardMaterial();
                }

                // Setup material
                material.name                   = FormatName(archive, record);
                material.mainTexture            = results.albedoMap;
                material.mainTexture.filterMode = MainFilterMode;

                // Setup normal map
                bool importedNormals = TextureReplacement.TextureExistsAmongLooseFiles(settings.archive, settings.record, settings.frame, TextureMap.Normal);
                if ((GenerateNormals || importedNormals) && results.normalMap != null)
                {
                    results.normalMap.filterMode = MainFilterMode;
                    material.SetTexture(Uniforms.BumpMap, results.normalMap);
                    material.EnableKeyword(KeyWords.NormalMap);
                }

                // Setup emission map
                if (results.isEmissive && !results.isWindow && results.emissionMap != null)
                {
                    results.emissionMap.filterMode = MainFilterMode;
                    material.SetTexture(Uniforms.EmissionMap, results.emissionMap);
                    material.SetColor(Uniforms.EmissionColor, Color.white);
                    material.EnableKeyword(KeyWords.Emission);
                }
                else if (results.isEmissive && results.isWindow && results.emissionMap != null)
                {
                    results.emissionMap.filterMode = MainFilterMode;
                    material.SetTexture(Uniforms.EmissionMap, results.emissionMap);
                    material.SetColor(Uniforms.EmissionColor, DayWindowColor * DayWindowIntensity);
                    material.EnableKeyword(KeyWords.Emission);
                }

                // Import additional custom components of material
                TextureReplacement.CustomizeMaterial(archive, record, frame, material);
            }

            // Setup cached material
            DFSize     size   = results.textureFile.GetSize(record);
            DFSize     scale  = results.textureFile.GetScale(record);
            DFPosition offset = results.textureFile.GetOffset(record);

            Vector2[] recordSizes = new Vector2[1] {
                new Vector2(size.Width, size.Height)
            };
            Vector2[] recordScales = new Vector2[1] {
                new Vector2(scale.Width, scale.Height)
            };
            Vector2[] recordOffsets = new Vector2[1] {
                new Vector2(offset.X, offset.Y)
            };
            CachedMaterial newcm = new CachedMaterial()
            {
                key              = key,
                keyGroup         = 0,
                albedoMap        = results.albedoMap,
                normalMap        = results.normalMap,
                emissionMap      = results.emissionMap,
                singleRect       = rectOut = results.singleRect,
                material         = material,
                filterMode       = MainFilterMode,
                isWindow         = results.isWindow,
                recordSizes      = recordSizes,
                recordScales     = recordScales,
                recordOffsets    = recordOffsets,
                singleFrameCount = results.textureFile.GetFrameCount(record),
                framesPerSecond  = archive == FireWallsArchive ? 5 : 0, // Slow down fire walls
            };

            materialDict.Add(key, newcm);

            return(material);
        }
        /// <summary>
        /// Gets Unity Material from Daggerfall terrain tilemap texture.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <returns>Material or null.</returns>
        public Material GetTerrainTilesetMaterial(int archive)
        {
            // Ready check
            if (!IsReady)
                return null;

            // Return from cache if present
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, TileMapKeyGroup);
            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return cm.material;
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            //// TODO: Attempt to load prebuilt atlas asset, otherwise create one in memory
            //Texture2D texture = TerrainAtlasBuilder.LoadTerrainAtlasTextureResource(archive, CreateTextureAssetResourcesPath);
            //if (texture == null)

            // Generate atlas
            // Not currently generating normals as very slow on such a large texture
            // and results are not very noticeable
            GetTextureResults results = textureReader.GetTerrainTilesetTexture(archive);
            results.albedoMap.filterMode = MainFilterMode;

            Shader shader = Shader.Find(_DaggerfallTilemapShaderName);
            Material material = new Material(shader);
            material.name = string.Format("TEXTURE.{0:000} [Tilemap]", archive);
            material.SetTexture("_TileAtlasTex", results.albedoMap);

            CachedMaterial newcm = new CachedMaterial()
            {
                key = key,
                keyGroup = TileMapKeyGroup,
                material = material,
                filterMode = MainFilterMode,
            };
            materialDict.Add(key, newcm);

            return material;
        }
Exemple #12
0
        /// <summary>
        /// Gets Unity Material atlas from Daggerfall texture archive.
        /// </summary>
        /// <param name="archive">Archive index to create atlas from.</param>
        /// <param name="alphaIndex">Index to receive transparent alpha.</param>
        /// <param name="rectsOut">Array of rects, one for each record sub-texture and frame.</param>
        /// <param name="padding">Number of pixels each sub-texture.</param>
        /// <param name="maxAtlasSize">Max size of atlas.</param>
        /// <param name="rectsOut">Array of rects, one for each record sub-texture and frame.</param>
        /// <param name="indicesOut">Array of record indices into rect array, accounting for animation frames.</param>
        /// <param name="border">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="shrinkUVs">Number of pixels to shrink UV rect.</param>
        /// <param name="copyToOppositeBorder">Copy texture edges to opposite border. Requires border, will overwrite dilate.</param>
        /// <param name="shader">Shader for material. If null, DefaultShaderName will be applied.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterialAtlas(
            int archive,
            int alphaIndex,
            int padding,
            int maxAtlasSize,
            out Rect[] rectsOut,
            out RecordIndex[] indicesOut,
            int border                = 0,
            bool dilate               = false,
            int shrinkUVs             = 0,
            bool copyToOppositeBorder = false,
            Shader shader             = null)
        {
            // Ready check
            if (!IsReady)
            {
                rectsOut   = null;
                indicesOut = null;
                return(null);
            }

            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, AtlasKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    rectsOut   = cm.atlasRects;
                    indicesOut = cm.indices;
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            if (shader == null)
            {
                shader = Shader.Find(DefaultShaderName);
            }

            Vector2[] sizesOut, scalesOut, offsetsOut;
            Material  material = new Material(shader);

            material.name = string.Format("TEXTURE.{0:000} [Atlas]", archive);
            Texture2D texture = textureReader.GetTexture2DAtlas(
                archive,
                alphaIndex,
                padding,
                maxAtlasSize,
                out rectsOut,
                out indicesOut,
                out sizesOut,
                out scalesOut,
                out offsetsOut,
                border,
                dilate,
                shrinkUVs,
                copyToOppositeBorder);

            material.mainTexture            = texture;
            material.mainTexture.filterMode = MainFilterMode;

            CachedMaterial newcm = new CachedMaterial();

            newcm.key           = key;
            newcm.keyGroup      = AtlasKeyGroup;
            newcm.atlasRects    = rectsOut;
            newcm.indices       = indicesOut;
            newcm.material      = material;
            newcm.filterMode    = MainFilterMode;
            newcm.recordSizes   = sizesOut;
            newcm.recordScales  = scalesOut;
            newcm.recordOffsets = offsetsOut;
            materialDict.Add(key, newcm);

            return(material);
        }
        /// <summary>
        /// Gets CachedMaterial properties.
        /// Material will be loaded into cache if not present already.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        /// <param name="frame">Frame index.</param>
        /// <param name="cachedMaterialOut">CachedMaterial out.</param>
        /// <param name="alphaIndex">Alpha index used if material needs to be loaded.</param>
        /// <returns>True if CachedMaterial found or loaded successfully.</returns>
        public bool GetCachedMaterial(int archive, int record, int frame, out CachedMaterial cachedMaterialOut, int alphaIndex = -1)
        {
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);
            if (materialDict.ContainsKey(key))
            {
                cachedMaterialOut = materialDict[key];
                return true;
            }
            else
            {
                // Not in cache - try to load material
                if (GetMaterial(archive, record, frame, alphaIndex) == null)
                {
                    cachedMaterialOut = new CachedMaterial();
                    return false;
                }
            }

            cachedMaterialOut = materialDict[key];

            return true;
        }
        /// <summary>
        /// Gets Unity Mesh from previously combined model data.
        /// </summary>
        /// <param name="dfUnity">DaggerfallUnity singleon for loading content.</param>
        /// <param name="combiner">ModelCombiner to build from.</param>
        /// <param name="cachedMaterialsOut">Array of cached materials in order of submesh.</param>
        /// <param name="textureKeysOut">Array of original texture keys in order of submesh.</param>
        /// <param name="hasAnimationsOut">True if one or more materials have animations.</param>
        /// <param name="solveTangents">Solve tangents for this mesh.</param>
        /// <param name="lightmapUVs">Add secondary lightmap UVs to this mesh.</param>
        /// <returns>Mesh object or null.</returns>
        public Mesh GetCombinedMesh(
            DaggerfallUnity dfUnity,
            ModelCombiner combiner,
            out CachedMaterial[] cachedMaterialsOut,
            out int[] textureKeysOut,
            out bool hasAnimationsOut,
            bool solveTangents = false,
            bool lightmapUVs   = false)
        {
            cachedMaterialsOut = null;
            hasAnimationsOut   = false;
            textureKeysOut     = null;

            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Get combined model
            ModelCombiner.CombinedModel combinedModel;
            if (!combiner.GetCombinedModel(out combinedModel))
            {
                return(null);
            }

            // Load materials
            cachedMaterialsOut = new CachedMaterial[combinedModel.SubMeshes.Length];
            textureKeysOut     = new int[combinedModel.SubMeshes.Length];
            for (int i = 0; i < combinedModel.SubMeshes.Length; i++)
            {
                int archive = combinedModel.SubMeshes[i].TextureArchive;
                int record  = combinedModel.SubMeshes[i].TextureRecord;
                textureKeysOut[i] = MaterialReader.MakeTextureKey((short)archive, (byte)record, (byte)0);

                // Add material to array
                CachedMaterial cachedMaterial;
                dfUnity.MaterialReader.GetCachedMaterial(archive, record, 0, out cachedMaterial);
                cachedMaterialsOut[i] = cachedMaterial;

                // Set animation flag
                if (cachedMaterial.singleFrameCount > 1 && !hasAnimationsOut)
                {
                    hasAnimationsOut = true;
                }
            }

            // Create mesh
            Mesh mesh = new Mesh();

            mesh.name         = "CombinedMesh";
            mesh.vertices     = combinedModel.Vertices;
            mesh.normals      = combinedModel.Normals;
            mesh.uv           = combinedModel.UVs;
            mesh.subMeshCount = combinedModel.SubMeshes.Length;

            // Set submesh triangles
            for (int s = 0; s < mesh.subMeshCount; s++)
            {
                var   sub       = combinedModel.SubMeshes[s];
                int[] triangles = new int[sub.PrimitiveCount * 3];
                for (int t = 0; t < sub.PrimitiveCount * 3; t++)
                {
                    triangles[t] = combinedModel.Indices[sub.StartIndex + t];
                }
                mesh.SetTriangles(triangles, s);
            }

            // Finalise mesh
            if (solveTangents)
            {
                TangentSolver(mesh);
            }
            if (lightmapUVs)
            {
                AddLightmapUVs(mesh);
            }
            mesh.RecalculateBounds();

            return(mesh);
        }
Exemple #15
0
        /// <summary>
        /// Gets Unity Material 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="rectOut">Receives UV rect for texture inside border.</param>
        /// <param name="borderSize">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterial(
            int archive,
            int record,
            int frame,
            int alphaIndex,
            out Rect rectOut,
            int borderSize = 0,
            bool dilate    = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectOut = new Rect();
                return(null);
            }

            // Try to retrieve from cache
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                rectOut = cm.singleRect;
                return(cm.material);
            }

            // Create new texture settings
            GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, record, frame, alphaIndex, borderSize, dilate);

            settings.autoEmissionForWindows = true;
            settings.sharpen = Sharpen;
            if (GenerateNormals)
            {
                settings.createNormalMap = true;
                settings.normalStrength  = NormalTextureStrength;
            }

            // Set emissive for self-illuminated textures
            if (textureReader.IsEmissive(archive, record))
            {
                settings.createEmissionMap = true;
                settings.emissionIndex     = -1;
            }

            // Get texture
            GetTextureResults results = textureReader.GetTexture2D(settings, AlphaTextureFormat, NonAlphaTextureFormat);

            rectOut = results.singleRect;

            // Setup material
            Material material = CreateStandardMaterial();

            material.name                   = FormatName(archive, record);
            material.mainTexture            = results.albedoMap;
            material.mainTexture.filterMode = MainFilterMode;

            // Setup normal map
            if (GenerateNormals && results.normalMap != null)
            {
                results.normalMap.filterMode = MainFilterMode;
                material.SetTexture("_BumpMap", results.normalMap);
                material.EnableKeyword("_NORMALMAP");
            }

            // Setup emission map
            if (results.isEmissive && !results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", Color.white);
                material.EnableKeyword("_EMISSION");
            }
            else if (results.isEmissive && results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", DayWindowColor * DayWindowIntensity);
                material.EnableKeyword("_EMISSION");
            }

            // Setup cached material
            DFSize     size   = results.textureFile.GetSize(record);
            DFSize     scale  = results.textureFile.GetScale(record);
            DFPosition offset = results.textureFile.GetOffset(record);

            Vector2[] recordSizes = new Vector2[1] {
                new Vector2(size.Width, size.Height)
            };
            Vector2[] recordScales = new Vector2[1] {
                new Vector2(scale.Width, scale.Height)
            };
            Vector2[] recordOffsets = new Vector2[1] {
                new Vector2(offset.X, offset.Y)
            };
            CachedMaterial newcm = new CachedMaterial()
            {
                key              = key,
                keyGroup         = 0,
                albedoMap        = results.albedoMap,
                normalMap        = results.normalMap,
                emissionMap      = results.emissionMap,
                singleRect       = rectOut,
                material         = material,
                filterMode       = MainFilterMode,
                isWindow         = results.isWindow,
                recordSizes      = recordSizes,
                recordScales     = recordScales,
                recordOffsets    = recordOffsets,
                singleFrameCount = results.textureFile.GetFrameCount(record),
            };

            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #16
0
        /// <summary>
        /// Gets Unity Mesh from Daggerfall model.
        /// </summary>
        /// <param name="dfUnity">DaggerfallUnity singleon for loading content.</param>
        /// <param name="modelID">Daggerfall model ID to load..</param>
        /// <param name="cachedMaterialsOut">Array of cached materials in order of submesh.</param>
        /// <param name="textureKeysOut">Array of original texture keys in order of submesh.</param>
        /// <param name="hasAnimationsOut">True if one or more materials have animations.</param>
        /// <param name="solveTangents">Solve tangents for this mesh.</param>
        /// <param name="lightmapUVs">Add secondary lightmap UVs to this mesh.</param>
        /// <returns>Mesh object or null.</returns>
        public Mesh GetMesh(
            DaggerfallUnity dfUnity,
            uint modelID,
            out CachedMaterial[] cachedMaterialsOut,
            out int[] textureKeysOut,
            out bool hasAnimationsOut,
            bool solveTangents = false,
            bool lightmapUVs   = false)
        {
            cachedMaterialsOut = null;
            hasAnimationsOut   = false;
            textureKeysOut     = null;

            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Get model data
            ModelData model;

            if (!GetModelData(modelID, out model))
            {
                DaggerfallUnity.LogMessage(string.Format("Unknown ModelID {0}.", modelID.ToString()), true);
                return(null);
            }

            // Load materials
            cachedMaterialsOut = new CachedMaterial[model.SubMeshes.Length];
            textureKeysOut     = new int[model.SubMeshes.Length];
            for (int i = 0; i < model.SubMeshes.Length; i++)
            {
                int archive = model.DFMesh.SubMeshes[i].TextureArchive;
                int record  = model.DFMesh.SubMeshes[i].TextureRecord;
                textureKeysOut[i] = MaterialReader.MakeTextureKey((short)archive, (byte)record, (byte)0);

                // Add material to array
                CachedMaterial cachedMaterial;
                dfUnity.MaterialReader.GetCachedMaterial(archive, record, 0, out cachedMaterial);
                cachedMaterialsOut[i] = cachedMaterial;

                // Set animation flag
                if (cachedMaterial.singleFrameCount > 1 && !hasAnimationsOut)
                {
                    hasAnimationsOut = true;
                }
            }

            // Create mesh
            Mesh mesh = new Mesh();

            mesh.name         = modelID.ToString();
            mesh.vertices     = model.Vertices;
            mesh.normals      = model.Normals;
            mesh.uv           = model.UVs;
            mesh.subMeshCount = model.SubMeshes.Length;

            // Set submesh triangles
            for (int s = 0; s < mesh.subMeshCount; s++)
            {
                var   sub       = model.SubMeshes[s];
                int[] triangles = new int[sub.PrimitiveCount * 3];
                for (int t = 0; t < sub.PrimitiveCount * 3; t++)
                {
                    triangles[t] = model.Indices[sub.StartIndex + t];
                }
                mesh.SetTriangles(triangles, s);
            }

            // Finalise mesh
            if (solveTangents)
            {
                TangentSolver(mesh);
            }
            if (lightmapUVs)
            {
                AddLightmapUVs(mesh);
            }
            mesh.RecalculateBounds();
            mesh.Optimize();

            return(mesh);
        }
        /// <summary>
        /// Gets Unity Material from Daggerfall terrain using texture arrays.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <returns>Material or null.</returns>
        public Material GetTerrainTextureArrayMaterial(int archive)
        {
            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Return from cache if present
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, TileMapKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = GetMaterialFromCache(key);
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            // Generate texture array
            Texture2DArray textureArrayTerrainTiles              = textureReader.GetTerrainTextureArray(archive, TextureMap.Albedo);
            Texture2DArray textureArrayTerrainTilesNormalMap     = textureReader.GetTerrainTextureArray(archive, TextureMap.Normal);
            Texture2DArray textureArrayTerrainTilesParallaxMap   = textureReader.GetTerrainTextureArray(archive, TextureMap.Height);
            Texture2DArray textureArrayTerrainTilesMetallicGloss = textureReader.GetTerrainTextureArray(archive, TextureMap.MetallicGloss);

            textureArrayTerrainTiles.filterMode = MainFilterMode;

            Shader   shader   = Shader.Find(_DaggerfallTilemapTextureArrayShaderName);
            Material material = new Material(shader);

            material.name = string.Format("TEXTURE.{0:000} [TilemapTextureArray]", archive);

            material.SetTexture(TileTexArrUniforms.TileTexArr, textureArrayTerrainTiles);
            if (textureArrayTerrainTilesNormalMap != null)
            {
                // If normal map texture array was loaded successfully enable _NORMALMAP in shader and set texture
                material.SetTexture(TileTexArrUniforms.TileNormalMapTexArr, textureArrayTerrainTilesNormalMap);
                material.EnableKeyword(KeyWords.NormalMap);
                //textureArrayTerrainTilesNormalMap.filterMode = MainFilterMode;
            }
            if (textureArrayTerrainTilesParallaxMap != null)
            {
                // If parallax map texture array was loaded successfully enable _PARALLAXMAP in shader and set texture
                material.SetTexture(TileTexArrUniforms.TileParallaxMapTexArr, textureArrayTerrainTilesParallaxMap);
                material.EnableKeyword(KeyWords.HeightMap);
                //textureArrayTerrainTilesParallaxMap.filterMode = MainFilterMode;
            }
            if (textureArrayTerrainTilesMetallicGloss != null)
            {
                // If metallic gloss map texture array was loaded successfully enable _METALLICGLOSSMAP in shader and set texture
                material.SetTexture(TileTexArrUniforms.TileMetallicGlossMapTexArr, textureArrayTerrainTilesMetallicGloss);
                material.EnableKeyword(KeyWords.MetallicGlossMap);
                material.SetFloat(Uniforms.Smoothness, 0.35f);
                //textureArrayTerrainTilesMetallicGloss.filterMode = MainFilterMode;
            }

            CachedMaterial newcm = new CachedMaterial()
            {
                key        = key,
                keyGroup   = TileMapKeyGroup,
                material   = material,
                filterMode = MainFilterMode,
            };

            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #18
0
        private Material GetWindowMaterial(int key, WindowStyle windowStyle)
        {
            // Reverse key (input must be a MainKeyGroup key)
            int archive, record, frame;

            ReverseTextureKey(key, out archive, out record, out frame);

            // Determine new key group based on style
            int   group;
            Color color;
            float intensity;

            switch (windowStyle)
            {
            case WindowStyle.Day:
                group     = DayWindowKeyGroup;
                color     = dfUnity.MaterialReader.DayWindowColor;
                intensity = dfUnity.MaterialReader.DayWindowIntensity;
                break;

            case WindowStyle.Night:
                group     = NightWindowKeyGroup;
                color     = dfUnity.MaterialReader.NightWindowColor;
                intensity = dfUnity.MaterialReader.NightWindowIntensity;
                break;

            case WindowStyle.Fog:
                group     = FogWindowKeyGroup;
                color     = dfUnity.MaterialReader.FogWindowColor;
                intensity = dfUnity.MaterialReader.FogWindowIntensity;
                break;

            case WindowStyle.Custom:
                group     = CustomWindowKeyGroup;
                color     = dfUnity.MaterialReader.CustomWindowColor;
                intensity = dfUnity.MaterialReader.CustomWindowIntensity;
                break;

            default:
                return(GetMaterial(archive, record));       // Just get base material with no processing
            }

            // Make new key based on group
            int newkey = MakeTextureKey((short)archive, (byte)record, (byte)0, group);

            // Check if material is already in cache
            CachedMaterial cm;

            if (materialDict.TryGetValue(newkey, out cm))
            {
                // Return same if settings have not changed since last time
                if (cm.windowColor == color &&
                    cm.windowIntensity == intensity &&
                    cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return(cm.material);
                }
                else
                {
                    materialDict.Remove(newkey);
                }
            }

            // Load texture file and get colour arrays
            textureReader.TextureFile.Load(Path.Combine(dfUnity.Arena2Path, TextureFile.IndexToFileName(archive)), FileUsage.UseMemory, true);
            Color32 alpha = new Color32(0, 0, 0, (byte)(255f / intensity));

            Color32[] diffuseColors, alphaColors;
            DFSize    sz = textureReader.TextureFile.GetWindowColors32(record, color, alpha, out diffuseColors, out alphaColors);

            // Create diffuse texture
            Texture2D diffuse = new Texture2D(sz.Width, sz.Height, TextureFormat.RGBA32, MipMaps);

            diffuse.SetPixels32(diffuseColors);
            diffuse.Apply(true);

            // Create illumin texture
            Texture2D illumin = new Texture2D(sz.Width, sz.Height, TextureFormat.RGBA32, MipMaps);

            illumin.SetPixels32(alphaColors);
            illumin.Apply(true);

            // Create new material with a self-illuminating shader
            Shader   shader   = Shader.Find(DefaultSelfIlluminShaderName);
            Material material = new Material(shader);

            material.name = FormatName(archive, record);

            // Set material textures
            material.SetTexture("_MainTex", diffuse);
            material.SetTexture("_Illum", illumin);
            material.mainTexture.filterMode = MainFilterMode;

            // Cache this window material
            CachedMaterial newcm = new CachedMaterial()
            {
                key             = newkey,
                keyGroup        = group,
                singleRect      = new Rect(0, 0, sz.Width, sz.Height),
                material        = material,
                filterMode      = MainFilterMode,
                isWindow        = true,
                windowColor     = color,
                windowIntensity = intensity,
            };

            materialDict.Add(newkey, newcm);

            return(material);
        }
 /// <summary>
 /// Sets CachedMaterial properties.
 /// existing Material will be updated in cache with cachedMaterialIn.
 /// </summary>
 /// <param name="archive">Archive index.</param>
 /// <param name="record">Record index.</param>
 /// <param name="frame">Frame index.</param>
 /// <param name="cachedMaterialIn">the CachedMaterial used to update the cache.</param>
 /// <returns>True if CachedMaterial was found and updated successfully.</returns>
 public bool SetCachedMaterial(int archive, int record, int frame, CachedMaterial cachedMaterialIn)
 {
     int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);
     if (materialDict.ContainsKey(key))
     {
         materialDict[key] = cachedMaterialIn;
         return true;
     }
     else
     {
         return false;
     }
 }
Exemple #20
0
        /// <summary>
        /// Gets Unity Material from Daggerfall terrain using texture arrays.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <returns>Material or null.</returns>
        public Material GetTerrainTextureArrayMaterial(int archive)
        {
            // Ready check
            if (!IsReady)
            {
                return(null);
            }

            // Return from cache if present
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, TileMapKeyGroup);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = GetMaterialFromCache(key);
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            // Generate texture array
            Texture2DArray textureArrayTerrainTiles              = textureReader.GetTerrainAlbedoTextureArray(archive);
            Texture2DArray textureArrayTerrainTilesNormalMap     = textureReader.GetTerrainNormalMapTextureArray(archive);
            Texture2DArray textureArrayTerrainTilesMetallicGloss = textureReader.GetTerrainMetallicGlossMapTextureArray(archive);

            textureArrayTerrainTiles.filterMode = MainFilterMode;

            Shader   shader   = Shader.Find(_DaggerfallTilemapTextureArrayShaderName);
            Material material = new Material(shader);

            material.name = string.Format("TEXTURE.{0:000} [TilemapTextureArray]", archive);

            material.SetTexture(TileTexArrUniforms.TileTexArr, textureArrayTerrainTiles);
            if (textureArrayTerrainTilesNormalMap != null)
            {
                // if normal map texture array was loaded successfully enable normalmap in shader and set texture
                material.SetTexture(TileTexArrUniforms.TileNormalMapTexArr, textureArrayTerrainTilesNormalMap);
                material.EnableKeyword(KeyWords.NormalMap);
            }
            if (textureArrayTerrainTilesMetallicGloss != null)
            {
                // if metallic gloss map texture array was loaded successfully set texture (should always contain a valid texture array - since it defaults to 1x1 textures)
                material.SetTexture(TileTexArrUniforms.TileMetallicGlossMapTexArr, textureArrayTerrainTilesMetallicGloss);
            }

            CachedMaterial newcm = new CachedMaterial()
            {
                key        = key,
                keyGroup   = TileMapKeyGroup,
                material   = material,
                filterMode = MainFilterMode,
            };

            materialDict.Add(key, newcm);

            return(material);
        }
Exemple #21
0
        /// <summary>
        /// Sets CachedMaterial properties for a billboard with custom material.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        public void SetCachedMaterialCustomBillboard(int archive, int record, int frame, CachedMaterial cachedMaterialIn)
        {
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame, CustomBillboardKeyGroup);

            cachedMaterialIn.key      = key;
            cachedMaterialIn.keyGroup = CustomBillboardKeyGroup;
            materialDict.Add(key, cachedMaterialIn);
        }
        /// <summary>
        /// Gets Unity Mesh from Daggerfall model.
        /// </summary>
        /// <param name="dfUnity">DaggerfallUnity singleon for loading content.</param>
        /// <param name="modelID">Daggerfall model ID to load..</param>
        /// <param name="cachedMaterialsOut">Array of cached materials in order of submesh.</param>
        /// <param name="textureKeysOut">Array of original texture keys in order of submesh.</param>
        /// <param name="hasAnimationsOut">True if one or more materials have animations.</param>
        /// <param name="solveTangents">Solve tangents for this mesh.</param>
        /// <param name="lightmapUVs">Add secondary lightmap UVs to this mesh.</param>
        /// <returns>Mesh object or null.</returns>
        public Mesh GetMesh(
            DaggerfallUnity dfUnity,
            uint modelID,
            out CachedMaterial[] cachedMaterialsOut,
            out int[] textureKeysOut,
            out bool hasAnimationsOut,
            bool solveTangents = false,
            bool lightmapUVs = false)
        {
            cachedMaterialsOut = null;
            hasAnimationsOut = false;
            textureKeysOut = null;

            // Ready check
            if (!IsReady)
                return null;

            // Get model data
            ModelData model;
            if (!GetModelData(modelID, out model))
            {
                DaggerfallUnity.LogMessage(string.Format("Unknown ModelID {0}.", modelID.ToString()), true);
                return null;
            }

            // Load materials
            cachedMaterialsOut = new CachedMaterial[model.SubMeshes.Length];
            textureKeysOut = new int[model.SubMeshes.Length];
            for (int i = 0; i < model.SubMeshes.Length; i++)
            {
                int archive = model.DFMesh.SubMeshes[i].TextureArchive;
                int record = model.DFMesh.SubMeshes[i].TextureRecord;
                textureKeysOut[i] = MaterialReader.MakeTextureKey((short)archive, (byte)record, (byte)0);

                // Add material to array
                CachedMaterial cachedMaterial;
                dfUnity.MaterialReader.GetCachedMaterial(archive, record, 0, out cachedMaterial);
                cachedMaterialsOut[i] = cachedMaterial;

                // Set animation flag
                if (cachedMaterial.singleFrameCount > 1 && !hasAnimationsOut)
                    hasAnimationsOut = true;
            }

            // Create mesh
            Mesh mesh = new Mesh();
            mesh.name = modelID.ToString();
            mesh.vertices = model.Vertices;
            mesh.normals = model.Normals;
            mesh.uv = model.UVs;
            mesh.subMeshCount = model.SubMeshes.Length;

            // Set submesh triangles
            for (int s = 0; s < mesh.subMeshCount; s++)
            {
                var sub = model.SubMeshes[s];
                int[] triangles = new int[sub.PrimitiveCount * 3];
                for (int t = 0; t < sub.PrimitiveCount * 3; t++)
                {
                    triangles[t] = model.Indices[sub.StartIndex + t];
                }
                mesh.SetTriangles(triangles, s);
            }

            // Finalise mesh
            if (solveTangents) TangentSolver(mesh);
            if (lightmapUVs) AddLightmapUVs(mesh);
            mesh.RecalculateBounds();
            mesh.Optimize();

            return mesh;
        }
        /// <summary>
        /// Gets Unity Material atlas from Daggerfall texture archive.
        /// </summary>
        /// <param name="archive">Archive index to create atlas from.</param>
        /// <param name="alphaIndex">Index to receive transparent alpha.</param>
        /// <param name="rectsOut">Array of rects, one for each record sub-texture and frame.</param>
        /// <param name="padding">Number of pixels each sub-texture.</param>
        /// <param name="maxAtlasSize">Max size of atlas.</param>
        /// <param name="rectsOut">Array of rects, one for each record sub-texture and frame.</param>
        /// <param name="indicesOut">Array of record indices into rect array, accounting for animation frames.</param>
        /// <param name="border">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="shrinkUVs">Number of pixels to shrink UV rect.</param>
        /// <param name="copyToOppositeBorder">Copy texture edges to opposite border. Requires border, will overwrite dilate.</param>
        /// <param name="shader">Shader for material. If null, DefaultShaderName will be applied.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterialAtlas(
            int archive,
            int alphaIndex,
            int padding,
            int maxAtlasSize,
            out Rect[] rectsOut,
            out RecordIndex[] indicesOut,
            int border = 0,
            bool dilate = false,
            int shrinkUVs = 0,
            bool copyToOppositeBorder = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectsOut = null;
                indicesOut = null;
                return null;
            }

            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, AtlasKeyGroup);
            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    rectsOut = cm.atlasRects;
                    indicesOut = cm.atlasIndices;
                    return cm.material;
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            // Create material
            Material material = CreateStandardMaterial();

            // Create settings
            GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, 0, 0, alphaIndex, border, dilate);
            settings.createNormalMap = GenerateNormals;
            settings.autoEmission = true;
            settings.atlasShrinkUVs = shrinkUVs;
            settings.atlasPadding = padding;
            settings.atlasMaxSize = maxAtlasSize;
            settings.copyToOppositeBorder = copyToOppositeBorder;

            // Setup material
            material.name = string.Format("TEXTURE.{0:000} [Atlas]", archive);
            GetTextureResults results = textureReader.GetTexture2DAtlas(settings, AlphaTextureFormat, NonAlphaTextureFormat);
            material.mainTexture = results.albedoMap;
            material.mainTexture.filterMode = MainFilterMode;

            // Setup normal map
            if (GenerateNormals && results.normalMap != null)
            {
                results.normalMap.filterMode = MainFilterMode;
                material.SetTexture("_BumpMap", results.normalMap);
                material.EnableKeyword("_NORMALMAP");
            }

            // Setup emission map
            if (results.isEmissive && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", Color.white);
                material.EnableKeyword("_EMISSION");
            }

            // TEMP: Bridging between legacy material out params and GetTextureResults for now
            Vector2[] sizesOut, scalesOut, offsetsOut;
            sizesOut = results.atlasSizes.ToArray();
            scalesOut = results.atlasScales.ToArray();
            offsetsOut = results.atlasOffsets.ToArray();
            rectsOut = results.atlasRects.ToArray();
            indicesOut = results.atlasIndices.ToArray();

            // Setup cached material
            CachedMaterial newcm = new CachedMaterial();
            newcm.key = key;
            newcm.keyGroup = AtlasKeyGroup;
            newcm.atlasRects = rectsOut;
            newcm.atlasIndices = indicesOut;
            newcm.material = material;
            newcm.filterMode = MainFilterMode;
            newcm.recordSizes = sizesOut;
            newcm.recordScales = scalesOut;
            newcm.recordOffsets = offsetsOut;
            newcm.atlasFrameCounts = results.atlasFrameCounts.ToArray();
            materialDict.Add(key, newcm);

            return material;
        }
        /// <summary>
        /// Gets CachedMaterial properties for an atlased material.
        /// Atlas material will not be loaded automatically if not found in cache.
        /// </summary>
        /// <param name="archive">Atlas archive index.</param>
        /// <param name="cachedMaterialOut">CachedMaterial out</param>
        /// <returns>True if CachedMaterial found.</returns>
        public bool GetCachedMaterialAtlas(int archive, out CachedMaterial cachedMaterialOut)
        {
            int key = MakeTextureKey((short)archive, (byte)0, (byte)0, AtlasKeyGroup);
            if (materialDict.ContainsKey(key))
            {
                cachedMaterialOut = materialDict[key];
                return true;
            }

            cachedMaterialOut = new CachedMaterial();
            return false;
        }
Exemple #25
0
        /// <summary>
        /// Gets Unity Material 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="rectOut">Receives UV rect for texture inside border.</param>
        /// <param name="border">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="shader">Shader for material. If null, DefaultShaderName will be applied.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterial(
            int archive,
            int record,
            int frame,
            int alphaIndex,
            out Rect rectOut,
            int border    = 0,
            bool dilate   = false,
            Shader shader = null)
        {
            // Ready check
            if (!IsReady)
            {
                rectOut = new Rect();
                return(null);
            }

            // HACK: Override shader for unlit textures
            // TODO: Find a better way to do this
            if (archive == 356 && (record == 0 || record == 2 || record == 3) ||
                archive == 87 && record == 0)
            {
                // Only override if not specified
                if (shader == null)
                {
                    shader = Shader.Find(dfUnity.MaterialReader.DefaultUnlitTextureShaderName);
                }
            }

            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                if (cm.filterMode == MainFilterMode)
                {
                    // Properties are the same
                    rectOut = cm.singleRect;
                    return(cm.material);
                }
                else
                {
                    // Properties don't match, remove material and reload
                    materialDict.Remove(key);
                }
            }

            if (shader == null)
            {
                shader = Shader.Find(DefaultShaderName);
            }

            Material material = new Material(shader);

            material.name = FormatName(archive, record);
            Texture2D texture = textureReader.GetTexture2D(archive, record, frame, alphaIndex, out rectOut, border, dilate);

            material.mainTexture            = texture;
            material.mainTexture.filterMode = MainFilterMode;

            DFSize size   = textureReader.TextureFile.GetSize(record);
            DFSize scale  = textureReader.TextureFile.GetScale(record);
            DFSize offset = textureReader.TextureFile.GetOffset(record);

            Vector2[] recordSizes = new Vector2[1] {
                new Vector2(size.Width, size.Height)
            };
            Vector2[] recordScales = new Vector2[1] {
                new Vector2(scale.Width, scale.Height)
            };
            Vector2[] recordOffsets = new Vector2[1] {
                new Vector2(offset.Width, offset.Height)
            };
            CachedMaterial newcm = new CachedMaterial()
            {
                key              = key,
                keyGroup         = 0,
                singleRect       = rectOut,
                material         = material,
                filterMode       = MainFilterMode,
                isWindow         = ClimateSwaps.IsExteriorWindow(archive, record),
                recordSizes      = recordSizes,
                recordScales     = recordScales,
                recordOffsets    = recordOffsets,
                recordFrameCount = textureReader.TextureFile.GetFrameCount(record),
            };

            materialDict.Add(key, newcm);

            return(material);
        }
        /// <summary>
        /// Gets Unity Material 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="rectOut">Receives UV rect for texture inside border.</param>
        /// <param name="borderSize">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterial(
            int archive,
            int record,
            int frame,
            int alphaIndex,
            out Rect rectOut,
            int borderSize = 0,
            bool dilate = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectOut = new Rect();
                return null;
            }

            // Try to retrieve from cache
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);
            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                rectOut = cm.singleRect;
                return cm.material;
            }

            // Create new texture settings
            GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, record, frame, alphaIndex, borderSize, dilate);
            settings.autoEmissionForWindows = true;
            settings.sharpen = Sharpen;
            if (GenerateNormals)
            {
                settings.createNormalMap = true;
                settings.normalStrength = NormalTextureStrength;
            }

            // Set emissive for self-illuminated textures
            if (textureReader.IsEmissive(archive, record))
            {
                settings.createEmissionMap = true;
                settings.emissionIndex = -1;
            }

            // Get texture
            GetTextureResults results = textureReader.GetTexture2D(settings, AlphaTextureFormat, NonAlphaTextureFormat);
            rectOut = results.singleRect;

            // Setup material
            Material material = CreateStandardMaterial();
            material.name = FormatName(archive, record);
            material.mainTexture = results.albedoMap;
            material.mainTexture.filterMode = MainFilterMode;

            // Setup normal map
            if (GenerateNormals && results.normalMap != null)
            {
                results.normalMap.filterMode = MainFilterMode;
                material.SetTexture("_BumpMap", results.normalMap);
                material.EnableKeyword("_NORMALMAP");
            }

            // Setup emission map
            if (results.isEmissive && !results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", Color.white);
                material.EnableKeyword("_EMISSION");
            }
            else if (results.isEmissive && results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", DayWindowColor * DayWindowIntensity);
                material.EnableKeyword("_EMISSION");
            }

            // Setup cached material
            DFSize size = results.textureFile.GetSize(record);
            DFSize scale = results.textureFile.GetScale(record);
            DFSize offset = results.textureFile.GetOffset(record);
            Vector2[] recordSizes = new Vector2[1] { new Vector2(size.Width, size.Height) };
            Vector2[] recordScales = new Vector2[1] { new Vector2(scale.Width, scale.Height) };
            Vector2[] recordOffsets = new Vector2[1] { new Vector2(offset.Width, offset.Height) };
            CachedMaterial newcm = new CachedMaterial()
            {
                key = key,
                keyGroup = 0,
                albedoMap = results.albedoMap,
                normalMap = results.normalMap,
                emissionMap = results.emissionMap,
                singleRect = rectOut,
                material = material,
                filterMode = MainFilterMode,
                isWindow = results.isWindow,
                recordSizes = recordSizes,
                recordScales = recordScales,
                recordOffsets = recordOffsets,
                singleFrameCount = results.textureFile.GetFrameCount(record),
            };
            materialDict.Add(key, newcm);

            return material;
        }
        /// <summary>
        /// Gets Unity Mesh from previously combined model data.
        /// </summary>
        /// <param name="dfUnity">DaggerfallUnity singleon for loading content.</param>
        /// <param name="combiner">ModelCombiner to build from.</param>
        /// <param name="cachedMaterialsOut">Array of cached materials in order of submesh.</param>
        /// <param name="textureKeysOut">Array of original texture keys in order of submesh.</param>
        /// <param name="hasAnimationsOut">True if one or more materials have animations.</param>
        /// <param name="solveTangents">Solve tangents for this mesh.</param>
        /// <param name="lightmapUVs">Add secondary lightmap UVs to this mesh.</param>
        /// <returns>Mesh object or null.</returns>
        public Mesh GetCombinedMesh(
            DaggerfallUnity dfUnity,
            ModelCombiner combiner,
            out CachedMaterial[] cachedMaterialsOut,
            out int[] textureKeysOut,
            out bool hasAnimationsOut,
            bool solveTangents = false,
            bool lightmapUVs = false)
        {
            cachedMaterialsOut = null;
            hasAnimationsOut = false;
            textureKeysOut = null;

            // Ready check
            if (!IsReady)
                return null;

            // Get combined model
            ModelCombiner.CombinedModel combinedModel;
            if (!combiner.GetCombinedModel(out combinedModel))
                return null;

            // Load materials
            cachedMaterialsOut = new CachedMaterial[combinedModel.SubMeshes.Length];
            textureKeysOut = new int[combinedModel.SubMeshes.Length];
            for (int i = 0; i < combinedModel.SubMeshes.Length; i++)
            {
                int archive = combinedModel.SubMeshes[i].TextureArchive;
                int record = combinedModel.SubMeshes[i].TextureRecord;
                textureKeysOut[i] = MaterialReader.MakeTextureKey((short)archive, (byte)record, (byte)0);

                // Add material to array
                CachedMaterial cachedMaterial;
                dfUnity.MaterialReader.GetCachedMaterial(archive, record, 0, out cachedMaterial);
                cachedMaterialsOut[i] = cachedMaterial;

                // Set animation flag
                if (cachedMaterial.singleFrameCount > 1 && !hasAnimationsOut)
                    hasAnimationsOut = true;
            }

            // Create mesh
            Mesh mesh = new Mesh();
            mesh.name = "CombinedMesh";
            mesh.vertices = combinedModel.Vertices;
            mesh.normals = combinedModel.Normals;
            mesh.uv = combinedModel.UVs;
            mesh.subMeshCount = combinedModel.SubMeshes.Length;

            // Set submesh triangles
            for (int s = 0; s < mesh.subMeshCount; s++)
            {
                var sub = combinedModel.SubMeshes[s];
                int[] triangles = new int[sub.PrimitiveCount * 3];
                for (int t = 0; t < sub.PrimitiveCount * 3; t++)
                {
                    triangles[t] = combinedModel.Indices[sub.StartIndex + t];
                }
                mesh.SetTriangles(triangles, s);
            }

            // Finalise mesh
            if (solveTangents) TangentSolver(mesh);
            if (lightmapUVs) AddLightmapUVs(mesh);
            mesh.RecalculateBounds();
            mesh.Optimize();

            return mesh;
        }