Jypeli  5
The simple game programming library
Image.cs
Siirry tämän tiedoston dokumentaatioon.
1 using Microsoft.Xna.Framework.Graphics;
2 using Microsoft.Xna.Framework;
3 using System;
4 using System.IO;
5 using System.Collections.Generic;
6 using System.ComponentModel;
7 using System.Diagnostics;
8 
9 using XnaRectangle = Microsoft.Xna.Framework.Rectangle;
10 using XnaV2 = Microsoft.Xna.Framework.Vector2;
11 using XnaColor = Microsoft.Xna.Framework.Color;
13 
14 #if !XBOX
15 using System.Net;
16 using System.Threading;
17 #endif
18 
19 namespace Jypeli
20 {
24  public class Image
25  {
26  private Image parentImage;
27  private XnaRectangle parentRectangle;
28 
29  private string assetName;
30  private Texture2D xnaTexture;
31 
32  private event Action InitDimensions;
33  private event Action InitTexture;
34 
35  int _width = -1;
36  int _height = -1;
37 
38  internal Texture2D XNATexture
39  {
40  get { DoInitTexture(); return xnaTexture; }
41  }
42 
43  public Color this[int row, int col]
44  {
45  get
46  {
47  DoInitTexture();
48 
49  Color[] buffer = new Color[1];
50  XnaRectangle rect = new XnaRectangle( col, row, 1, 1 );
51  xnaTexture.GetData<Color>( 0, rect, buffer, 0, 1 );
52  return buffer[0];
53  }
54  set
55  {
56  DoInitTexture();
57  InvalidateAsset();
58 
59  if ( row < 0 || row >= xnaTexture.Height ) throw new IndexOutOfRangeException( "row" );
60  if ( col < 0 || col >= XNATexture.Width ) throw new IndexOutOfRangeException( "col" );
61 
62  Color[] buffer = new Color[1] { value };
63  XnaRectangle rect = new XnaRectangle( col, row, 1, 1 );
64 
65  xnaTexture.SetData<Color>( 0, rect, buffer, 0, 1 );
66  UpdateTexture();
67  }
68  }
69 
70 
79  public Color[,] GetData( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
80  {
81  int ny = Height;
82  if ( h < ny ) ny = h;
83  if ( Height < ny + oy ) ny = Height - oy;
84  int nx = Width;
85  if ( w < nx ) nx = w;
86  if ( Width < nx + ox ) nx = Width - ox;
87  if ( nx <= 0 || ny <= 0 ) return new Color[0, 0];
88 
89  DoInitTexture();
90  Color[,] bmp = new Color[ny, nx];
91 
92  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
93  Color[] buffer = new Color[ny * nx];
94  xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
95  int i = 0;
96  for ( int iy = 0; iy < ny; iy++ )
97  for ( int ix = 0; ix < nx; ix++ )
98  bmp[iy, ix] = buffer[i++];
99  return bmp;
100  }
101 
102 
112  public void SetData( Color[,] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
113  {
114  DoInitTexture();
115  InvalidateAsset();
116  int ny = bmp.GetLength( 0 );
117  int nx = bmp.GetLength( 1 );
118  if ( ny > Height ) ny = Height;
119  if ( nx > Width ) nx = Height;
120  if ( ny > h ) ny = h;
121  if ( nx > w ) nx = w;
122  if ( Height < ny + oy ) ny = Height - oy;
123  if ( Width < nx + ox ) nx = Width - ox;
124  if ( nx <= 0 || ny <= 0 ) return;
125 
126  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
127  Color[] buffer = new Color[ny * nx];
128  int i = 0;
129  for ( int iy = 0; iy < ny; iy++ )
130  for ( int ix = 0; ix < nx; ix++ )
131  buffer[i++] = bmp[iy, ix];
132 
133  xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
134  UpdateTexture();
135  }
136 
137 
146  public uint[,] GetDataUInt( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
147  {
148  int ny = Height;
149  if ( h < ny ) ny = h;
150  if ( Height < ny + oy ) ny = Height - oy;
151  int nx = Width;
152  if ( w < nx ) nx = w;
153  if ( Width < nx + ox ) nx = Width - ox;
154  if ( nx <= 0 || ny <= 0 ) return new uint[0, 0];
155 
156  DoInitTexture();
157  uint[,] bmp = new uint[ny, nx];
158 
159  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
160  Color[] buffer = new Color[ny * nx];
161  xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
162  int i = 0;
163  for ( int iy = 0; iy < ny; iy++ )
164  for ( int ix = 0; ix < nx; ix++ )
165  bmp[iy, ix] = buffer[i++].ToUInt();
166  return bmp;
167  }
168 
169 
178  public uint[][] GetDataUIntAA( int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
179  {
180  int ny = Height;
181  if ( h < ny ) ny = h;
182  if ( Height < ny + oy ) ny = Height - oy;
183  int nx = Width;
184  if ( w < nx ) nx = w;
185  if ( Width < nx + ox ) nx = Width - ox;
186  if ( nx <= 0 || ny <= 0 ) return new uint[0][];
187 
188  DoInitTexture();
189  uint[][] bmp = new uint[ny][];
190 
191  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
192  Color[] buffer = new Color[ny * nx];
193  xnaTexture.GetData<Color>( 0, rect, buffer, 0, buffer.Length );
194  int i = 0;
195  for ( int iy = 0; iy < ny; iy++ )
196  {
197  uint[] row = new uint[nx];
198  bmp[iy] = row;
199  for ( int ix = 0; ix < nx; ix++ )
200  row[ix] = buffer[i++].ToUInt();
201  }
202  return bmp;
203  }
204 
205 
214  public void SetData( uint[,] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
215  {
216  DoInitTexture();
217  InvalidateAsset();
218  int ny = bmp.GetLength( 0 );
219  int nx = bmp.GetLength( 1 );
220  if ( ny > Height ) ny = Height;
221  if ( nx > Width ) nx = Width;
222  if ( ny > h ) ny = h;
223  if ( nx > w ) nx = w;
224  if ( Height < ny + oy ) ny = Height - oy;
225  if ( Width < nx + ox ) nx = Width - ox;
226 
227  if ( nx <= 0 || ny <= 0 ) return;
228 
229  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
230  Color[] buffer = new Color[ny * nx];
231  int i = 0;
232  for ( int iy = 0; iy < ny; iy++ )
233  for ( int ix = 0; ix < nx; ix++ )
234  buffer[i++] = Jypeli.Color.UIntToColor( bmp[iy, ix] );
235  // foreach (int c in bmp) buffer[i++] = Jypeli.Color.IntToColor(c);
236 
237  xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
238  UpdateTexture();
239  }
240 
241 
250  public void SetData( uint[][] bmp, int ox = 0, int oy = 0, int w = int.MaxValue, int h = int.MaxValue )
251  {
252  DoInitTexture();
253  InvalidateAsset();
254  int ny = bmp.Length;
255  int nx = bmp[0].Length;
256  if ( ny > Height ) ny = Height;
257  if ( nx > Width ) nx = Width;
258  if ( ny > h ) ny = h;
259  if ( nx > w ) nx = w;
260  if ( nx <= 0 || ny <= 0 ) return;
261 
262  XnaRectangle rect = new XnaRectangle( ox, oy, nx, ny );
263  Color[] buffer = new Color[ny * nx];
264  int i = 0;
265  for ( int iy = 0; iy < ny; iy++ )
266  for ( int ix = 0; ix < nx; ix++ )
267  buffer[i++] = Jypeli.Color.UIntToColor( bmp[iy][ix] );
268  // foreach (int c in bmp) buffer[i++] = Jypeli.Color.IntToColor(c);
269 
270  xnaTexture.SetData<Color>( 0, rect, buffer, 0, buffer.Length );
271  UpdateTexture();
272  }
273 
274  public override int GetHashCode()
275  {
276  if ( assetName != null )
277  return assetName.GetHashCode();
278 
279  if ( xnaTexture != null )
280  return xnaTexture.GetHashCode();
281 
282  return base.GetHashCode();
283  }
284 
285 
289  public int Width
290  {
291  get { DoInitDimensions(); return _width; }
292  }
293 
297  public int Height
298  {
299  get { DoInitDimensions(); return _height; }
300  }
301 
305  public string Name
306  {
307  get { DoInitTexture(); return xnaTexture.Name; }
308  }
309 
310  internal Image( int width, int height )
311  {
312  this._width = width;
313  this._height = height;
314  this.InitTexture += CreateNewTexture;
315  }
316 
317  internal Image( string assetName )
318  {
319  this.assetName = assetName;
320  this.InitDimensions += LoadContentTexture;
321  }
322 
323  [EditorBrowsable( EditorBrowsableState.Never )]
324  public Image( Microsoft.Xna.Framework.Graphics.Texture2D texture )
325  {
326  this.xnaTexture = texture;
327  this._width = texture.Width;
328  this._height = texture.Height;
329  }
330 
337  public Image( int width, int height, Color backColor )
338  {
339  assetName = null;
340  this._width = width;
341  this._height = height;
342  this.InitTexture += CreateNewTexture;
343  this.InitTexture += delegate { this.Fill( backColor ); };
344  }
345 
352  public Image( double width, double height, Color backColor )
353  : this( (int)Math.Round( width ), (int)Math.Round( height ), backColor )
354  {
355  }
356 
357  private void DoInitDimensions()
358  {
359  if ( _width >= 0 && _height >= 0 )
360  return;
361 
362  if ( InitDimensions != null )
363  InitDimensions();
364  else
365  throw new InvalidOperationException( "Cannot initialize dimensions for image!" );
366  }
367 
368  private void DoInitTexture()
369  {
370  DoInitDimensions();
371 
372  if ( xnaTexture != null )
373  return;
374 
375  if ( InitTexture != null )
376  InitTexture();
377  else
378  throw new InvalidOperationException( "Cannot initialize texture for image!" );
379  }
380 
381  private void LoadContentTexture()
382  {
383  // Some duct tape around the fact that in XNA,
384  // content can not be loaded before LoadContent().
385  Debug.Assert( assetName != null );
386  xnaTexture = Game.Instance.Content.Load<Texture2D>( assetName );
387  _width = xnaTexture.Width;
388  _height = xnaTexture.Height;
389  }
390 
391  private void CreateNewTexture()
392  {
393  this.xnaTexture = new Texture2D( Game.GraphicsDevice, Width, Height );
394  }
395 
396  public Image Clone()
397  {
398  Image copy;
399 
400  if ( assetName != null )
401  {
402  copy = new Image( assetName );
403  }
404  else
405  {
406  copy = new Image( this.Width, this.Height );
407  copy.InitTexture += delegate { CopyData( copy, this ); };
408  }
409 
410  return copy;
411  }
412 
413  private static void CopyData( Image dest, Image src )
414  {
415  src.DoInitTexture();
416 
417  int w = src.Width;
418  int h = src.Height;
419  XnaRectangle rect = new XnaRectangle( 0, 0, w, 1 );
420  Color[] scanline = new Color[w];
421 
422  for ( rect.Y = 0; rect.Y < h; rect.Y++ )
423  {
424  src.xnaTexture.GetData<Color>( 0, rect, scanline, 0, w );
425  dest.xnaTexture.SetData<Color>( 0, rect, scanline, 0, w );
426  }
427  }
428 
429  private static void CopyData( Texture2D dest, Texture2D src )
430  {
431  int w = src.Width;
432  int h = src.Height;
433  XnaRectangle rect = new XnaRectangle( 0, 0, w, 1 );
434  Color[] scanline = new Color[w];
435 
436  for ( rect.Y = 0; rect.Y < h; rect.Y++ )
437  {
438  src.GetData<Color>( 0, rect, scanline, 0, w );
439  dest.SetData<Color>( 0, rect, scanline, 0, w );
440  }
441  }
442 
443  private static void CopyData( Image dest, Image src, XnaRectangle destRect, XnaRectangle srcRect )
444  {
445  src.DoInitTexture();
446 
447  int w = srcRect.Width;
448  int h = srcRect.Height;
449  Color[] buffer = new Color[w * h];
450  //XnaRectangle srcScan = new XnaRectangle( 0, 0, w, 1 );
451  //Color[] scanline = new Color[w];
452 
453  //for ( rect.Y = 0; rect.Y < h; rect.Y++ )
454  //{
455  // src.xnaTexture.GetData<Color>( 0, rect, scanline, 0, w );
456  // dest.xnaTexture.SetData<Color>( 0, rect, scanline, 0, w );
457  //}
458 
459  src.xnaTexture.GetData<Color>( 0, srcRect, buffer, 0, w * h );
460  dest.xnaTexture.SetData<Color>( 0, destRect, buffer, 0, w * h );
461  }
462 
467  public void ApplyPixelOperation( Converter<Color, Color> operation )
468  {
469  Converter<XnaColor, XnaColor> newOp = delegate( XnaColor c )
470  {
471  return operation( new Color( c ) ).AsXnaColor();
472  };
473 
474  ApplyPixelOperation( newOp );
475  }
476 
481  internal void ApplyPixelOperation( Converter<XnaColor, XnaColor> operation )
482  {
483  DoInitTexture();
484  InvalidateAsset();
485 
486  XnaRectangle scanRect = new XnaRectangle( 0, 0, xnaTexture.Width, 1 );
487  XnaColor[] scanline = new XnaColor[xnaTexture.Width];
488 
489  for ( scanRect.Y = 0; scanRect.Y < xnaTexture.Height; scanRect.Y++ )
490  {
491  xnaTexture.GetData<XnaColor>( 0, scanRect, scanline, 0, xnaTexture.Width );
492 
493  for ( int j = 0; j < xnaTexture.Width; j++ )
494  {
495  scanline[j] = operation( scanline[j] );
496  }
497 
498  xnaTexture.SetData<XnaColor>( 0, scanRect, scanline, 0, xnaTexture.Width );
499  }
500 
501  UpdateTexture();
502  }
503 
509  private void InvalidateAsset()
510  {
511  if ( assetName == null )
512  return;
513 
514  Texture2D oldTex = xnaTexture;
515  CreateNewTexture();
516  CopyData( xnaTexture, oldTex );
517  assetName = null;
518  }
519 
520  private void UpdateTexture()
521  {
522  Game.DoNextUpdate( DoUpdateTexture );
523  }
524 
525  private void DoUpdateTexture()
526  {
527  if ( parentImage != null )
528  {
529  XnaRectangle srcRect = new XnaRectangle( 0, 0, Width, Height );
530  CopyData( parentImage, this, parentRectangle, srcRect );
531  parentImage.UpdateTexture();
532  }
533  }
534 
535  #region static methods
536 
542 #if !XBOX
543  public static Image FromFile( string path )
544  {
545  StreamReader sr = new StreamReader( path );
546  Image img = new Image( Texture2D.FromStream( Game.GraphicsDevice, sr.BaseStream ) );
547  return img;
548  }
549 
550 #endif
551 
557  public static Image FromFile( StorageFile file )
558  {
559  return FromStream( file.Stream );
560  }
561 
567  public static Image FromStream( Stream stream )
568  {
569  return new Image( Texture2D.FromStream( Game.GraphicsDevice, stream ) );
570  }
571 
572 #if WINDOWS
573  public static Image FromURL( string url )
579  {
580  HttpWebRequest request = (HttpWebRequest)WebRequest.Create( url );
581  HttpWebResponse response = (HttpWebResponse)request.GetResponse();
582  Stream resStream = response.GetResponseStream();
583 
584  MemoryStream memStream = new MemoryStream();
585  resStream.CopyTo( memStream );
586 
587  Image img = new Image( Texture2D.FromStream( Game.GraphicsDevice, memStream ) );
588  return img;
589  }
590 #endif
591 
600  public static Image CreateStarSky( int width, int height, int stars, bool transparent = false)
601  {
602  XnaColor[] textureColors = new XnaColor[width * height];
603 
604  // Background, black or transparent
605  int i = 0;
606  for ( int ver = 0; ver < height; ver++ )
607  {
608  for ( int hor = 0; hor < width; hor++ )
609  {
610  if (transparent) textureColors[i++] = XnaColor.Transparent;
611  else textureColors[i++] = XnaColor.Black;
612  }
613  }
614 
615  // Random stars
616  for ( int j = 0; j < stars; j++ )
617  {
618  int star = RandomGen.NextInt( 0, width * height );
619  int size = RandomGen.NextInt( 1, 5 );
620 
621  for ( int k = 0; k < size / 2; k++ )
622  {
623  XnaColor starcolor = RandomGen.NextColor( Jypeli.Color.White, new Color( 192, 192, 192, 255 ) ).AsXnaColor();
624 
625  if ( star + k < textureColors.Length )
626  textureColors[star + k] = starcolor;
627 
628  if ( size % 2 != 0 || size == 2 )
629  continue;
630 
631  int nextStar = star + k + width;
632 
633  if ( nextStar < ( width * height ) )
634  {
635  textureColors[nextStar] = starcolor;
636  }
637  }
638  }
639 
640  //Texture2D newTexture = new Texture2D( Game.GraphicsDevice, width, height, 1, TextureUsage.None, SurfaceFormat.Color );
641  Texture2D newTexture = new Texture2D( Game.GraphicsDevice, width, height, false, SurfaceFormat.Color );
642  newTexture.SetData<XnaColor>( textureColors );
643 
644  return new Image( newTexture );
645  }
646 
655  public static Image FromText( string text, Font font, Color textColor, Color backgroundColor )
656  {
657  if ( text == null )
658  text = "";
659 
660  var spriteBatch = new SpriteBatch( Game.GraphicsDevice );
661  var device = spriteBatch.GraphicsDevice;
662 
663  XnaV2 textDims = font.XnaFont.MeasureString( text );
664  int textw = ( textDims.X > 1 ) ? Convert.ToInt32( textDims.X ) : 1;
665  int texth = ( textDims.Y > 1 ) ? Convert.ToInt32( textDims.Y ) : 1;
666 
667  //RenderTarget2D rt = new RenderTarget2D( device, textw, texth, 1, device.DisplayMode.Format );
668  RenderTarget2D rt = new RenderTarget2D( device, textw, texth, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8 );
669 
670  //device.SetRenderTarget( 0, rt );
671  device.SetRenderTarget( rt );
672  device.Clear( ClearOptions.Target | ClearOptions.DepthBuffer, backgroundColor.AsXnaColor(), 1.0f, 0 );
673 
674  spriteBatch.Begin();
675  spriteBatch.DrawString( font.XnaFont, text, XnaV2.Zero, textColor.AsXnaColor() );
676  spriteBatch.End();
677 
678  //device.SetRenderTarget( 0, null );
679  device.SetRenderTarget( null );
680 
681  //return new Image( rt.GetTexture() );
682  return new Image( rt );
683  }
684 
695  public static Image DrawTextOnImage( Image img, string text, Vector position, Font font, Color textColor, Color backgroundColor )
696  {
697  if ( text == null )
698  text = "";
699 
700  var spriteBatch = new SpriteBatch( Game.GraphicsDevice );
701  var device = spriteBatch.GraphicsDevice;
702 
703  XnaV2 textDims = font.XnaFont.MeasureString( text );
704  int textw = ( textDims.X > 1 ) ? Convert.ToInt32( textDims.X ) : 1;
705  int texth = ( textDims.Y > 1 ) ? Convert.ToInt32( textDims.Y ) : 1;
706 
707  //RenderTarget2D rt = new RenderTarget2D( device, textw, texth, 1, device.DisplayMode.Format );
708  RenderTarget2D rt = new RenderTarget2D( device, img.Width, img.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8 );
709 
710  //device.SetRenderTarget( 0, rt );
711  device.SetRenderTarget( rt );
712  device.Clear( ClearOptions.Target | ClearOptions.DepthBuffer, backgroundColor.AsXnaColor(), 1.0f, 0 );
713 
714  float xpos = 0.5f * ( img.Width - textw ) + (float)position.X;
715  float ypos = 0.5f * ( img.Height - texth ) - (float)position.Y;
716 
717  spriteBatch.Begin();
718  spriteBatch.Draw( img.XNATexture, rt.Bounds, XnaColor.White );
719  spriteBatch.DrawString( font.XnaFont, text, new XnaV2( xpos, ypos ), textColor.AsXnaColor() );
720  spriteBatch.End();
721 
722  //device.SetRenderTarget( 0, null );
723  device.SetRenderTarget( null );
724 
725 
726  //return new Image( rt.GetTexture() );
727  return new Image( rt );
728  }
729 
738  public static Image DrawTextOnImage( Image img, string text, Font font, Color textColor )
739  {
740  return DrawTextOnImage( img, text, Vector.Zero, font, textColor, Jypeli.Color.Transparent );
741  }
742 
751  public static Image FromGradient( int imageWidth, int imageHeight, Color lowerColor, Color upperColor )
752  {
753  XnaColor lower = lowerColor.AsXnaColor();
754  XnaColor upper = upperColor.AsXnaColor();
755  XnaColor[] textureColors = new XnaColor[imageWidth * imageHeight];
756  int i = 0;
757 
758  for ( int ver = 0; ver < imageHeight; ver++ )
759  {
760  for ( int hor = 0; hor < imageWidth; hor++ )
761  {
762  textureColors[i++] = XnaColor.Lerp( upper, lower, ( (float)ver / (float)imageHeight ) );
763  }
764  }
765 
766  Texture2D newTexture = new Texture2D( Game.GraphicsDevice, imageWidth, imageHeight, false, SurfaceFormat.Color );
767  newTexture.SetData<XnaColor>( textureColors );
768  return new Image( newTexture );
769  }
770 
778  public static Image FromColor( int imageWidth, int imageHeight, Color color )
779  {
780  return Image.FromGradient( imageWidth, imageHeight, color, color );
781  }
782 
783  private static XnaColor[] MirrorLine( XnaColor[] scanline, int width )
784  {
785  XnaColor[] res = new XnaColor[width];
786  int l = 0;
787  int r = width - 1;
788 
789  while ( l < r )
790  {
791  res[l] = scanline[r];
792  res[r] = scanline[l];
793  l++; r--;
794  }
795 
796  if ( l == r )
797  {
798  // Center pixel
799  res[l] = scanline[l];
800  }
801 
802  return res;
803  }
804 
810  public static Image Mirror( Image image )
811  {
812  Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
813  XnaColor[] scanline = new XnaColor[image.Width];
814  var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
815 
816  for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
817  {
818  image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
819  scanline = MirrorLine( scanline, image.Width );
820  newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
821  }
822 
823  return new Image( newTex );
824  }
825 
831  public static Image[] Mirror( Image[] images )
832  {
833  Image[] result = new Image[images.Length];
834  for ( int i = 0; i < images.Length; i++ )
835  result[i] = Mirror( images[i] );
836  return result;
837  }
838 
844  public static Image Flip( Image image )
845  {
846  Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
847  XnaColor[] scanlineUpper = new XnaColor[image.Width];
848  XnaColor[] scanlineLower = new XnaColor[image.Width];
849  var scanRectUpper = new XnaRectangle( 0, 0, image.Width, 1 );
850  var scanRectLower = new XnaRectangle( 0, 0, image.Width, 1 );
851 
852  for ( int i = 0; i < image.Height / 2; i++ )
853  {
854  scanRectUpper.Y = i;
855  scanRectLower.Y = image.Height - 1 - i;
856 
857  image.XNATexture.GetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
858  image.XNATexture.GetData<XnaColor>( 0, scanRectLower, scanlineLower, 0, image.Width );
859 
860  newTex.SetData<XnaColor>( 0, scanRectUpper, scanlineLower, 0, image.Width );
861  newTex.SetData<XnaColor>( 0, scanRectLower, scanlineUpper, 0, image.Width );
862  }
863 
864  if ( image.Height % 2 == 1 )
865  {
866  // Center line
867  scanRectUpper.Y = image.Height / 2;
868  image.XNATexture.GetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
869  newTex.SetData<XnaColor>( 0, scanRectUpper, scanlineUpper, 0, image.Width );
870  }
871 
872  return new Image( newTex );
873  }
874 
880  public static Image[] Flip( Image[] images )
881  {
882  Image[] result = new Image[images.Length];
883  for ( int i = 0; i < images.Length; i++ )
884  result[i] = Flip( images[i] );
885  return result;
886  }
887 
894  public static Image Color( Image image, Color color )
895  {
896  Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
897  XnaColor[] scanline = new XnaColor[image.Width];
898  var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
899  XnaColor xnaColor = color.AsXnaColor();
900 
901  for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
902  {
903  image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
904 
905  for ( int i = 0; i < image.Width; i++ )
906  {
907  if ( scanline[i].A < 255 )
908  {
909  scanline[i].R = (byte)( ( 255 - scanline[i].A ) * xnaColor.R + scanline[i].A * scanline[i].R );
910  scanline[i].G = (byte)( ( 255 - scanline[i].A ) * xnaColor.G + scanline[i].A * scanline[i].G );
911  scanline[i].B = (byte)( ( 255 - scanline[i].A ) * xnaColor.B + scanline[i].A * scanline[i].B );
912 
913  if ( scanline[i].A > 10 )
914  {
915  scanline[i].A = color.AlphaComponent;
916  }
917  }
918  }
919 
920  newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
921  }
922 
923  return new Image( newTex );
924  }
925 
932  public static Image[] Color( Image[] images, Color color )
933  {
934  Image[] result = new Image[images.Length];
935  for ( int i = 0; i < images.Length; i++ )
936  result[i] = Color( images[i], color );
937  return result;
938  }
939 
940  public static Image Color( Image image, byte alpha )
941  {
942  Texture2D newTex = new Texture2D( image.XNATexture.GraphicsDevice, image.Width, image.Height, false, image.XNATexture.Format );
943  XnaColor[] scanline = new XnaColor[image.Width];
944  var scanRect = new XnaRectangle( 0, 0, image.Width, 1 );
945 
946  for ( scanRect.Y = 0; scanRect.Y < image.Height; scanRect.Y++ )
947  {
948  image.XNATexture.GetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
949  for ( int i = 0; i < image.Width; i++ )
950  {
951  scanline[i].A = alpha;
952  }
953  newTex.SetData<XnaColor>( 0, scanRect, scanline, 0, image.Width );
954  }
955  return new Image( newTex );
956  }
957 
958  public static Image TileHorizontal( Image left, Image right )
959  {
960  if ( left.Height != right.Height ) throw new InvalidOperationException( "Cannot tile two images with different height" );
961 
962  left.DoInitTexture();
963  right.DoInitTexture();
964 
965  XnaRectangle leftRect = new XnaRectangle( 0, 0, left.Width, left.Height );
966  XnaRectangle rightSrc = new XnaRectangle( 0, 0, right.Width, right.Height );
967  XnaRectangle rightDest = new XnaRectangle( left.Width, 0, right.Width, right.Height );
968 
969  Image tiled = new Image( left.Width + right.Width, left.Height );
970  tiled.InitTexture += delegate { CopyData( tiled, left, leftRect, leftRect ); };
971  tiled.InitTexture += delegate { CopyData( tiled, right, rightDest, rightSrc ); };
972 
973  return tiled;
974  }
975 
976  public static Image TileVertical( Image top, Image bottom )
977  {
978  if ( top.Width != bottom.Width ) throw new InvalidOperationException( "Cannot tile two images with different width" );
979 
980  top.DoInitTexture();
981  bottom.DoInitTexture();
982 
983  XnaRectangle topRect = new XnaRectangle( 0, 0, top.Width, top.Height );
984  XnaRectangle botSrc = new XnaRectangle( 0, 0, bottom.Width, bottom.Height );
985  XnaRectangle botDest = new XnaRectangle( 0, top.Height, bottom.Width, bottom.Height );
986 
987  Image tiled = new Image( top.Width, top.Height + bottom.Height );
988  tiled.InitTexture += delegate { CopyData( tiled, top, topRect, topRect ); };
989  tiled.InitTexture += delegate { CopyData( tiled, bottom, botDest, botSrc ); };
990 
991  return tiled;
992  }
993 
994  #endregion
995 
996  public Image Area( int left, int top, int right, int bottom )
997  {
998  int width = right - left;
999  int height = bottom - top;
1000 
1001  if ( width <= 0 ) throw new ArgumentException( "Left coordinate must be less than right coordinate" );
1002  if ( height <= 0 ) throw new ArgumentException( "Top coordinate must be less than bottom coordinate" );
1003 
1004  XnaRectangle srcRect = new XnaRectangle( left, top, width, height );
1005  XnaRectangle destRect = new XnaRectangle( 0, 0, width, height );
1006 
1007  Image areaImage = new Image( width, height );
1008  areaImage.parentImage = this;
1009  areaImage.parentRectangle = srcRect;
1010  areaImage.InitTexture += delegate { CopyData( areaImage, this, destRect, srcRect ); };
1011  return areaImage;
1012  }
1013 
1014  public void Fill( Color backColor )
1015  {
1016  DoInitTexture();
1017  InvalidateAsset();
1018 
1019  XnaRectangle rect = new XnaRectangle( 0, 0, xnaTexture.Width, 1 );
1020  Color[] scanline = new Color[xnaTexture.Width];
1021 
1022  for ( int i = 0; i < xnaTexture.Width; i++ )
1023  scanline[i] = backColor;
1024 
1025  for ( rect.Y = 0; rect.Y < xnaTexture.Height; rect.Y++ )
1026  xnaTexture.SetData<Color>( 0, rect, scanline, 0, xnaTexture.Width );
1027 
1028  UpdateTexture();
1029  }
1030 
1039  public void ReplaceColor( Color src, Color dest, double tolerance, bool blend, bool exactAlpha = false )
1040  {
1041  XnaColor srcColor = src.AsXnaColor();
1042  XnaColor destColor = dest.AsXnaColor();
1043  Converter<XnaColor, XnaColor> op = delegate( XnaColor c )
1044  {
1045  if ( exactAlpha && c.A != srcColor.A )
1046  return c;
1047 
1048  if ( JyColor.Distance( c, srcColor ) <= tolerance )
1049  {
1050  if ( !blend ) return destColor;
1051  Vector3 srcDist = new Vector3( c.R - srcColor.R, c.G - srcColor.G, c.B - srcColor.B );
1052  return new XnaColor( destColor.ToVector3() + srcDist );
1053  }
1054 
1055  return c;
1056  };
1057 
1058  ApplyPixelOperation( op );
1059  }
1060 
1066  public void ReplaceColor( Color src, Color dest )
1067  {
1068  XnaColor srcColor = src.AsXnaColor();
1069  XnaColor destColor = dest.AsXnaColor();
1070  Converter<XnaColor, XnaColor> op = delegate( XnaColor c )
1071  {
1072  return c == srcColor ? destColor : c;
1073  };
1074 
1075  ApplyPixelOperation( op );
1076  }
1077 
1083  public Stream AsJpeg()
1084  {
1085  DoInitTexture();
1086  MemoryStream jpegStream = new MemoryStream();
1087  XNATexture.SaveAsJpeg( jpegStream, Width, Height );
1088  jpegStream.Seek( 0, SeekOrigin.Begin );
1089  return jpegStream;
1090  }
1091 
1097  public Stream AsPng()
1098  {
1099  DoInitTexture();
1100  MemoryStream pngStream = new MemoryStream();
1101  XNATexture.SaveAsPng( pngStream, Width, Height );
1102  pngStream.Seek( 0, SeekOrigin.Begin );
1103  return pngStream;
1104  }
1105  }
1106 }
1107 
static Color UIntToColor(uint c)
Tekee kokonaisluvusta värin
Definition: Color.cs:261
Stream AsPng()
Palauttaa kuvan png-muodossa, jossa se voidaan esimerkiksi tallentaa DataStorage.Export -metodilla...
Definition: Image.cs:1097
void ReplaceColor(Color src, Color dest)
Korvaa värin toisella värillä.
Definition: Image.cs:1066
static Image Mirror(Image image)
Peilaa kuvan X-suunnassa.
Definition: Image.cs:810
static Image DrawTextOnImage(Image img, string text, Vector position, Font font, Color textColor, Color backgroundColor)
Piirtää tekstiä kuvan päälle.
Definition: Image.cs:695
static void DoNextUpdate(Action action)
Suorittaa aliohjelman seuraavalla päivityksellä.
Definition: Game.cs:642
Image(int width, int height, Color backColor)
Luo uuden kuvan.
Definition: Image.cs:337
static Image FromColor(int imageWidth, int imageHeight, Color color)
Luo yksivärisen kuvan.
Definition: Image.cs:778
static Image FromText(string text, Font font, Color textColor, Color backgroundColor)
Luo kuvan tekstistä.
Definition: Image.cs:655
void ApplyPixelOperation(Converter< Color, Color > operation)
Suorittaa annetun pikselioperaation koko kuvalle.
Definition: Image.cs:467
Microsoft.Xna.Framework.Rectangle XnaRectangle
Definition: Image.cs:9
static Image FromStream(Stream stream)
Lataa kuvan tiedostovirrasta.
Definition: Image.cs:567
Fontti.
Definition: Font.cs:22
static Image [] Flip(Image[] images)
Peilaa kuvat Y-suunnassa.
Definition: Image.cs:880
uint [][] GetDataUIntAA(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Palalutetaan kuvan pikselit ARGB-uint[][] -taulukkona
Definition: Image.cs:178
Satunnaisgeneraattori. Luo satunnaisia arvoja, mm. lukuja, vektoreita sekä kulmia.
Definition: RandomGen.cs:39
static Image [] Color(Image[] images, Color color)
Värittää kuvat.
Definition: Image.cs:932
int Width
Leveys pikseleinä.
Definition: Image.cs:290
static Image FromGradient(int imageWidth, int imageHeight, Color lowerColor, Color upperColor)
Luo pystysuuntaisen liukuväritetyn kuvan.
Definition: Image.cs:751
static Game Instance
Definition: Game.cs:149
static readonly Vector Zero
Nollavektori.
Definition: Vector.cs:61
void Fill(Color backColor)
Definition: Image.cs:1014
Kuva.
Definition: Image.cs:24
Image(double width, double height, Color backColor)
Luo uuden kuvan.
Definition: Image.cs:352
static Image TileHorizontal(Image left, Image right)
Definition: Image.cs:958
static int NextInt(int maxValue)
Palauttaa satunnaisen kokonaisluvun, joka on vähintään 0 ja pienempi kuin
Definition: RandomGen.cs:56
static Image [] Mirror(Image[] images)
Peilaa kuvat X-suunnassa.
Definition: Image.cs:831
void SetData(Color[,] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asettaa kuvan pikselit Color-taulukosta
Definition: Image.cs:112
void SetData(uint[][] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asetetaan kuvan pikselit ARGB-uint taulukosta
Definition: Image.cs:250
static readonly Color Transparent
Läpinäkyvä väri.
Definition: Color.cs:869
double Y
Definition: Vector.cs:275
Peliluokka reaaliaikaisille peleille.
Definition: DebugScreen.cs:10
static Image Color(Image image, Color color)
Värittää kuvan.
Definition: Image.cs:894
Image(Microsoft.Xna.Framework.Graphics.Texture2D texture)
Definition: Image.cs:324
static Image Color(Image image, byte alpha)
Definition: Image.cs:940
int Height
Korkeus pikseleinä.
Definition: Image.cs:298
string Name
Nimi.
Definition: Image.cs:306
static Image FromFile(StorageFile file)
Lataa kuvan tiedostosta. Kuvan ei tarvitse olla lisättynä Content-projektiin.
Definition: Image.cs:557
double X
Definition: Vector.cs:274
static Image FromFile(string path)
Lataa kuvan tiedostosta. Kuvan ei tarvitse olla lisättynä Content-projektiin.
Definition: Image.cs:543
Image Clone()
Definition: Image.cs:396
static new GraphicsDevice GraphicsDevice
Definition: Game.cs:368
static Image CreateStarSky(int width, int height, int stars, bool transparent=false)
Luo tähtitaivaskuvan.
Definition: Image.cs:600
static Color NextColor()
Palauttaa satunnaisen värin.
Definition: RandomGen.cs:163
static Image TileVertical(Image top, Image bottom)
Definition: Image.cs:976
byte AlphaComponent
Läpinäkymättömyys välillä 0-255
Definition: Color.cs:37
Väri.
Definition: Color.cs:13
void ReplaceColor(Color src, Color dest, double tolerance, bool blend, bool exactAlpha=false)
Korvaa värin toisella värillä.
Definition: Image.cs:1039
Color [,] GetData(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Kuvan pikselit Color-taulukkona
Definition: Image.cs:79
Stream AsJpeg()
Palauttaa kuvan jpeg-muodossa, jossa se voidaan esimerkiksi tallentaa DataStorage.Export -metodilla.
Definition: Image.cs:1083
Image Area(int left, int top, int right, int bottom)
Definition: Image.cs:996
2D-vektori.
Definition: Vector.cs:56
static Image DrawTextOnImage(Image img, string text, Font font, Color textColor)
Piirtää tekstiä kuvan päälle keskelle kuvaa.
Definition: Image.cs:738
static readonly Color White
Valkoinen.
Definition: Color.cs:894
uint [,] GetDataUInt(int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Palalutetaan kuvan pikselit ARGB-uint[,] -taulukkona
Definition: Image.cs:146
override int GetHashCode()
Definition: Image.cs:274
static Image Flip(Image image)
Peilaa kuvan Y-suunnassa.
Definition: Image.cs:844
void SetData(uint[,] bmp, int ox=0, int oy=0, int w=int.MaxValue, int h=int.MaxValue)
Asetetaan kuvan pikselit ARGB-uint taulukosta
Definition: Image.cs:214
Microsoft.Xna.Framework.Color XnaColor
Definition: Image.cs:11