private Dictionary <int, TRColour4> GetSkyBoxColours() { Dictionary <int, TRColour4> colours = new Dictionary <int, TRColour4>(); TRMesh[] meshes = TR2LevelUtilities.GetModelMeshes(_level, TR2Entities.Skybox_H); if (meshes != null) { ISet <int> colourIndices = new SortedSet <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]); } } foreach (int i in colourIndices) { colours.Add(i, _level.Palette16[i]); } } return(colours); }
public override void Import() { // Copy the MeshTreeNodes and Meshes into the level, making a note of the first // inserted index for each - this is used to update the Model to point to the // correct starting positions. for (int i = 0; i < Definition.MeshTrees.Length; i++) { TRMeshTreeNode tree = Definition.MeshTrees[i]; int insertedIndex = TR2LevelUtilities.InsertMeshTreeNode(Level, tree); if (i == 0) { Definition.Model.MeshTree = 4 * (uint)insertedIndex; } } for (int i = 0; i < Definition.Meshes.Length; i++) { TRMesh mesh = Definition.Meshes[i]; int insertedIndex = TR2LevelUtilities.InsertMesh(Level, mesh); if (i == 0) { Definition.Model.StartingMesh = (ushort)insertedIndex; } } }
private void AdjustOutfit(TR2CombinedLevel level, TR2Entities lara) { if (level.Is(LevelNames.HOME) && lara != TR2Entities.LaraHome) { // This ensures that Lara's hips match the new outfit for the starting animation and shower cutscene, // otherwise the dressing gown hips are rendered, but the mesh is completely different for this, plus // its textures will have been removed. TRMesh laraMiscMesh = TR2LevelUtilities.GetModelFirstMesh(level.Data, TR2Entities.LaraMiscAnim_H); TRMesh laraHipsMesh = TR2LevelUtilities.GetModelFirstMesh(level.Data, TR2Entities.Lara); TR2LevelUtilities.DuplicateMesh(level.Data, laraMiscMesh, laraHipsMesh); } }
public Dictionary <TexturedTile, List <TexturedTileSegment> > GetModelSegments(TR2Entities modelEntity) { Dictionary <TexturedTile, List <TexturedTileSegment> > segmentMap = new Dictionary <TexturedTile, List <TexturedTileSegment> >(); TRMesh[] meshes = TR2LevelUtilities.GetModelMeshes(Level, modelEntity); if (meshes != null) { IEnumerable <int> indices = GetMeshTextureIndices(meshes); foreach (TexturedTile tile in _tiles) { List <TexturedTileSegment> segments = tile.GetObjectTextureIndexSegments(indices); if (segments.Count > 0) { segmentMap[tile] = segments; } } } return(segmentMap); }
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); } }
private void CutHair(TR2CombinedLevel level) { // Every level has a 64x64 transparent gunflare texture so rather than // importing something else, we'll just try to find that texture and // point Lara's braid to it, so making it invisible. TRMesh[] gunflareMeshes = TR2LevelUtilities.GetModelMeshes(level.Data, TR2Entities.Gunflare_H); if (gunflareMeshes == null) { return; } ISet <int> textureIndices = new HashSet <int>(); foreach (TRMesh mesh in gunflareMeshes) { foreach (TRFace4 r in mesh.TexturedRectangles) { textureIndices.Add(r.Texture); } foreach (TRFace3 t in mesh.TexturedTriangles) { textureIndices.Add(t.Texture); } } IndexedTRObjectTexture transparentTexture = null; foreach (int index in textureIndices) { transparentTexture = new IndexedTRObjectTexture { Index = index, Texture = level.Data.ObjectTextures[index] }; Rectangle rect = transparentTexture.Bounds; if (rect.Width == 64 && rect.Height == 64) { break; } else { transparentTexture = null; } } // Did we find it? if (transparentTexture == null) { return; } // Erase the braid foreach (TRMesh mesh in TR2LevelUtilities.GetModelMeshes(level.Data, TR2Entities.LaraPonytail_H)) { foreach (TRFace4 r in mesh.TexturedRectangles) { r.Texture = (ushort)transparentTexture.Index; } foreach (TRFace3 t in mesh.TexturedTriangles) { t.Texture = (ushort)transparentTexture.Index; } } }
public override void Export() { Definition.MeshTrees = TR2LevelUtilities.GetModelMeshTrees(Level, Definition.Model); Definition.Meshes = TR2LevelUtilities.GetModelMeshes(Level, Definition.Model); }