Exemplo n.º 1
0
        private StaticTextureSource LoadStaticSource(string name)
        {
            string dir = Path.Combine(@"Resources\Textures\Source\Static", name.Replace(".", @"\"));

            if (!Directory.Exists(dir))
            {
                throw new IOException(string.Format("Missing texture pack source folder ({0})", name));
            }

            string png = Path.Combine(dir, "Segments.png");

            if (!File.Exists(png))
            {
                throw new IOException(string.Format("Missing texture pack source PNG ({0})", png));
            }

            string mapping = Path.Combine(dir, "Data.json");

            if (!File.Exists(mapping))
            {
                throw new IOException(string.Format("Missing texture pack source JSON ({0})", mapping));
            }

            StaticTextureSource source = JsonConvert.DeserializeObject <StaticTextureSource>(File.ReadAllText(mapping));

            source.PNGPath = png;
            return(source);
        }
Exemplo n.º 2
0
        private void GenerateSpriteSequenceTargets(StaticTextureSource source)
        {
            if (!source.HasVariants)
            {
                throw new ArgumentException(string.Format("SpriteSequence {0} cannot be dynamically mapped without at least one source rectangle.", source.SpriteSequence));
            }

            int i = _level.SpriteSequences.ToList().FindIndex(s => s.SpriteID == (int)source.SpriteSequence);

            if (i == -1)
            {
                return;
            }

            TRSpriteSequence sequence = _level.SpriteSequences[i];

            StaticMapping[source] = new List <StaticTextureTarget>();

            // An assumption is made here that each variant in the source will have the same number
            // of rectangles. We only want to define targets for the number of source rectangles, rather
            // than the total number of sprites.
            int numTargets = source.VariantMap[source.Variants[0]].Count;

            for (int j = 0; j < numTargets; j++)
            {
                TRSpriteTexture sprite = _level.SpriteTextures[sequence.Offset + j];
                StaticMapping[source].Add(new StaticTextureTarget
                {
                    Segment = j,
                    Tile    = sprite.Atlas,
                    X       = sprite.X,
                    Y       = sprite.Y
                });
            }
        }
Exemplo n.º 3
0
 public TextureGrouping GetGrouping(StaticTextureSource source)
 {
     foreach (TextureGrouping grouping in Grouping)
     {
         if (grouping.Leader.Equals(source))
         {
             return(grouping);
         }
     }
     return(null);
 }
Exemplo n.º 4
0
        public static TextureLevelMapping Get(TR2Level level, string mappingFilePrefix, TextureDatabase database, Dictionary <StaticTextureSource, List <StaticTextureTarget> > predefinedMapping = null, List <TR2Entities> entitiesToIgnore = null)
        {
            string mapFile = Path.Combine(@"Resources\Textures\Mapping\", mappingFilePrefix + "-Textures.json");

            if (!File.Exists(mapFile))
            {
                return(null);
            }

            Dictionary <DynamicTextureSource, DynamicTextureTarget>       dynamicMapping = new Dictionary <DynamicTextureSource, DynamicTextureTarget>();
            Dictionary <StaticTextureSource, List <StaticTextureTarget> > staticMapping  = new Dictionary <StaticTextureSource, List <StaticTextureTarget> >();
            Dictionary <StaticTextureSource, Dictionary <int, List <LandmarkTextureTarget> > > landmarkMapping = new Dictionary <StaticTextureSource, Dictionary <int, List <LandmarkTextureTarget> > >();
            Color skyBoxColour = _defaultSkyBox;

            Dictionary <string, object> rootMapping = JsonConvert.DeserializeObject <Dictionary <string, object> >(File.ReadAllText(mapFile));

            // Read the dynamic mapping - this holds object and sprite texture indices for the level to which we will apply an HSB operation
            if (rootMapping.ContainsKey("Dynamic"))
            {
                SortedDictionary <string, Dictionary <string, object> > mapping = JsonConvert.DeserializeObject <SortedDictionary <string, Dictionary <string, object> > >(rootMapping["Dynamic"].ToString());
                foreach (string sourceName in mapping.Keys)
                {
                    DynamicTextureSource source = database.GetDynamicSource(sourceName);
                    DynamicTextureTarget target = new DynamicTextureTarget
                    {
                        DefaultTileTargets = JsonConvert.DeserializeObject <Dictionary <int, List <Rectangle> > >(mapping[sourceName]["Default"].ToString())
                    };

                    if (mapping[sourceName].ContainsKey("Optional"))
                    {
                        target.OptionalTileTargets = JsonConvert.DeserializeObject <Dictionary <TextureCategory, Dictionary <int, List <Rectangle> > > >(mapping[sourceName]["Optional"].ToString());
                    }

                    dynamicMapping[source] = target;
                }
            }

            // The static mapping contains basic texture segment source to tile target locations
            if (rootMapping.ContainsKey("Static"))
            {
                SortedDictionary <string, object> mapping = JsonConvert.DeserializeObject <SortedDictionary <string, object> >(rootMapping["Static"].ToString());
                foreach (string sourceName in mapping.Keys)
                {
                    staticMapping[database.GetStaticSource(sourceName)] = JsonConvert.DeserializeObject <List <StaticTextureTarget> >(mapping[sourceName].ToString());
                }
            }

            // Landmark mapping links static sources to room number -> rectangle/triangle indices
            if (rootMapping.ContainsKey("Landmarks"))
            {
                Dictionary <string, Dictionary <int, List <LandmarkTextureTarget> > > mapping = JsonConvert.DeserializeObject <Dictionary <string, Dictionary <int, List <LandmarkTextureTarget> > > >(rootMapping["Landmarks"].ToString());
                foreach (string sourceName in mapping.Keys)
                {
                    landmarkMapping[database.GetStaticSource(sourceName)] = mapping[sourceName];
                }
            }

            // If a level has had textures removed externally, but the JSON file has static
            // imports ready for it, we need to make sure they are ignored.
            if (entitiesToIgnore != null)
            {
                List <StaticTextureSource> sources = new List <StaticTextureSource>(staticMapping.Keys);
                for (int i = 0; i < sources.Count; i++)
                {
                    StaticTextureSource source = sources[i];
                    if (source.TextureEntities != null)
                    {
                        foreach (TR2Entities entity in source.TextureEntities)
                        {
                            if (entitiesToIgnore.Contains(entity))
                            {
                                staticMapping.Remove(source);
                                break;
                            }
                        }
                    }
                }
            }

            // Allows for dynamic mapping to be targeted at levels e.g. when importing non-native
            // models that are otherwise undefined in the default level JSON data.
            // This should be done after removing ignored entity textures, for the likes of when
            // Lara is being replaced.
            if (predefinedMapping != null)
            {
                foreach (StaticTextureSource source in predefinedMapping.Keys)
                {
                    staticMapping[source] = predefinedMapping[source];
                }
            }

            // Add global sources, unless they are already defined. These tend to be sprite sequences
            // so they will be mapped per GenerateSpriteSequenceTargets, but there is also scope to
            // define global targets if relevant.
            foreach (StaticTextureSource source in database.GlobalGrouping.Sources.Keys)
            {
                if (!staticMapping.ContainsKey(source))
                {
                    staticMapping[source] = new List <StaticTextureTarget>(database.GlobalGrouping.Sources[source]);
                }
            }

            // Apply grouping to what has been selected as source elements
            List <TextureGrouping> staticGrouping = database.GlobalGrouping.GetGrouping(staticMapping.Keys);

            return(new TextureLevelMapping(level)
            {
                DynamicMapping = dynamicMapping,
                StaticMapping = staticMapping,
                StaticGrouping = staticGrouping,
                LandmarkMapping = landmarkMapping,
                DefaultSkyBox = skyBoxColour
            });
        }
Exemplo n.º 5
0
        public void RedrawStaticTargets(StaticTextureSource source, string variant, Dictionary <TextureCategory, bool> options)
        {
            if (source.Categories != null)
            {
                // Exclude it if any of its categories are in the options and switched off
                foreach (TextureCategory category in source.Categories)
                {
                    if (options.ContainsKey(category) && !options[category])
                    {
                        return;
                    }
                }
            }

            // For sprite sequence sources, the targets are mapped dynamically.
            if (source.IsSpriteSequence && (!StaticMapping.ContainsKey(source) || StaticMapping[source].Count == 0))
            {
                GenerateSpriteSequenceTargets(source);
            }

            // This can happen if we have a source grouped for this level,
            // but the source is actually only in place on certain conditions
            // - an example is the flame in Venice, which is only added if
            // the Flamethrower has been imported.
            if (!StaticMapping.ContainsKey(source))
            {
                return;
            }

            List <Rectangle> segments = source.VariantMap[variant];

            foreach (StaticTextureTarget target in StaticMapping[source])
            {
                if (target.Segment < 0 || target.Segment >= segments.Count)
                {
                    throw new IndexOutOfRangeException(string.Format("Segment {0} is invalid for texture source {1}.", target.Segment, source.PNGPath));
                }

                GetBitmapGraphics(target.Tile).ImportSegment(source, target, segments[target.Segment]);
            }

            if (source.EntityColourMap != null)
            {
                foreach (TR2Entities entity in source.EntityColourMap.Keys)
                {
                    TRMesh[]   meshes        = TR2LevelUtilities.GetModelMeshes(_level, entity);
                    ISet <int> colourIndices = new HashSet <int>();
                    foreach (TRMesh mesh in meshes)
                    {
                        foreach (TRFace4 t in mesh.ColouredRectangles)
                        {
                            colourIndices.Add(BitConverter.GetBytes(t.Texture)[1]);
                        }
                        foreach (TRFace3 t in mesh.ColouredTriangles)
                        {
                            colourIndices.Add(BitConverter.GetBytes(t.Texture)[1]);
                        }
                    }

                    Dictionary <int, int> remapIndices = new Dictionary <int, int>();
                    foreach (Color targetColour in source.EntityColourMap[entity].Keys)
                    {
                        int matchedIndex = -1;
                        foreach (int currentIndex in colourIndices)
                        {
                            TRColour4 currentColour = _level.Palette16[currentIndex];
                            if (currentColour.Red == targetColour.R && currentColour.Green == targetColour.G && currentColour.Blue == targetColour.B)
                            {
                                matchedIndex = currentIndex;
                            }
                        }

                        if (matchedIndex == -1)
                        {
                            continue;
                        }

                        // Extract the colour from the top-left of the rectangle specified in the source, and import that into the level
                        int sourceRectangle = source.EntityColourMap[entity][targetColour];
                        int newColourIndex  = P16Importer.Import(_level, source.Bitmap.GetPixel(segments[sourceRectangle].X, segments[sourceRectangle].Y));
                        remapIndices.Add(matchedIndex, newColourIndex);
                    }

                    // Remap the affected mesh textures to the newly inserted colours
                    foreach (TRMesh mesh in meshes)
                    {
                        foreach (TRFace4 t in mesh.ColouredRectangles)
                        {
                            t.Texture = ConvertMeshTexture(t.Texture, remapIndices);
                        }
                        foreach (TRFace3 t in mesh.ColouredTriangles)
                        {
                            t.Texture = ConvertMeshTexture(t.Texture, remapIndices);
                        }
                    }
                }

                // Reset the palette tracking
                P16Importer.ResetPaletteTracking(_level);
            }
        }