/// <summary> /// /// </summary> /// <param name="handle"></param> /// <param name="fullScreen"></param> /// <param name="doubleBuffer"></param> /// <returns></returns> public IGraphicsSurface CreatePrimarySurface(IntPtr handle, Boolean fullScreen, Boolean doubleBuffer) { DDSURFACEDESC2 tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE; if (doubleBuffer) { tempDescr.lFlags |= CONST_DDSURFACEDESCFLAGS.DDSD_BACKBUFFERCOUNT; tempDescr.lBackBufferCount = 1; tempDescr.ddsCaps.lCaps |= CONST_DDSURFACECAPSFLAGS.DDSCAPS_COMPLEX | CONST_DDSURFACECAPSFLAGS.DDSCAPS_FLIP; } DirectDrawSurface surface = new DirectDrawSurface(tempDescr); if (fullScreen) { return(surface); } DirectDrawClipper clipper = DirectDraw.CreateClipper(0); clipper.SetHWnd(handle.ToInt32()); surface.Surface.SetClipper(clipper); return(surface); }
/// <summary> /// Creates a new sprite sheet with the given name from an image. /// The sheet is broken into sprites given the number of horizontal /// and vertical frames available on this sheet. /// </summary> /// <param name="spriteName">The name of the sprite sheet</param> /// <param name="spriteImagePath">The path to the image to load.</param> /// <param name="xFrames">The number of horizontal frames on this sheet.</param> /// <param name="yFrames">The number of vertical frames on this sheet.</param> public DirectDrawSpriteSurface(string spriteName, string spriteImagePath, int xFrames, int yFrames) { #if TRACE ManagedDirectX.Profiler.Start("DirectDrawSpriteSurface..ctor()"); #endif this.spriteName = spriteName; this.ddsurface = new DirectDrawSurface(spriteImagePath); if (ddsurface == null) { this.ddsurface = new DirectDrawSurface(spriteImagePath, DirectDrawSurface.SystemMemorySurfaceDescription); } this.ddsurface.TransparencyKey = DirectDrawSurface.DefaultColorKey; this.animationFrames = xFrames; this.animationTypes = yFrames; this.frameHeight = this.ddsurface.Rect.Bottom / this.animationTypes; this.frameWidth = this.ddsurface.Rect.Right / this.animationFrames; #if TRACE ManagedDirectX.Profiler.End("DirectDrawSpriteSurface..ctor()"); #endif }
/// <summary> /// Creates a new sprite sheet with the given name from an image. /// The sheet is broken into sprites given the number of horizontal /// and vertical frames available on this sheet. /// </summary> /// <param name="spriteName">The name of the sprite sheet</param> /// <param name="spriteImagePath">The path to the image to load.</param> /// <param name="xFrames">The number of horizontal frames on this sheet.</param> /// <param name="yFrames">The number of vertical frames on this sheet.</param> public DirectDrawSpriteSurface(string spriteName, string spriteImagePath, int xFrames, int yFrames) { #if TRACE GraphicsEngine.Profiler.Start("DirectDrawSpriteSurface..ctor()"); #endif this.spriteName = spriteName; ddsurface = new DirectDrawSurface(spriteImagePath); if (ddsurface == null) { ddsurface = new DirectDrawSurface(spriteImagePath, DirectDrawSurface.SystemMemorySurfaceDescription); } ddsurface.TransparencyKey = new ColorKey(DirectDrawSurface.DefaultColorKey); animationFrames = xFrames; animationTypes = yFrames; frameHeight = ddsurface.Rect.Bottom/animationTypes; frameWidth = ddsurface.Rect.Right/animationFrames; #if TRACE GraphicsEngine.Profiler.End("DirectDrawSpriteSurface..ctor()"); #endif }
/// <summary> /// Creates a new sprite sheet with the given name from an image. /// The sheet is broken into sprites given the number of horizontal /// and vertical frames available on this sheet. /// </summary> /// <param name="spriteName">The name of the sprite sheet</param> /// <param name="spriteImagePath">The path to the image to load.</param> /// <param name="xFrames">The number of horizontal frames on this sheet.</param> /// <param name="yFrames">The number of vertical frames on this sheet.</param> public DirectDrawSpriteSurface(string spriteName, string spriteImagePath, int xFrames, int yFrames) { #if TRACE ManagedDirectX.Profiler.Start("DirectDrawSpriteSurface..ctor()"); #endif this.spriteName = spriteName; ddsurface = new DirectDrawSurface(spriteImagePath); if (ddsurface == null) { ddsurface = new DirectDrawSurface(spriteImagePath, DirectDrawSurface.SystemMemorySurfaceDescription); } ddsurface.TransparencyKey = DirectDrawSurface.DefaultColorKey; animationFrames = xFrames; animationTypes = yFrames; frameHeight = ddsurface.Rect.Bottom / animationTypes; frameWidth = ddsurface.Rect.Right / animationFrames; #if TRACE ManagedDirectX.Profiler.End("DirectDrawSpriteSurface..ctor()"); #endif }
/// <summary> /// /// </summary> /// <param name="handle"></param> /// <param name="fullScreen"></param> /// <param name="doubleBuffer"></param> /// <returns></returns> public IGraphicsSurface CreatePrimarySurface(IntPtr handle, Boolean fullScreen, Boolean doubleBuffer) { DDSURFACEDESC2 tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE; if (doubleBuffer) { tempDescr.lFlags |= CONST_DDSURFACEDESCFLAGS.DDSD_BACKBUFFERCOUNT; tempDescr.lBackBufferCount = 1; tempDescr.ddsCaps.lCaps |= CONST_DDSURFACECAPSFLAGS.DDSCAPS_COMPLEX | CONST_DDSURFACECAPSFLAGS.DDSCAPS_FLIP; } DirectDrawSurface surface = new DirectDrawSurface(tempDescr); if (fullScreen) { return surface; } DirectDrawClipper clipper = DirectDraw.CreateClipper(0); clipper.SetHWnd(handle.ToInt32()); surface.Surface.SetClipper(clipper); return surface; }
/// <summary> /// Reinitialize all surfaces after they have been lost. /// This method invokes the garbage collector to make sure /// that any COM references have been cleaned up, else surface /// renewal won't work correctly. /// </summary> private void ReInitSurfaces() { ScreenSurface = null; BackBufferSurface = null; backgroundSurface = null; stagingSurface = null; tsm.Clear(); tfm.Clear(); GC.Collect(2); GC.WaitForPendingFinalizers(); if (fullscreen) { CreateFullScreenSurfaces(); } else { CreateWindowedSurfaces(); } }
/// <summary> /// Creates the surfaces required for full screen operation. /// </summary> /// <returns>True if the surfaces are initialized, false otherwise.</returns> public bool CreateFullScreenSurfaces() { if (doubleBuffer) { var tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE; ScreenSurface = new DirectDrawSurface(tempDescr); if (ScreenSurface != null) { tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN; tempDescr.lWidth = 640; tempDescr.lHeight = 480; BackBufferSurface = new DirectDrawSurface(tempDescr); } ClearBackground(); } else { var tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_BACKBUFFERCOUNT; tempDescr.lBackBufferCount = 1; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE | CONST_DDSURFACECAPSFLAGS.DDSCAPS_COMPLEX | CONST_DDSURFACECAPSFLAGS.DDSCAPS_FLIP; ScreenSurface = new DirectDrawSurface(tempDescr); if (ScreenSurface != null) { tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_BACKBUFFER; BackBufferSurface = new DirectDrawSurface(ScreenSurface.Surface.GetAttachedSurface(ref tempDescr.ddsCaps)); } } ResetTerrarium(); return true; }
/// <summary> /// Method used to create the necessary surfaces required for windowed /// mode. /// </summary> /// <returns>True if the surfaces are created, otherwise false.</returns> public bool CreateWindowedSurfaces() { var tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE; ScreenSurface = new DirectDrawSurface(tempDescr); Clipper = ManagedDirectX.DirectDraw.CreateClipper(0); Clipper.SetHWnd(Handle.ToInt32()); ScreenSurface.Surface.SetClipper(Clipper); Trace.WriteLine("Primary Surface InVideo? " + ScreenSurface.InVideo); if (ScreenSurface != null) { var workSurfaceWidth = Math.Min(Width, actualsize.Right); var workSurfaceHeight = Math.Min(Height, actualsize.Bottom); tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN; tempDescr.lWidth = workSurfaceWidth; tempDescr.lHeight = workSurfaceHeight; BackBufferSurface = new DirectDrawSurface(tempDescr); Trace.WriteLine("Back Buffer Surface InVideo? " + BackBufferSurface.InVideo); tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN; tempDescr.lWidth = workSurfaceWidth; tempDescr.lHeight = workSurfaceHeight; backgroundSurface = new DirectDrawSurface(tempDescr); Trace.WriteLine("Background Surface InVideo? " + backgroundSurface.InVideo); tempDescr = new DDSURFACEDESC2(); tempDescr.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH; tempDescr.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN; tempDescr.lWidth = workSurfaceWidth; tempDescr.lHeight = workSurfaceHeight; stagingSurface = new DirectDrawSurface(tempDescr); Trace.WriteLine("Staging Surface InVideo? " + stagingSurface.InVideo); } if (!ScreenSurface.InVideo || !BackBufferSurface.InVideo || !backgroundSurface.InVideo || !stagingSurface.InVideo) { videomemory = false; drawtext = true; // For now, turn this to false for a perf increase on slower machines } ResetTerrarium(); ClearBackground(); return true; }
/// <summary> /// Paint sprites on the given surface. This method is the meat /// of the graphics engine. Normally, creatures are painted to /// the work surface using this method. To increase performance plants /// are rendered to the background surface only once every 10 frames. /// Lots of work happening in this function so either read through the /// code or examine the Terrarium Graphics Engine whitepaper for more /// information. /// </summary> /// <param name="dds">The surface to render to.</param> /// <param name="PlantsOnly">True to render plants, false to render animals.</param> private void PaintSprites(DirectDrawSurface dds, bool PlantsOnly) { #if TRACE Profiler.Start("TerrariumDirectDrawGameView.PaintSprites()"); #endif if (wv == null) { return; } if (tfm.Count > 100) { tfm.Clear(); } var TeleporterZIndices = TeleporterZIndex(); var lastTeleporterZIndex = 0; foreach (OrganismState orgState in wv.State.ZOrderedOrganisms) { if (orgState.RenderInfo != null) { var tsSprite = (TerrariumSprite) orgState.RenderInfo; if ((PlantsOnly && !(orgState.Species is PlantSpecies)) || (!PlantsOnly && orgState.Species is PlantSpecies)) { continue; } if (orgState.Species is AnimalSpecies) { tsSprite.AdvanceFrame(); orgState.RenderInfo = tsSprite; } if (!videomemory && skipframe) { continue; } TerrariumSpriteSurface workTss = null; if (workTss == null && tsSprite.SpriteKey != null) { workTss = tsm[tsSprite.SpriteKey, orgState.Radius, (orgState.Species is AnimalSpecies)]; } if (workTss == null && tsSprite.SkinFamily != null) { workTss = tsm[tsSprite.SkinFamily, orgState.Radius, (orgState.Species is AnimalSpecies)]; } if (workTss == null) { if (orgState.Species is AnimalSpecies) { workTss = tsm["ant", orgState.Radius, (orgState.Species is AnimalSpecies)]; } else { workTss = tsm["plant", orgState.Radius, (orgState.Species is AnimalSpecies)]; } } if (workTss != null) { var direction = orgState.ActualDirection; var radius = orgState.Radius; var framedir = 1; var workSurface = workTss.GetClosestSurface((radius*2)); radius = workSurface.FrameWidth; if (direction >= 68 && direction < 113) { framedir = 1; } else if (direction >= 113 && direction < 158) { framedir = 2; } else if (direction >= 158 && direction < 203) { framedir = 3; } else if (direction >= 203 && direction < 248) { framedir = 4; } else if (direction >= 248 && direction < 293) { framedir = 5; } else if (direction >= 293 && direction < 338) { framedir = 6; } else if (direction >= 338 && direction < 23) { framedir = 7; } else { framedir = 8; } var dest = new RECT(); dest.Top = (int) tsSprite.YPosition - (viewsize.Top + (radius >> 1)); dest.Bottom = dest.Top + radius; dest.Left = (int) tsSprite.XPosition - (viewsize.Left + (radius >> 1)); dest.Right = dest.Left + radius; if (updateMiniMap) { var miniMapX = (int) (tsSprite.XPosition*miniMap.Width)/actualsize.Right; miniMapX = (miniMapX > (miniMap.Width - 1)) ? (miniMap.Width - 1) : miniMapX; var miniMapY = (int) (tsSprite.YPosition*miniMap.Height)/actualsize.Bottom; miniMapY = (miniMapY > (miniMap.Height - 1)) ? (miniMap.Height - 1) : miniMapY; var brushColor = Color.Fuchsia; if (orgState.Species.GetType() == typeof (PlantSpecies)) { brushColor = Color.Lime; } else if (orgState.IsAlive == false) { brushColor = Color.Black; } else { var orgSpecies = (Species) orgState.Species; if (orgSpecies.MarkingColor == KnownColor.Green || orgSpecies.MarkingColor == KnownColor.Black) { brushColor = Color.Red; } else { brushColor = Color.FromKnownColor(orgSpecies.MarkingColor); } } Brush orgBrush = new SolidBrush(brushColor); var miniMapGraphics = Graphics.FromImage(miniMap); miniMapGraphics.FillRectangle(orgBrush, miniMapX, miniMapY, 12, 12); miniMapGraphics.Dispose(); orgBrush.Dispose(); //this.miniMap.SetPixel( // miniMapX, // miniMapY, // (orgState.Species is PlantSpecies) ? Color.Green : (!orgState.IsAlive) ? Color.Black : (((Species) orgState.Species).MarkingColor == KnownColor.Green || ((Species) orgState.Species).MarkingColor == KnownColor.Black) ? Color.Red : Color.FromKnownColor(((Species) orgState.Species).MarkingColor)); } DirectDrawClippedRect ddClipRect; if (orgState.Species is PlantSpecies) { ddClipRect = workSurface.GrabSprite((int) tsSprite.CurFrame, 0, dest, clipRect); } else { if (tsSprite.PreviousAction == DisplayAction.NoAction || tsSprite.PreviousAction == DisplayAction.Reproduced || tsSprite.PreviousAction == DisplayAction.Teleported || tsSprite.PreviousAction == DisplayAction.Dead) { if (tsSprite.PreviousAction == DisplayAction.Dead) { ddClipRect = workSurface.GrabSprite( 9, ((int) DisplayAction.Died) + framedir, dest, clipRect); } else { ddClipRect = workSurface.GrabSprite(0, ((int) DisplayAction.Moved) + framedir, dest, clipRect); } } else { ddClipRect = workSurface.GrabSprite((int) tsSprite.CurFrame, ((int) tsSprite.PreviousAction) + framedir, dest, clipRect); } } if (!ddClipRect.Invisible) { if (!PlantsOnly) { RenderTeleporter(lastTeleporterZIndex, (int) tsSprite.YPosition); lastTeleporterZIndex = (int) tsSprite.YPosition; } dds.Surface.BltFast( ddClipRect.Destination.Left, ddClipRect.Destination.Top, workSurface.SpriteSurface.Surface, ref ddClipRect.Source, CONST_DDBLTFASTFLAGS.DDBLTFAST_SRCCOLORKEY); if (drawtext && !PlantsOnly) { var textSurface = tfm[((Species) orgState.Species).Name]; if (textSurface != null && textSurface.Surface != null) { dds.Surface.BltFast( ddClipRect.Destination.Left, ddClipRect.Destination.Top - 14, textSurface.Surface, ref TerrariumTextSurfaceManager.StandardFontRect, CONST_DDBLTFASTFLAGS.DDBLTFAST_SRCCOLORKEY); } } if (!ddClipRect.ClipLeft && !ddClipRect.ClipRight && !ddClipRect.ClipTop && !ddClipRect.ClipBottom) { if (drawDestinationLines) { if (orgState.CurrentMoveToAction != null) { var start = orgState.Position; var end = orgState.CurrentMoveToAction.MovementVector.Destination; dds.Surface.SetForeColor(0); dds.Surface.DrawLine(start.X - viewsize.Left, start.Y - viewsize.Top, end.X - viewsize.Left, end.Y - viewsize.Top); } } if (drawBoundingBox) { var boundingBox = GetBoundsOfState(orgState); dds.Surface.SetForeColor(0); dds.Surface.DrawBox( boundingBox.Left - viewsize.Left, boundingBox.Top - viewsize.Top, (boundingBox.Right + 1) - viewsize.Left, (boundingBox.Bottom + 1) - viewsize.Top ); } if (tsSprite.Selected) { dds.Surface.SetForeColor(0); dds.Surface.DrawBox(ddClipRect.Destination.Left, ddClipRect.Destination.Top, ddClipRect.Destination.Right, ddClipRect.Destination.Bottom); // red Maybe we want some cool graphic here though var lineheight = (int) ((ddClipRect.Destination.Bottom - ddClipRect.Destination.Top)* orgState.PercentEnergy); dds.Surface.SetForeColor(63488); dds.Surface.DrawLine(ddClipRect.Destination.Left - 1, ddClipRect.Destination.Top, ddClipRect.Destination.Left - 1, ddClipRect.Destination.Top + lineheight); //green Maybe we want some cool graphic here though (or an actual bar?) lineheight = (int) ((ddClipRect.Destination.Bottom - ddClipRect.Destination.Top)* orgState.PercentInjured); dds.Surface.SetForeColor(2016); dds.Surface.DrawLine(ddClipRect.Destination.Right + 1, ddClipRect.Destination.Top, ddClipRect.Destination.Right + 1, ddClipRect.Destination.Top + lineheight); } } } } } } RenderTeleporter(lastTeleporterZIndex, actualsize.Bottom); #if TRACE Profiler.End("TerrariumDirectDrawGameView.PaintSprites()"); #endif }
/// <summary> /// Adds a new string to the text surface manager. This creates /// the associated text surface so that text can be rendered with /// a fast Blt rather than with a DrawText call. Note that caching /// could be done in a much more efficient manner and some text /// surfaces will have identical contents. /// </summary> /// <param name="key">The string to add.</param> internal void Add(string key) { if (key == null || key.Length == 0) { return; } // Set up the surface RECT rect = new RECT(); DirectDrawSurface ddSurface = new DirectDrawSurface(StandardFontRect.Right,StandardFontRect.Bottom); ddSurface.TransparencyKey = DirectDrawSurface.MagentaColorKey; // Color in the back and add the text ddSurface.Surface.BltColorFill(ref rect, DirectDrawSurface.MagentaColorKey.low); ddSurface.Surface.SetForeColor(0); string text = key; if (text.Length > 16) { text = text.Substring(0,16); text += "..."; } IntPtr dcHandle = new IntPtr(ddSurface.Surface.GetDC()); System.Drawing.Graphics graphics = System.Drawing.Graphics.FromHdc( dcHandle ); System.Drawing.Font font = new System.Drawing.Font( "Verdana", 6.75f, System.Drawing.FontStyle.Regular ); graphics.DrawString( text, font, System.Drawing.Brushes.Black, 1, 1 ); graphics.DrawString( text, font, System.Drawing.Brushes.WhiteSmoke, 0, 0 ); font.Dispose(); graphics.Dispose(); ddSurface.Surface.ReleaseDC( dcHandle.ToInt32() ); sprites.Add(key, ddSurface); }
/// <summary> /// Adds a new string to the text surface manager. This creates /// the associated text surface so that text can be rendered with /// a fast Blt rather than with a DrawText call. Note that caching /// could be done in a much more efficient manner and some text /// surfaces will have identical contents. /// </summary> /// <param name="key">The string to add.</param> internal void Add(string key) { if (string.IsNullOrEmpty(key)) { return; } // Set up the surface var rect = new RECT(); var ddSurface = new DirectDrawSurface(StandardFontRect.Right, StandardFontRect.Bottom) { TransparencyKey = DirectDrawSurface.MagentaColorKey }; // Color in the back and add the text ddSurface.Surface.BltColorFill(ref rect, DirectDrawSurface.MagentaColorKey.low); ddSurface.Surface.SetForeColor(0); var text = key; if (text.Length > 16) { text = text.Substring(0, 16); text += "..."; } var dcHandle = new IntPtr(ddSurface.Surface.GetDC()); var graphics = Graphics.FromHdc(dcHandle); var font = new Font("Verdana", 6.75f, FontStyle.Regular); graphics.DrawString(text, font, Brushes.Black, 1, 1); graphics.DrawString(text, font, Brushes.WhiteSmoke, 0, 0); font.Dispose(); graphics.Dispose(); ddSurface.Surface.ReleaseDC(dcHandle.ToInt32()); sprites.Add(key, ddSurface); }