NomenNescio
NomenNescio

Reputation: 3030

WriteableBitmap Backbuffer not applying to image

I'm drawing on the backuffer of a writeablebitmap, and the applying it to the image but the image is not updating for some reason.

I've checked in the memory and the backbuffer values are changed, but setting the source of the image to the writeablebitmap doesn't change anything. The screen stays black.

Here is my program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace RayTracer
{
  class Main : Application
  {

    Window mainWindow;
    protected override void OnStartup(StartupEventArgs e)
    {
      base.OnStartup(e);
      CreateAndShowMainWindow();
    }

    public void CreateAndShowMainWindow()
    {
      mainWindow = new Window();
      mainWindow.Title = "Writeable Bitmap";
      mainWindow.Height = 480;
      mainWindow.Width = 640;
      mainWindow.ResizeMode = ResizeMode.NoResize;

      mImage = new Image();
      mWriteableBitmap = new WriteableBitmap(640, 480, 96, 96, PixelFormats.Rgb24, null);

      mImage.Stretch = Stretch.None;
      mImage.Margin = new Thickness(0);

      mBytesPerPixel = (mWriteableBitmap.Format.BitsPerPixel + 7) / 8;
      mStride = mWriteableBitmap.PixelWidth * mBytesPerPixel;

      StackPanel myStackPanel = new StackPanel();
      myStackPanel.Orientation = Orientation.Vertical;
      myStackPanel.Height = 480;
      myStackPanel.VerticalAlignment = VerticalAlignment.Top;
      myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;

      myStackPanel.Children.Add(mImage);

      mainWindow.Content = myStackPanel;
      mainWindow.Show();

      DispatcherTimer dispatcherTimer = new DispatcherTimer();
      dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
      dispatcherTimer.IsEnabled = true;
      dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
      dispatcherTimer.Start();
    }

    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
      for (int i = 0; i < 480; i++)
      {
        for (int j = 0; j < 640; j++)
        {
          setPixel(j, i, Color.FromRgb(255, 255, 255));
        }
      }
      mImage.Source = mWriteableBitmap; // image should be white but stays black
    }

    private Image mImage = null;
    private WriteableBitmap mWriteableBitmap = null;

    private int mBytesPerPixel = 0;
    private int mStride = 0;


    void setPixel(int x, int y, Color c)
    {
      int posX = x * mBytesPerPixel;
      int posY = y * mStride;
      unsafe
      {
        byte* backBuffer = (byte*)mWriteableBitmap.BackBuffer;
        backBuffer[posY + posX] = c.R;
        backBuffer[posY + posX + 1] = c.G;
        backBuffer[posY + posX + 2] = c.B;
      }
    }

    void clearScreen()
    {
      int totalBytes = mStride * 480;

      unsafe
      {
        byte* backBuffer = (byte*)mWriteableBitmap.BackBuffer;
        for (int i = 0; i < totalBytes; i++)
        {
          backBuffer[i] = 255;
        }
      }
    }
  }


  internal static class EntryClass
  {
    [System.STAThread()]
    private static void Main()
    {
      Main app = new Main();
      app.Run();
    }
  }
}

Upvotes: 0

Views: 2062

Answers (1)

Clemens
Clemens

Reputation: 128136

From the Remarks on the BackBuffer MSDN page:

Update the back buffer only between calls to the Lock and Unlock methods. If you do not follow the Lock/Unlock workflow described in the WriteableBitmap class remarks, undefined behaviors, such as tearing, can occur.

So your Tick handler should look like this:

private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    mWriteableBitmap.Lock();

    for (int i = 0; i < 480; i++)
    {
        for (int j = 0; j < 640; j++)
        {
            setPixel(j, i, Color.FromRgb(255, 255, 255));
        }
    }

    mWriteableBitmap.AddDirtyRect(new Int32Rect(0, 0,
        mWriteableBitmap.PixelWidth, mWriteableBitmap.PixelHeight));
    mWriteableBitmap.Unlock();

    mImage.Source = mWriteableBitmap; // image is white now
}

Upvotes: 2

Related Questions