Ok, noi abbiamo il nostro automa cellulare bidimensionale, un divertente gioco della vita interattivo implementato in C# / WPF. Vediamo come estendere il rendering grafico ad armoniose e più interessanti varianti. Definiamo prima di tutto l’interfaccia IRender:
public interface IRender {
int CellSize { get; set; }
void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette);
void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette);
System.Windows.Controls.Image Render(byte[] buf, int width, int height);
}
Il rendering base, basato cioè sulla corrispondenza “cella” -> “1×1 pixel su schermo” viene implementato agevolmente utilizzando BitmapImage.Create():
class RenderBase : IRender {
public int CellSize { get { return 1; } set { } }
private BitmapPalette Palette = BitmapPalettes.BlackAndWhite;
public void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette) {
Palette = new BitmapPalette(ImageUtils.ConvertPaletteInMediaColor(colorsPalette));
}
public void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette) {
Palette = new BitmapPalette(colorsPalette);
}
public System.Windows.Controls.Image Render(byte[] buf, int width, int height) {
const double dpi = 96;
return new Image() {
Source = BitmapImage.Create((int)width, (int)height, dpi, dpi,
PixelFormats.Indexed8, Palette, buf, (int)width)
};
}
public override string ToString() {
return "1x1 Pixel (fastest)";
}
}
Per ottenere diversi render più complessi, basati sulla forma della singola cella e relativamente al bordo della stessa, creiamo una classe astratta RenderGraphics che utilizza le librerie grafiche GDI+ per il disegno delle singole celle e la composizione dell’ambiente.
abstract class RenderGraphics : IRender {
public int CellSize { get; set; }
protected IList<System.Drawing.SolidBrush> Palette { get; private set; }
public void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette) {
foreach (System.Drawing.SolidBrush brush in Palette)
brush.Dispose();
Palette = colorsPalette;
}
public void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette) {
Palette = ImageUtils.ConvertPaletteInDrawingBrush(colorsPalette);
}
public System.Windows.Controls.Image Render(byte[] buf, int width, int height) {
using (Bitmap b = new Bitmap(width * CellSize, height * CellSize)) {
using (Graphics g = Graphics.FromImage(b)) {
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
for (int i = 0; i < width * height; i++) {
int x = (int)(i % width);
int y = (int)(i / width);
Draw(g, Palette[buf[i]], x, y);
}
}
return ImageUtils.ConvertToWpfImage(b);
}
}
protected abstract void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y);
}
-
-
RenderFilledRects
-
-
RenderFilledRectsBorder
-
-
RenderEmptyRects
-
-
RenderFilledDotsBorder
-
-
RenderFilledDots
-
-
RenderEmptyDots
I diversi rendering grafici si ottengono estendendo RenderGraphics e implementando il metodo Draw():
class RenderFilledRects : RenderGraphics {
public override string ToString() { return "Filled Rects without border"; }
protected override void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y) {
g.FillRectangle(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize, CellSize);
}
}
class RenderFilledRectsBorder : RenderGraphics {
public override string ToString() { return "Filled Rects with border"; }
protected override void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y) {
g.FillRectangle(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 1, CellSize - 1);
}
}
class RenderFilledDots : RenderGraphics {
public override string ToString() { return "Filled Dots without border"; }
protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
g.FillEllipse(brush, x + (CellSize-1) * x, y + (CellSize-1) * y, CellSize+1, CellSize+1);
}
}
class RenderFilledDotsBorder : RenderGraphics {
public override string ToString() { return "Filled Dots with border"; }
protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
g.FillEllipse(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize-1, CellSize-1);
}
}
class RenderEmptyDots : RenderGraphics {
public override string ToString() { return "Empty Dots"; }
protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
g.DrawEllipse(new Pen(brush, 1), x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 2, CellSize - 2);
}
}
class RenderEmptyRects : RenderGraphics {
public override string ToString() { return "Empty Rects"; }
protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
g.DrawRectangle(new Pen(brush, 1), x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 2, CellSize - 2);
}
}
Gioco della vita renderizzato a cubetti
Devi effettuare l'accesso per postare un commento.