Search code examples
xnadrawpixelmonogametexture2d

How to draw on the fly 2D pixel-by-pixel in MonoGame/XNA?


I was wondering how to draw on the fly pixel by pixel in XNA/MonoGame and could only find this. Problem is, the question wasn't centered about how to actually draw pixel by pixel but rather manage resources and updating stuff.

Because I couldn't find any simple and short answer and was wondering how to do for some time now, I'll share a snippet I stumbled upon (see answer).

NB: If anyone having a better approach or an alternative method to do it, feel free to post or comment!


Solution

  • Declare a class level variable for your texture and sizes:

    Texture2D Tex, Tex1, Tex2;
    const int WIDTH = 32;
    const int HEIGHT = 32;
    Color[] TexSource = new Color[WIDTH * HEIGHT];
    

    Initialize the variables in LoadContent()

    int radius = 5;
    point center = new Point(WIDTH >> 2, HEIGHT >> 2);
    Tex = new Texture2D(GraphicsDevice, WIDTH, HEIGHT);
    for(int x = 0 ; x < WIDTH; x++)
      for(int y = 0 ; y < HEIGHT; y++)
        if(Math.Sqrt((x - center.x)* (x - center.x)) < radius && Math.Sqrt((y - center.y) * (y - center.y) < radius))
           TexSource[x + y * WIDTH] = Color.Red;
        else
           TexSource[x + y * WIDTH] = Color.White;
      Tex = SetData<Color>(TexSource);    
      //The resulting texture is a red circle on a white background.
    
      //If you want to draw on top of an existing texture Tex1 as Tex2:
      Tex1 = Content.Load<Texture2D>(Tex1Name);
      Tex2 = new Texture2D(GraphicsDevice, Tex1.Width, Tex1.Height);
      TexSource = Tex1.GetData<Color>();
      // Draw a white \ on the image, we will assume tex1 is square for this task
      for(int x = 0 ; x < Tex1.Width; x++)
        for(int y = 0 ; y < Tex1.Width; y++)
           if(x==y) TexSource[x + y * Tex1.Width] = Color.White;
    
    

    You may change the textures in Update()

    But, never create or modify a texture in Draw() ever.

    The SpriteBatch.Draw() call expects the GraphicsDevice buffer to contain all of the texture data (by extension to the GPU buffer), any changes still happening(from Update and IsRunningSlowly == true) at this point will cause tearing when rendered.

    The workaround of GraphicsDevice.Textures[0] = null; blocks the Draw call and the game until transfer to the GPU is complete, thus slowing the entire game loop.