public override void SetSubject(Chunk xiChunk) { if (!(xiChunk is SteeringImageChunk)) { mChunk = null; } else { mChunk = (SteeringImageChunk)xiChunk; } if (mLastSubject == mChunk) { return; } if (mChunk == null) { mMainForm.SteeringEditPictureBox.Image = null; } else { byte lType = mChunk.GetPixelType(mX, mY); mMainForm.SteeringTypeLabel.Text = GetSteeringDirectionName(lType); SetUpDropDown(lType); RefreshView(); } mLastSubject = xiChunk; }
public override void SetSubject(Chunk xiChunk) { if (!(xiChunk is IImageProvider)) xiChunk = null; if (mLastSubject == xiChunk) return; if (xiChunk == null) { mMainForm.ImgPictureBox.Image = null; } else { Image im = ((IImageProvider)xiChunk).ToImage(); mMainForm.ImgPictureBox.Image = im; if (im != null) { int scaleFactor = Math.Max(1, 128/Math.Max(Math.Max(im.Width, im.Height), 1)); if (scaleFactor != 1) { mMainForm.ImgPictureBox.SizeMode = PictureBoxSizeMode.StretchImage; mMainForm.ImgPictureBox.Width = im.Width*scaleFactor; mMainForm.ImgPictureBox.Height = im.Height*scaleFactor; } else { mMainForm.ImgPictureBox.SizeMode = PictureBoxSizeMode.AutoSize; } } } mLastSubject = xiChunk; }
public override void SetSubject(Chunk xiChunk) { if (mSubject == xiChunk) return; if (xiChunk == null || !CanViewChunk(xiChunk)) { mMainForm.XMLTextBox.Text = ""; } else { XmlSerializer xs = new XmlSerializer(xiChunk.GetType()); StringWriter sw = new StringWriter(); xs.Serialize(sw, xiChunk); mMainForm.XMLTextBox.Text = sw.ToString(); } mSubject = xiChunk; }
public override void SetSubject(Chunk xiChunk) { if (mSubject == xiChunk || xiChunk == null) return; if (!(xiChunk is CameraPosChunk)) { throw new InvalidOperationException(string.Format("Tried to view chunk of type {0} in CameraViewer", xiChunk.GetType())); } mMainForm.CameraRenderingSurface.Visible = true; mSubject = (CameraPosChunk)xiChunk; SetDirection(mSubject.Direction); mMainForm.TextDistance.Text = mSubject.Distance.ToString(); mMainForm.TextElevation.Text = mSubject.Elevation.ToString(); InitialiseThreeDeeView(); }
// all chunk types can be viewed except for VersionLists and Versions... public override bool CanViewChunk(Chunk xiChunk) { return !(xiChunk is VersionList || xiChunk is MMEd.Chunks.Version); }
/// <summary> /// Modifies this Chunk, replacing the given child with /// the given replacement. /// </summary> /// <param name="xiFrom"> /// Must be a child Chunk of this one /// </param> public virtual void ReplaceChild(Chunk xiFrom, Chunk xiTo) { throw new Exception("This operation has not been implemented or is not permitted for this chunk type."); }
public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is IEntityProvider; }
private void SaveInternal(eSaveMode xiSaveMode, string xiFilename) { if (RootChunk == null) { MessageBox.Show("Can't save: no file is open"); return; } string lExceptionWhen = "saving file"; try { long lPreviousSize = -1; if (xiSaveMode == eSaveMode.Binary && File.Exists(xiFilename)) { lPreviousSize = new FileInfo(xiFilename).Length; } using (FileStream fs = File.Create(xiFilename)) { lExceptionWhen = "serialising the file"; if (xiSaveMode == eSaveMode.Binary) { if (RootChunk is VersionList) { CurrentLevel.Serialise(fs); } else { RootChunk.Serialise(fs); } } else if (xiSaveMode == eSaveMode.Xml) { XmlSerializer xs = new XmlSerializer(typeof(Chunk)); if (RootChunk is VersionList) { xs.Serialize(fs, CurrentLevel); } else { xs.Serialize(fs, RootChunk); } } else if (xiSaveMode == eSaveMode.Mmv) { if (RootChunk is VersionList) { VersionList lVersionList = (VersionList)RootChunk; lVersionList.AddLevel(CurrentLevel); RecursiveAddChunkNode(ChunkTreeView.Nodes[0].Nodes, 1, lVersionList.GetLastVersion()); } else if (RootChunk is Level) { VersionList lVersionList = new VersionList( (Level)RootChunk, Path.GetFileNameWithoutExtension(xiFilename), null); RootChunk = lVersionList; } RootChunk.Serialise(fs); } } if (lPreviousSize != -1 && lPreviousSize != new FileInfo(xiFilename).Length) { MessageBox.Show("WARNING: The size of your level has changed. Please check it's not too large, and check MMEd for bugs that have allowed the size to change.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } catch (Exception err) { Trace.WriteLine(err); MessageBox.Show(string.Format("Exception occurred while {0}: {1}", lExceptionWhen, err.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } mLocalSettings.LastSavedFile = xiFilename; mLocalSettings.LastSavedMode = xiSaveMode; mCurrentFile = xiFilename; mCurrentFileMode = xiSaveMode; }
private void newToolStripMenuItem_Click(object sender, EventArgs e) { NewForm lForm = new NewForm(this); if (lForm.ShowDialog() == DialogResult.OK) { //===================================================================== // Load the file from the CD image //===================================================================== CDImage lCDImage = new CDImage(new FileInfo(lForm.CDImageTextBox.Text)); MMCD.Course lCourse = (MMCD.Course)lForm.CourseDropDown.SelectedItem; byte[] lLevelBinary = lCDImage.Extract(lCourse.CDOffset, lCourse.CDLength); MemoryStream lLevelStream = new MemoryStream(lLevelBinary); Level lNewLevel = new Level(lLevelStream); //===================================================================== // Check that the whole file has been read //===================================================================== if (lLevelStream.Length != lLevelStream.Position) { throw new DeserialisationException(string.Format("Deserialisation terminated early at byte {0} of {1}", lLevelStream.Position, lLevelStream.Length)); } //===================================================================== // Create a new VersionList based on this level, and set it up //===================================================================== VersionList lVersionList = new VersionList(lNewLevel, lCourse.CourseName, lCourse.FileName); RootChunk = lVersionList; mCurrentFile = null; } }
public override void SetSubject(Chunk xiChunk) { if (!CanViewChunk(xiChunk)) xiChunk = null; if (mSubject == xiChunk && mMainForm.VRAMPictureBox.Image != null) return; mSubject = xiChunk; mOptionsMenu.Visible = (mSubject != null); if (xiChunk == null) { //don't bother freeing the image, as it'll just cause memory churn return; } else { Bitmap lNewImage; if (SelectedPage == -1) { lNewImage = new Bitmap(16 * TEX_PAGE_WIDTH, 2 * TEX_PAGE_HEIGHT); Graphics g = Graphics.FromImage(lNewImage); g.Clear(Color.Black); AddChunkToImage(mSubject, g); } else { lNewImage = GetTexturePage(mSubject, SelectedPage); } mMainForm.VRAMPictureBox.Image = lNewImage; mMainForm.VRAMPictureBox.SizeMode = PictureBoxSizeMode.Normal; mMainForm.VRAMPictureBox.Width = lNewImage.Width; mMainForm.VRAMPictureBox.Height = lNewImage.Height; mMainForm.VRAMPictureBox.Invalidate(); } }
/// <summary> /// Instructs the viewer to display the given object, /// or to free up resources, if appropriate, if the argument is null /// </summary> public abstract void SetSubject(Chunk xiChunk);
public abstract bool CanViewChunk(Chunk xiChunk);
// Only CameraPosChunks can be viewed. public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is CameraPosChunk; }
public override void SetSubject(Chunk xiChunk) { mOptionsMenu.Visible = (mSubject != null); if (xiChunk == null) { if (mMainForm.ViewerTabControl.SelectedTab == null || !(mMainForm.ViewerTabControl.SelectedTab.Tag is ThreeDeeViewer)) { // the view has switched to another tab - reset the tree mMainForm.ChunkTreeView.CheckBoxes = false; } return; } if (mSubject != mMainForm.CurrentLevel) { mSubject = mMainForm.CurrentLevel; RebuildScene(); ResetCamera(); } mMainForm.ChunkTreeView.CheckBoxes = (mSubject != null); ActiveObject = xiChunk; }
private void AddChunkToImage(Chunk c, Graphics g) { if (c is TIMChunk) AddChunkToImage((TIMChunk)c, g); foreach (Chunk child in c.GetChildren()) { if (child is TIMChunk) { AddChunkToImage((TIMChunk)child, g); } else { AddChunkToImage(child, g); } } }
public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is IImageProvider; }
// returns a Bitmap holding the textures in the given Texture page // from VRAM public Bitmap GetTexturePage(Chunk xiRootChunk, int xiPageId) { //check that the level hasn't changed, which would invalidate our cache if (xiRootChunk != mRootChunkForCachedTexPages) { mCachedTexPages = new Bitmap[32]; mRootChunkForCachedTexPages = xiRootChunk; } if (mCachedTexPages == null) { // not a level file -- no textures available return null; } //cache miss? if (mCachedTexPages[xiPageId] == null) { Bitmap lPage = new Bitmap(WIDTH_SCALE * 64, 256); //(i.e. 256x256) Graphics g = Graphics.FromImage(lPage); g.Clear(Color.Black); g.Clip = new Region(new Rectangle(new Point(), lPage.Size)); g.TranslateTransform(-(xiPageId % 16) * (WIDTH_SCALE * 64), -xiPageId / 16 * 256); AddChunkToImage(mRootChunkForCachedTexPages, g); mCachedTexPages[xiPageId] = lPage; } return mCachedTexPages[xiPageId]; }
private void LoadInternal(eOpenType xiOpenType, string xiFilename) { Chunk lNewRootChunk = null; string lExceptionWhen = "opening file"; try { using (FileStream fs = File.OpenRead(xiFilename)) { lExceptionWhen = "deserialising the file"; switch (xiOpenType) { case eOpenType.LevelBinary: lNewRootChunk = new Level(fs); break; case eOpenType.UnknownBinary: lNewRootChunk = new FileChunk(fs); break; case eOpenType.Mmv: lNewRootChunk = new VersionList(fs); break; case eOpenType.Xml: XmlSerializer xs = new XmlSerializer(typeof(Chunk)); lNewRootChunk = (Chunk)xs.Deserialize(fs); break; default: throw new Exception("unreachable case"); } if (fs.Length != fs.Position) { //check the whole file has been read throw new DeserialisationException(string.Format("Deserialisation terminated early at byte {0} of {1}", fs.Position, fs.Length)); } } } catch (Exception err) { Trace.WriteLine(err); MessageBox.Show(string.Format("Exception occurred while {0}: {1}", lExceptionWhen, err.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // level loaded OK, now fill tree: RootChunk = lNewRootChunk; mLocalSettings.LastOpenedFile = xiFilename; mLocalSettings.LastOpenedType = xiOpenType; mCurrentFile = xiFilename; mCurrentFileMode = xiOpenType == eOpenType.Mmv ? eSaveMode.Mmv : xiOpenType == eOpenType.Xml ? eSaveMode.Xml : eSaveMode.Binary; }
public override void SetSubject(Chunk xiChunk) { if (!(xiChunk is FlatChunk)) xiChunk = null; if (mSubject == xiChunk) return; mSubject = (FlatChunk)xiChunk; mWireFrameCache = null; if (xiChunk == null) { mMainForm.GridDisplayPanel.Width = 100; mMainForm.GridDisplayPanel.Height = 100; mMainForm.GridDisplayPanel.Controls.Clear(); } else { //find the width and height of the tex components short topLeftTexIdx = mSubject.TextureIds[0][0]; TIMChunk firstTim = mMainForm.CurrentLevel.GetTileById(topLeftTexIdx); mSubjectTileNativeHeight = firstTim.ImageHeight; mSubjectTileNativeWidth = firstTim.ImageWidth; UpdateZoom(); //init the selected image display boxes const int PADDING = 5, IMG_X_OFF = 32; object[] keys = new object[] { MouseButtons.Left, MouseButtons.Right, '1', '2', '3', '4', 'q', 'w', 'e', 'r' }; mMainForm.GridViewSelPanel.Size = new Size(IMG_X_OFF + PADDING + 64, (64 + PADDING) * keys.Length); for (int i = 0; i < keys.Length; i++) { object key = keys[i]; if (!mKeyOrMouseToSelPicBoxDict.ContainsKey(key)) { Label lab = new Label(); lab.Text = (MouseButtons.Left.Equals(key) ? "LMB" : (MouseButtons.Right.Equals(key) ? "RMB" : key.ToString())); lab.AutoSize = true; mMainForm.GridViewSelPanel.Controls.Add(lab); mKeyOrMouseToLabelDict[key] = lab; PictureBox lPB = new PictureBox(); mMainForm.GridViewSelPanel.Controls.Add(lPB); lPB.Size = new Size(64, 64); lPB.SizeMode = PictureBoxSizeMode.StretchImage; mKeyOrMouseToSelPicBoxDict[key] = lPB; } mKeyOrMouseToLabelDict[key].Location = new Point(0, (int)((i + 0.5) * (64 + PADDING) - 5)); mKeyOrMouseToSelPicBoxDict[key].Location = new Point(IMG_X_OFF, i * (64 + PADDING)); } } //======================================================================= // Reset the ViewMode. This will ensure that the currently selected // mode is valid for the new subject. //======================================================================= ViewMode = ViewMode; }
private void RecursiveAddChunkNode(TreeNodeCollection xiNodes, int xiIndex, Chunk xiChunk) { TreeNode lNode = xiNodes.Insert(xiIndex, xiChunk.Name); //record the mapping on the two objects, for easy reference later //no doubt, this will play merry hell with the GC if you load lots //of different levels... lNode.Tag = xiChunk; xiChunk.TreeNode = lNode; //recurse foreach (Chunk child in xiChunk.GetChildren()) { RecursiveAddChunkNode(lNode.Nodes, child); } }
public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is BumpImageChunk; }
private static void AddChunkToImage(Chunk xiChunk, Bitmap xiBmp, int[,] xiPixelUsageMap) { if (xiChunk is TIMChunk) { try { TIMChunk c = (TIMChunk)xiChunk; Bitmap lTIMImage = c.ToBitmap(); int lPixelsPerTwoBytes; switch (c.BPP) { case TIMChunk.TimBPP._4BPP: lPixelsPerTwoBytes = 4; break; case TIMChunk.TimBPP._8BPP: lPixelsPerTwoBytes = 2; break; case TIMChunk.TimBPP._16BPP: lPixelsPerTwoBytes = 1; break; default: throw new Exception("Can't deal with this BPP"); } Rectangle lDestRect = new Rectangle( WIDTH_SCALE * c.ImageOrgX, c.ImageOrgY, c.ImageWidth * WIDTH_SCALE / lPixelsPerTwoBytes, c.ImageHeight); int lWidthScale = WIDTH_SCALE / lPixelsPerTwoBytes; for (int y = lDestRect.Top; y < lDestRect.Bottom; y++) { for (int x = lDestRect.Left; x < lDestRect.Right; x++) { Color lFromTIM = lTIMImage.GetPixel((x - lDestRect.Left) * lWidthScale, y - lDestRect.Top); SetPixel(xiBmp, x, y, lFromTIM, xiPixelUsageMap); } } if (c.Palette != null) { if (c.ClutCount != 1) throw new Exception("Don't know what to do with multi-CLUT TIMs"); for (int palIdx = 0; palIdx < c.Palette.Length; palIdx++) { Color col = Color.FromArgb(Utils.PS16bitColorToARGB(c.Palette[palIdx])); for (int x = 0; x < WIDTH_SCALE; x++) { SetPixel(xiBmp, WIDTH_SCALE * (c.PaletteOrgX + palIdx) + x, c.PaletteOrgY, col, xiPixelUsageMap); } } } } catch (Exception e) { Console.Error.WriteLine("Error: {0}\nSkipping this TIM", e); } } else { foreach (Chunk c in xiChunk.GetChildren()) { AddChunkToImage(c, xiBmp, xiPixelUsageMap); } } }
public override void SetSubject(Chunk xiChunk) { mSubject = xiChunk as FlatChunk; if (mSubject != null) { Level lLevel = mMainForm.CurrentLevel; Panel.SuspendLayout(); Panel.WeaponsTable.SuspendLayout(); Panel.ObjectsTable.SuspendLayout(); //===================================================================== // Set the general Flat properties //===================================================================== Panel.IdTextBox.Text = mSubject.DeclaredIdx.ToString(); Panel.NameTextBox.Text = mSubject.DeclaredName; Panel.OriginXTextBox.Text = mSubject.OriginPosition.X.ToString(); Panel.OriginYTextBox.Text = mSubject.OriginPosition.Y.ToString(); Panel.OriginZTextBox.Text = mSubject.OriginPosition.Z.ToString(); Panel.RotationXTextBox.Text = mSubject.RotationVector.X.ToString(); Panel.RotationYTextBox.Text = mSubject.RotationVector.Y.ToString(); Panel.RotationZTextBox.Text = mSubject.RotationVector.Z.ToString(); Panel.WidthTextBox.Text = mSubject.Width.ToString(); Panel.HeightTextBox.Text = mSubject.Height.ToString(); Panel.ScaleXTextBox.Text = mSubject.ScaleX.ToString(); Panel.ScaleYTextBox.Text = mSubject.ScaleY.ToString(); Panel.HasMetaDataCheckBox.Checked = mSubject.HasMetaData; Panel.FlagBCheckBox.Checked = mSubject.FlgB; Panel.FlagCCheckBox.Checked = mSubject.FlgC; Panel.VisibleCheckBox.Checked = mSubject.Visible; Panel.FlagECheckBox.Checked = mSubject.FlgE; Panel.NextNTextBox.Text = ArrayToString(mSubject.NextN); Panel.ByteSizeLabel.Text = string.Format("{0} bytes ({1} bytes free)", mSubject.ByteSize, lLevel.SHET.TrailingZeroByteCount); //===================================================================== // Set up the Weapons section //===================================================================== while (Panel.WeaponsTable.RowStyles.Count > 1) { Panel.WeaponsTable.RowStyles.RemoveAt(1); for (int ii = 0; ii < 6; ii++) { Panel.WeaponsTable.Controls.RemoveAt(6); } } if (mSubject.Weapons != null) { foreach (FlatChunk.WeaponEntry lWeapon in mSubject.Weapons) { AddWeaponToTable(lWeapon); } } //===================================================================== // Set up the Objects section //===================================================================== while (Panel.ObjectsTable.RowStyles.Count > 1) { Panel.ObjectsTable.RowStyles.RemoveAt(1); for (int ii = 0; ii < 11; ii++) { Panel.ObjectsTable.Controls.RemoveAt(11); } } if (mSubject.Objects != null) { foreach (FlatChunk.ObjectEntry lObject in mSubject.Objects) { AddObjectToTable(lObject); } } Panel.ObjectsTable.ResumeLayout(); Panel.WeaponsTable.ResumeLayout(); Panel.ResumeLayout(); } }
public override void SetSubject(Chunk xiChunk) { if (!(xiChunk is IEntityProvider)) xiChunk = null; mOptionsMenu.Visible = (xiChunk != null); if (mSubject == xiChunk) return; bool lResetViewMode = true; if (xiChunk != null && mSubject != null && xiChunk.GetType() == mSubject.GetType()) lResetViewMode = false; mSubject = (IEntityProvider)xiChunk; const double MOVE_SCALE = 100; Cursor prevCursor = mMainForm.Viewer3DRenderingSurface.Cursor; mMainForm.Viewer3DRenderingSurface.Cursor = Cursors.WaitCursor; RebuildScene(); if (mSubject != null) { mCamera.Position = new GLTK.Point(-3 * MOVE_SCALE, -3 * MOVE_SCALE, 3 * MOVE_SCALE); mCamera.LookAt(new GLTK.Point(3 * MOVE_SCALE, 3 * MOVE_SCALE, 0), new GLTK.Vector(0, 0, 1)); //set defaults if (lResetViewMode) { if (mSubject is TMDChunk) { LightingMode = eLightingMode.None; //qq MovementMode = eMovementMode.InspectMode; DrawNormalsMode = eDrawNormalsMode.HideNormals; TextureMode = eTextureMode.NormalTextures; SelectedMetadata = eTexMetaDataEntries.Waypoint; } else { LightingMode = eLightingMode.None; MovementMode = eMovementMode.FlyMode; DrawNormalsMode = eDrawNormalsMode.HideNormals; TextureMode = eTextureMode.NormalTextures; SelectedMetadata = eTexMetaDataEntries.Waypoint; } } if (MovementMode == eMovementMode.InspectMode) { mLight.Transform = mCamera.Transform; } mMainForm.ChunkTreeView.CheckBoxes = (mSubject is Level); } else { if (mMainForm.ViewerTabControl.SelectedTab == null || !(mMainForm.ViewerTabControl.SelectedTab.Tag is ThreeDeeEditor)) { mMainForm.ChunkTreeView.CheckBoxes = false; } } mMainForm.Viewer3DRenderingSurface.Cursor = prevCursor; InvalidateViewer(); }
// FlatChunks can be viewed public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is FlatChunk; }
///======================================================================== /// Method : GetDifferences /// /// <summary> /// Produce a list of differences between this chunk and another. /// /// Subclasses should override this method to produce a customised list /// of differences for themselves, but call the base implementation /// which will handle collecting data from their children. /// </summary> /// <param name="xiChunk"></param> /// <returns></returns> /// <remarks> /// This is a brute force method of comparing differences. An alternative /// would be to record the actual actions taken in the UI - this would /// produce cleaner results, although it would be more work to implement. /// </remarks> ///======================================================================== public virtual List<string> GetDifferences(Chunk xiChunk) { //======================================================================= // Get a list of all the children of this chunk, by type //======================================================================= Dictionary<Type, List<Chunk>> lMyChildren = new Dictionary<Type, List<Chunk>>(); foreach (Chunk lChunk in GetChildren()) { List<Chunk> lChunksOfType; if (!lMyChildren.TryGetValue(lChunk.GetType(), out lChunksOfType)) { lChunksOfType = new List<Chunk>(); lMyChildren[lChunk.GetType()] = lChunksOfType; } lChunksOfType.Add(lChunk); } //======================================================================= // Get a list of all the children of the old chunk, by type //======================================================================= Dictionary<Type, List<Chunk>> lOldChildren = new Dictionary<Type, List<Chunk>>(); foreach (Chunk lChunk in xiChunk.GetChildren()) { List<Chunk> lChunksOfType; if (!lOldChildren.TryGetValue(lChunk.GetType(), out lChunksOfType)) { lChunksOfType = new List<Chunk>(); lOldChildren[lChunk.GetType()] = lChunksOfType; } lChunksOfType.Add(lChunk); } //======================================================================= // Generate the list of differences //======================================================================= List<string> lDifferences = new List<string>(); foreach (Type lChunkType in lMyChildren.Keys) { List<Chunk> lMine = lMyChildren[lChunkType]; if (!lOldChildren.ContainsKey(lChunkType)) { lDifferences.Add(string.Format(" Added {0} {1}(s)", lMine.Count, lChunkType)); continue; } List<Chunk> lOld = lOldChildren[lChunkType]; for (int ii = 0; ii < Math.Min(lMine.Count, lOld.Count); ii++) { List<string> lChildDifferences = lMine[ii].GetDifferences(lOld[ii]); if (lChildDifferences.Count > 0) { lDifferences.AddRange( lChildDifferences.ConvertAll<string>( new Converter<string, string>(delegate(string xiDifference) { return " " + xiDifference; }))); } } if (lMine.Count > lOld.Count) { lDifferences.Add(string.Format(" Added {0} {1}(s)", lMine.Count - lOld.Count, lChunkType)); } else if (lOld.Count > lMine.Count) { lDifferences.Add(string.Format(" Removed {0} {1}(s)", lOld.Count - lMine.Count, lChunkType)); } lOldChildren.Remove(lChunkType); } foreach (Type lChunkType in lOldChildren.Keys) { List<Chunk> lOld = lOldChildren[lChunkType]; lDifferences.Add(string.Format(" Removed {0} {1}(s)", lOld.Count, lChunkType)); } if (lDifferences.Count > 0) { lDifferences.Insert(0, string.Format("On {0}:", Name)); } return lDifferences; }
public override bool CanViewChunk(Chunk xiChunk) { return xiChunk is SteeringImageChunk; }