diff --git a/FastPixel.cs b/FastPixel.cs index ed56cda..d4e7ad5 100644 --- a/FastPixel.cs +++ b/FastPixel.cs @@ -5,13 +5,13 @@ using System.Drawing.Imaging; class FastPixel { private byte[] rgbValues; private BitmapData bmpData; - private IntPtr bmpPtr; private bool locked = false; private bool _isAlpha = false; private Bitmap _bitmap; private int _width; private int _height; + private int bytesPerPixel; public int Width { get { return this._width; } @@ -37,6 +37,7 @@ class FastPixel { this._isAlpha = (this.Bitmap.PixelFormat == (this.Bitmap.PixelFormat | PixelFormat.Alpha)); this._width = bitmap.Width; this._height = bitmap.Height; + this.bytesPerPixel = (this._isAlpha)?4:3; } public void Lock() { @@ -45,16 +46,21 @@ class FastPixel { Rectangle rect = new Rectangle(0, 0, this.Width, this.Height); this.bmpData = this.Bitmap.LockBits(rect, ImageLockMode.ReadWrite, this.Bitmap.PixelFormat); - this.bmpPtr = this.bmpData.Scan0; - - int bytes; - if (this.IsAlphaBitmap) { - bytes = (this.Width * this.Height) * 4; - } else { - bytes = (this.Width * this.Height) * 3; + this.rgbValues = new byte[(this.Width * this.Height) * this.bytesPerPixel]; + + unsafe { + byte* ptr= (byte*)this.bmpData.Scan0; + int offset = this.bmpData.Stride - this.bmpData.Width * this.bytesPerPixel; + for(int y = 0; y < this.Height; y++, ptr += offset) { + for(int x = 0; x < this.Width; x++, ptr += this.bytesPerPixel) { + int index = ((y * this.Width + x) * this.bytesPerPixel); + this.rgbValues[index] = ptr[0]; + this.rgbValues[index+1] = ptr[1]; + this.rgbValues[index+2] = ptr[2]; + if (this.bytesPerPixel == 4) this.rgbValues[index+3] = ptr[3]; + } + } } - this.rgbValues = new byte[bytes]; - System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length); this.locked = true; } @@ -63,8 +69,21 @@ class FastPixel { throw new Exception("Bitmap not locked."); // Copy the RGB values back to the bitmap; - if (setPixels) - System.Runtime.InteropServices.Marshal.Copy(this.rgbValues, 0, this.bmpPtr, this.rgbValues.Length); + if (setPixels) { + unsafe { + byte* ptr= (byte*)this.bmpData.Scan0; + int offset = this.bmpData.Stride - this.bmpData.Width * this.bytesPerPixel; + for(int y = 0; y < this.Height; y++, ptr += offset) { + for(int x = 0; x < this.Width; x++, ptr += this.bytesPerPixel) { + int index = ((y * this.Width + x) * this.bytesPerPixel); + ptr[0] = this.rgbValues[index]; + ptr[1] = this.rgbValues[index+1]; + ptr[2] = this.rgbValues[index+2]; + if (this.bytesPerPixel == 4) ptr[3] = this.rgbValues[index+3]; + } + } + } + } // Unlock the bits.; this.Bitmap.UnlockBits(bmpData); @@ -75,19 +94,11 @@ class FastPixel { if (!this.locked) throw new Exception("Bitmap not locked."); - if (this.IsAlphaBitmap) { - for (int index = 0; index < this.rgbValues.Length; index += 4) { - this.rgbValues[index] = colour.B; - this.rgbValues[index + 1] = colour.G; - this.rgbValues[index + 2] = colour.R; - this.rgbValues[index + 3] = colour.A; - } - } else { - for (int index = 0; index < this.rgbValues.Length; index += 3) { - this.rgbValues[index] = colour.B; - this.rgbValues[index + 1] = colour.G; - this.rgbValues[index + 2] = colour.R; - } + for (int index = 0; index < this.rgbValues.Length; index += this.bytesPerPixel) { + this.rgbValues[index] = colour.B; + this.rgbValues[index + 1] = colour.G; + this.rgbValues[index + 2] = colour.R; + if (this.bytesPerPixel == 4) this.rgbValues[index + 3] = colour.A; } } @@ -99,18 +110,11 @@ class FastPixel { if (!this.locked) throw new Exception("Bitmap not locked."); - if (this.IsAlphaBitmap) { - int index = ((y * this.Width + x) * 4); - this.rgbValues[index] = colour.B; - this.rgbValues[index + 1] = colour.G; - this.rgbValues[index + 2] = colour.R; - this.rgbValues[index + 3] = colour.A; - } else { - int index = ((y * this.Width + x) * 3); - this.rgbValues[index] = colour.B; - this.rgbValues[index + 1] = colour.G; - this.rgbValues[index + 2] = colour.R; - } + int index = ((y * this.Width + x) * this.bytesPerPixel); + this.rgbValues[index] = colour.B; + this.rgbValues[index + 1] = colour.G; + this.rgbValues[index + 2] = colour.R; + if (this.bytesPerPixel == 4) this.rgbValues[index + 3] = colour.A; } public Color GetPixel(Point location) { @@ -121,19 +125,14 @@ class FastPixel { if (!this.locked) throw new Exception("Bitmap not locked."); - if (this.IsAlphaBitmap) { - int index = ((y * this.Width + x) * 4); - int b = this.rgbValues[index]; - int g = this.rgbValues[index + 1]; - int r = this.rgbValues[index + 2]; + int index = ((y * this.Width + x) * this.bytesPerPixel); + int b = this.rgbValues[index]; + int g = this.rgbValues[index + 1]; + int r = this.rgbValues[index + 2]; + if (this.bytesPerPixel == 4) { int a = this.rgbValues[index + 3]; return Color.FromArgb(a, r, g, b); - } else { - int index = ((y * this.Width + x) * 3); - int b = this.rgbValues[index]; - int g = this.rgbValues[index + 1]; - int r = this.rgbValues[index + 2]; - return Color.FromArgb(r, g, b); } + return Color.FromArgb(r, g, b); } } \ No newline at end of file diff --git a/Output_GUI.cs b/Output_GUI.cs index a8b389a..be9e29e 100644 --- a/Output_GUI.cs +++ b/Output_GUI.cs @@ -10,7 +10,7 @@ namespace vampi { public class Output_GUI : Output { const int statsHeight = 45; - double scale = 1; + int scale = 1; Form f = new Form(); FastPixel fp; Graphics fg; @@ -18,11 +18,8 @@ namespace vampi { Bitmap stats; public Output_GUI() { - field = new Bitmap(Settings.size, Settings.size, System.Drawing.Imaging.PixelFormat.Format24bppRgb); - stats = new Bitmap(300, Output_GUI.statsHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); - fp = new FastPixel(field); - fg = Graphics.FromHwnd(f.Handle); - fg.InterpolationMode = InterpolationMode.NearestNeighbor; + this.field = new Bitmap(Settings.size, Settings.size, System.Drawing.Imaging.PixelFormat.Format24bppRgb); + this.stats = new Bitmap(f.ClientSize.Width, Output_GUI.statsHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); @@ -37,10 +34,17 @@ namespace vampi { Graphics g = Graphics.FromImage(this.field); g.Clear(Settings.guiColorEmpty); g.Dispose(); + + if (Math.Min(f.ClientSize.Width, f.ClientSize.Height-Output_GUI.statsHeight) < Settings.size) { + f.ClientSize = new Size(Settings.size, Settings.size+Output_GUI.statsHeight); + } + fp = new FastPixel(field); + fg = Graphics.FromHwnd(f.Handle); + fg.InterpolationMode = InterpolationMode.NearestNeighbor; fg.Clear(Color.White); // clear window background - calculateScale(); f.Show(); + calculateScale(); } ~Output_GUI() { @@ -54,11 +58,13 @@ namespace vampi { } public void calculateScale() { - scale = (double)(Math.Min(f.ClientSize.Height - Output_GUI.statsHeight, f.ClientSize.Width) / Settings.size); + scale = (int)Math.Floor((double)Math.Min(f.ClientSize.Height - Output_GUI.statsHeight, f.ClientSize.Width) / (double)Settings.size); + if (scale<1) scale = 1; } public void FormResize(object sender, EventArgs e) { calculateScale(); + stats = new Bitmap(f.ClientSize.Width, Output_GUI.statsHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); fg = Graphics.FromHwnd(f.Handle); fg.InterpolationMode = InterpolationMode.NearestNeighbor; fg.Clear(Color.White); @@ -66,7 +72,7 @@ namespace vampi { public override void doOutput() { this.drawGameMap(); - if (Program.AnzSimDone % 2 == 0) this.drawStatistics(); + this.drawStatistics(); Application.DoEvents(); } @@ -123,19 +129,22 @@ namespace vampi { } } fp.Unlock(true); - fg.DrawImage(this.field, 0, Output_GUI.statsHeight, (int)(Settings.size * this.scale), (int)(Settings.size * this.scale)); + fg.DrawImage(this.field, 0, Output_GUI.statsHeight, Settings.size * this.scale, Settings.size * this.scale); f.Update(); } public void drawStatistics() { if (!f.Visible) this.requestAbort = true; Graphics g = Graphics.FromImage(this.stats); + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; g.Clear(Color.White); int lineSpc = 10; int Ecount = Einwohner.Count; // sflaeche.countTypeOccurrences(Typliste.EINWOHNER); int Vcount = Vampir.Count; // sflaeche.countTypeOccurrences(Typliste.VAMPIR); - g.DrawString(String.Format("Steps Done: {0:D5}", Program.AnzSimDone), Settings.guiFont, Settings.guiFontBrush, 5, 0); + g.DrawString(String.Format("Step: {0:D5}", Program.AnzSimDone), Settings.guiFont, Settings.guiFontBrush, 5, 0); + g.DrawString(String.Format("T{0:N} = {1:D}/sec", Program.lastCalcTime+Program.lastStatsTime, (int)Math.Floor(1000/(Program.lastCalcTime+Program.lastStatsTime))), Settings.guiFont, Settings.guiFontBrush, 100, 0); + g.DrawString(String.Format("C{0:N} D{1:N}", Program.lastCalcTime, Program.lastStatsTime), Settings.guiFont, Settings.guiFontBrush, 200, 0); g.DrawString(String.Format(String.Format("Einwohner: {0:D} / Vampire: {1:D}", Ecount, Vcount), Program.AnzSimDone), Settings.guiFont, Settings.guiFontBrush, 5, 1*lineSpc); g.DrawString(String.Format(String.Format("Verhältnis Vampire/Einwohner = 1/{0:N5}", (double)Ecount / Vcount), Program.AnzSimDone), Settings.guiFont, Settings.guiFontBrush, 5, 2*lineSpc); g.DrawString(String.Format(String.Format("Bedeckung: {0:N5} %", (double)(Ecount + Vcount) / (Settings.size*Settings.size) * 100), Program.AnzSimDone), Settings.guiFont, Settings.guiFontBrush, 5, 3*lineSpc); diff --git a/Program.cs b/Program.cs index 3d8be8b..9dc0b6c 100644 --- a/Program.cs +++ b/Program.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Timers; +using System.Timers; +using System.Diagnostics; namespace vampi { class Program { @@ -12,17 +13,28 @@ namespace vampi { get { return Program.anz_sim_done; } } public static Random random = new Random(); - public static Spielflaeche sflaeche = new Spielflaeche(Settings.size, Settings.coveragePercent, Settings.vampireRatio); + public static Spielflaeche sflaeche = new Spielflaeche(Settings.size, Settings.coveragePercent, Settings.vampireRatio); + public static double lastCalcTime = 0; + public static double lastStatsTime = 0; static void Main(string[] args) { - Output output = new Output_GUI(); + Output output = new Output_GUI(); + Stopwatch sw = new Stopwatch(); for (anz_sim_done=0; anz_sim_done < anz_sim; anz_sim_done++) { if (anz_sim_done % Settings.drawEveryNthStep == 0) { - output.doOutput(); + sw.Reset(); + sw.Start(); + output.doOutput(); + sw.Stop(); + Program.lastStatsTime = sw.Elapsed.TotalMilliseconds; } - if (output.requestAbort) break; - sflaeche.simulateStep(); + if (output.requestAbort) break; + sw.Reset(); + sw.Start(); + sflaeche.simulateStep(); + sw.Stop(); + Program.lastCalcTime = sw.Elapsed.TotalMilliseconds; } }//Main }//class diff --git a/Settings.cs b/Settings.cs index 55a8d2f..02edd5d 100644 --- a/Settings.cs +++ b/Settings.cs @@ -3,20 +3,23 @@ using System.Drawing; namespace vampi { public abstract class Settings { - public const int size = 43; + public const int size = 500; public const int coveragePercent = 77; public const int vampireRatio = 3; - public const int drawEveryNthStep = 1; + public const int drawEveryNthStep = 1; public const ConsoleColor colorHuman = ConsoleColor.Green; public const ConsoleColor colorHumanInfected = ConsoleColor.DarkMagenta; public const ConsoleColor colorVampire = ConsoleColor.Red; public const ConsoleColor colorEmpty = ConsoleColor.Gray; - public static Color[] guiColorHuman = {Color.FromArgb(0, 60, 0), Color.LimeGreen}; +/* public static Color guiColorHuman = Color.LimeGreen; + public static Color guiColorHumanInfected = Color.DarkMagenta; + public static Color guiColorVampire = Color.Red; +*/ public static Color[] guiColorHuman = {Color.FromArgb(0, 60, 0), Color.LimeGreen}; public static Color[] guiColorHumanInfected = {Color.FromArgb(60, 0, 60), Color.DarkMagenta}; public static Color[] guiColorVampire = {Color.FromArgb(60, 0, 0), Color.Red}; - public static Color guiColorEmpty = Color.Gray; + public static Color guiColorEmpty = Color.Silver; public static Font guiFont = new Font("sans-serif", 8); public static Brush guiFontBrush = Brushes.Black; diff --git a/vampi.csproj b/vampi.csproj index 04a6597..9cac808 100644 --- a/vampi.csproj +++ b/vampi.csproj @@ -24,7 +24,7 @@ <OutputType>Exe</OutputType> <AssemblyName>vampi</AssemblyName> <RootNamespace>vampi</RootNamespace> - <AllowUnsafeBlocks>false</AllowUnsafeBlocks> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <ApplicationIcon>.</ApplicationIcon> </PropertyGroup> @@ -39,7 +39,7 @@ <AssemblyName>vampi</AssemblyName> <DebugSymbols>true</DebugSymbols> <RootNamespace>vampi</RootNamespace> - <AllowUnsafeBlocks>false</AllowUnsafeBlocks> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> <ApplicationIcon>.</ApplicationIcon> </PropertyGroup>