Wednesday, May 14, 2008

Allocating Unmanaged Memory in Managed Code

I have been doing a bunch of interop stuff with unmanaged interfaces lately as part of an audio project I'm working on, so I have been dealing with unmanaged memory. While allocating unmanaged memory in C++ is fairly straightforward, I find programming in C++ to be pure misery. As a result, I dug around until I figured out how to do it in C#.

It all revolves around the Marshal class in System.Runtime.InteropServices. To allocate a chunk of unmanged memory, do:

 IntPtr myMemory = System.Runtime.InteropServices.Marshal.AllocHGlobal(numberOfBytes);

The 'IntPtr' is C#'s way of giving you a pointer reference. You can't do anything directly with it, but you can pass it around. The Marshall.Copy() function gives you a bunch of ways to copy chunks of various types of managed data to and from unmanaged data you have IntPtr references to.

What if you want to allocate a multi-dimensional unmanaged array? Things get a bit more complicated, but it can be done. Here is an example of allocating a 10 by 100 array of floats:
 int dimension1 = 10;
int dimension2 = 100;

IntPtr arrayPtr = Marshal.AllocHGlobal(dimension1 * Marshal.SizeOf(typeof(IntPtr)));
IntPtr dimension2Pointers = new IntPtr[dimension1];

for (int pos = 0; pos < dimension1; pos++)
{
dimension2Pointers[pos] = Marshal.AllocHGlobal(dimension2 * sizeof(float));
}

Marshal.Copy(dimension2Pointers, 0, arrayPtr, dimension1);

With a bit more work, you could probably avoid having to use the managed IntPtr array. In my case, though, I wanted managed pointers to both the full two-dimensional array as well as each of the individual one-dimensional arrays.

The use of Marshal.SizeOf() instead of sizeof() is because sizeof(IntPtr) is indeterminate unless you are in unsafe code.

Don't forget that this is all unmanaged memory, so you are responsible for freeing it using the corresponding Marshall.FreeHGlobal() call.

Friday, December 21, 2007

WPF Progress Bars

Implementing a progress bar display for long-running tasks is a commonly occurring task. WPF has a simple ProgressBar control which works as you would expect. It has a floating point Value property that is used to display progress within a range (set using the Minimum and Maximum properties). Here is some XAML to implement a progress dialog:

<Window x:Class="MyNamespace.ProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Progress Dialog" Width="300" SizeToContent="Height">
<Grid>
<StackPanel Margin="10">
<ProgressBar Name="Progress" Width="200" Height="20" Minimum="0" Maximum="1" Margin="10" />
<TextBlock Name="StatusText" Margin="10" Height="50"/>
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Name="CancelButton">Cancel</Button>
</StackPanel>
</StackPanel>
</Grid>
</Window>

The progress bar is set to take progress values from 0 to 1, and has a TextBlock for displaying a status message.

It might seem like we are finished, but it is only part of what you need for a functional progress dialog. In trying to use the dialog, you quickly run into a problem - how to avoid blocking the UI thread while your operation proceeds. In Windows Forms, a common cheat was to periodically call Application.DoEvents() to allow the UI to update. While you can do something similar in WPF, it is ugly and best avoided.

Instead, you should do your work asynchronously in a separate thread. Given that, the next question becomes how to update the UI from your second thread, as WPF UI operations are not thread-safe, and you will get an exception if you try to interact with a control outside of the thread in which it was created. The solution? Use the Dispatcher. The Dispatcher basically lets you queue up function calls on the UI thread from your background thread.

To manage this communication, we will first create an interface for interacting with a progress dialog:
public interface IProgressContext
{
void UpdateProgress(double progress);
void UpdateStatus(string status);
void Finish();
bool Canceled { get; }
}

The UpdateProgress() method allows us to set the current progress value, UpdateStatus() allows us to display a text status message, Finish() lets us signal that our operation has completed, and the Canceled property allows us to check if the user has canceled the operation.

Now, the code-behind for the dialog:
public partial class ProgressDialog : Window, IProgressContext
{
private bool canceled = false;

public bool Canceled
{
get { return canceled; }
}

public ProgressDialog()
{
InitializeComponent();

CancelButton.Click += new RoutedEventHandler(CancelButton_Click);
}

void CancelButton_Click(object sender, RoutedEventArgs e)
{
canceled = true;
CancelButton.IsEnabled = false;
}

public void UpdateProgress(double progress)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Progress.SetValue(ProgressBar.ValueProperty, progress); }, null);
}

public void UpdateStatus(string status)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { StatusText.SetValue(TextBlock.TextProperty, status); }, null);
}

public void Finish()
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Close(); }, null);
}
}

As you can see, we are basically just implementing the IProgressContext interface. We use the dispatcher to send along our progress updates to the UI thread. To use the dialog, launch a background thread to do your work, passing it a progress dialog as IProgressContext. Your work loop will look something like this:
for (int i = 0; i < 100; i++)
{
if (myProgressContext.Canceled)
break;

myProgressContext.UpdateProgress((double)i / 100.0);
myProgressContext.UpdateStatus("Doing Step " + i);
}

myProgressContext.Finish();

You can obviously get more fancy with your dialog - this is just a simple implementation to get started with.

Wednesday, December 12, 2007

Drag and Drop in WPF

Drag and Drop in WPF is, I think, more complex than it should be. I've had to implement it a few times now, so I recently put together a simple helper class that simplifies things.

The full class code follows at the end of the post, but first I will give a few examples of using it. If you have an object that you want to be draggable, just create a DragDropHander object for it:

DragDropHandler dragDrop = new DragDropHandler(myControl, new System.Windows.DataObject(myDragData));
Where "myControl" is the WPF control the use will drag from, and "myDragData" is the object you wish to receive on the other end of the drag and drop. To receive the drop, make sure the control you want to drop to has AllowDrop set, and add a drop handler in your control initialization:
MyControl.Drop += new DragEventHandler(MyControl_Drop);

Implement the handler like this:
void MyControl_Drop(object sender, DragEventArgs e)
{
MyDataType myData = (MyDataType )e.Data.GetData(typeof(MyDataType).ToString());

// Do something with the dropped object
}
If you want to drag an object outside of your application, you need to create the appropriate DataObject. A common case is a filename. To create a drag handler that drags a filename, do:
DragDropHandler dragDrop = new DragDropHandler(myControl, new System.Windows.DataObject(DataFormats.FileDrop, new string[] { myPath }));
You can obviously get much more complicated with drag and drop - handling drag enter/over/leave events and using adorners to visually display drag data, for example. This should get you started, though, and probably is sufficient for most needs.

Here is the full DragDropHandler class implementation:
using System;
using System.Windows.Data;
using System.Windows;
using System.Windows.Input;

namespace MyCoolNamespace
{
public class DragDropHandler
{
private FrameworkElement dragElement = null;
private bool dragging = false;
private bool inDragDrop = false;
private Point dragStart;
private DataObject dataObject = null;

public DragDropHandler(FrameworkElement dragElement, DataObject dataObject)
{
this.dragElement = dragElement;
this.dataObject = dataObject;

dragElement.MouseLeftButtonDown += new MouseButtonEventHandler(dragElement_MouseLeftButtonDown);
dragElement.MouseMove += new MouseEventHandler(dragElement_MouseMove);
}

void dragElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!dragElement.IsMouseCaptured)
{
dragging = true;
dragStart = e.GetPosition(dragElement);
}
}

void dragElement_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
Point currentPos = e.GetPosition(dragElement);

if ((Math.Abs(currentPos.X - dragStart.X) > 5) || (Math.Abs(currentPos.Y - dragStart.Y) > 5))
{
dragElement.CaptureMouse();

inDragDrop = true;
DragDropEffects de = DragDrop.DoDragDrop(dragElement, dataObject, DragDropEffects.Move);
inDragDrop = false;
dragging = false;
dragElement.ReleaseMouseCapture();
}
}
}
}
}

WPF ListView - Getting the Clicked Item

I recently had the need to figure out which item in a WPF ListView was under the mouse when it was clicked. The solution wasn't completely straightforward, so I thought I'd post it here.

First, obviously you need to register a mouse button event hander in your control initialization. In this case, I'm using a double-click event:

MyListView.MouseDoubleClick += new MouseButtonEventHandler(MyListView_MouseDoubleClick);
and then implement the event handler like such:
void MyListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;

while ((dep != null) && !(dep is ListViewItem))
{
dep = VisualTreeHelper.GetParent(dep);
}

if (dep == null)
return;

MyDataItemType item = (MyDataItemType)MyListView.ItemContainerGenerator.ItemFromContainer(dep);

// Do something with the item...
}
What we are doing is walking up the visual tree starting at the element the generated the mouse event. We stop when we find a ListViewItem, which we can then use to get the corresponding data item. If all you want is the index of the item, use IndexFromContainer() instead.

Monday, December 3, 2007

C# Xml List Serialization Behavior

Xml serialization in C# is, for the most part, simple and transparent. Public properties of your objects are automatically written to and read from a corresponding Xml representation. Usually this happens exactly as you would expect, but there are a few gotchas in serialization of lists.

Take this example object:

public class XmlTest
{
private List<int> integerList = new List<int> { 1, 2, 3 };

public List<int> IntegerList
{
get { return integerList; }
set { integerList = value; }
}
}


We have a single property which is a list of integer values. If we create an object and serialize it:

XmlTest xmlTest = new XmlTest();
TextWriter writer = new StreamWriter("test.xml");
XmlSerializer serializer = new XmlSerializer(typeof(XmlTest));
serializer.Serialize(writer, xmlTest);
writer.Close();


we get the following Xml, just like we would expect:

<?xml version="1.0" encoding="utf-8"?>
<XmlTest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IntegerList>
<int>1</int>
<int>2</int>
<int>3</int>
</IntegerList>
</XmlTest>


But when we deserialize the generated Xml like so:

FileStream fs = new FileStream("test.xml", FileMode.Open);
XmlReader reader = new XmlTextReader(fs);
xmlTest = (XmlTest)serializer.Deserialize(reader);
fs.Close();


we get a surprise. The integer list in the deserialized object has 6 items rather than three. The list ends up being "1, 2, 3, 1, 2, 3". Why is this? It has to do with the details of how lists are deserialized. If you put a breakpoint in the "set" of the IntegerList property, you will find that it never gets called during deserialization. Instead, it seems that the .NET deserializer uses "get" to access the property, and then calls "Add()" to deserialize the list items. Because we initialize the list to "1, 2, 3", those items are already there before adding the items from the Xml.

I don't know that I am prepared to call this behavior "wrong", but it certainly was unexpected for me. Ideally, serializing and then deserializing an object would result in the exact same data. In this case, not so much.

A better behavior, I think, would be for the deserialzer to creat a new list, populate it from the Xml, and then call my property's "set" method to hook it into my object. This also would allow you to put business logic in your property and have it survive serialization. At the very least, it would probably make sense to clear the list before adding items during deserialization.

Thursday, November 29, 2007

iPod Hacking



Ever since I first wrote Grip and DigitalDJ back in the late 90's, I have always maintained my own software for managing my digital music collection. My current incarnation is a C# application with a WPF user interface and a custom streaming server that sends music to my Xbox running Xbox Media Center.

My music lives on a linux box in my office closet. Since I am soon going to be traveling extensively, I needed a way to get my music portable. I had an 80gb iPod still in the shrink-wrap from company xmas present excess when I worked at DefenseWeb. My current music collection is around 45gb, so that seemed like a good solution.

The problem is that the iPod, while mounting like a normal USB drive, uses a messed up, proprietary method of storing music. Finding a way to interact with the iPod's music database in my language of choice (C#) proved difficult.

Enter Rockbox. Rockbox is alternative firmware for many portable music players, including the Ipod. Most importantly, it stores music as a simple, straightforward filesystem. This allows for easy synchronization of music using my custom software, and easy playback directly on the device, or using the device as a USB filesystem.

Rockbox proved very easy to install. After some initial frustration with the automated installer (don't use it), I quickly installed it manually. The default look is pretty nasty, but there are lots of themes available. I'm currently using the "Black Glass AA" theme, which displays album art if you have it (you simple need to put 100x100 "cover.bmp" files in each album directory).

Tuesday, November 13, 2007

3D Landscape Rendering With Texture Splatting



The above image is from a project I'm working on at the moment. It took a bit of research and trial and error to get to this point, so I thought I would take a moment to share some of what I've learned along the way.

One of the key elements of many types of 3D games is rendering realistic-looking landscapes, and one of the key elements of rendering a realistic-looking landscape is being able to texture the landscape so it looks good both at a distance and up close, all without completely killing the framerate. A technique known as texture splatting allows us to do just that.

But first, a few landscape basics. A rendered landscape has two basic elements -- an elevation, or height map and texturing. The information for both of these can be generated by a landscape generation program. The one I use is a fantastic program called L3DT. It uses all sorts of fancy techniques to generate realistic looking terrain, and can output a number of useful data files that can be used inside a 3D engine to display the landscape.

First, the height map. This is generally exported as a grayscale image, with lighter areas being higher in elevation. Here is an example:



L3DT can also generate a corresponding texture image that represents the type of the terrain and also bakes in lighting information:



Using just these two images, we can already generate a pretty decent 3D visualization of the landscape. All we do is create a terrain mesh based on the height map and stretch the texture image completely over it. The result is something like this:



Looks pretty good, right? Well, there is a problem. It looks good at a distance because we are seeing the texture image at roughly it's actual resolution. When we render up close it is a different story altogether:



Not so hot. The texture image just doesn't have enough resolution to show detail up close. We could increase the resolution of the texture, but that quickly breaks down -- it simply takes too much memory in the graphics card.

This is where texture splatting comes in. What we want to do is supplement the high-level texture with some low-level details. To do this, we render some number of tiled-texture detail layers on top of the high-level texture. Each detail layer alpha-blended with the rest using an alpha map that represents the "amount" of the detail texture at any given point on the landscape. As a simple example, lets say that we have two detail textures -- grass and rock. Here are the two alpha maps, one for each, that can be used to control the texture splatting, along with an example subregion of the grass and rock detail textures I am using:




In the alpha maps, lighter areas mean more of the texture, with white being solid and black being fully transparent. These simple alpha maps will result in a landscape that is half grass and half rock, with a transition in the middle. If we use these alpha maps and apply them to our height map from earlier, we get this:



Kind of silly looking, but I hope it serves as a good example to understand how the alpha maps determine how the textures are rendered on the landscape.

For a real example, however, we will want alpha maps that match our landscape texture. Fortunately, L3DT can export these as well. For each terrain type L3DT is using to generate the landscape, it can export an alpha map that represents the density of that kind of terrain. For example, here is the grass density map it generates:



As you can see, we have grass all over the island area except for certain steep sections that contain rock. One thing to note here is that I have slightly modified the alpha map L3DT produces by taking the brightness down by about a quarter. This is so that we will still be able to see the high-level texture under the splatting layer.

Here is the result with splatting. I am using three splatting layers -- grass, rock and sand (which you can see a bit on the shore).



As you can see, we have nice details up close, while still retaining the color variation and shadowing from the high-level texture. By using the high-level texture as a base, you can often get by with just a few splatting layers. They only need to be used to highlight textural differences, not color differences since the color variation is provided by the high-level texture base. Here is an example of this:



You can see the rock texture blend into the grass texture. This is caused by the alpha maps. The variation in lightness within the rock area, however, just comes from color variation in the high-level texture base.

That's it. Hopefully this helped to explain what texture splatting is, why it is useful and how you use it.

Some additional notes:

  • How to actually *do* the splatting: Your best bet is to use an engine that supports it. I use Truevision3d. Failing that, you'll need to implement a splatting shader yourself that blends the base texture with the splatting layers while tiling the detail textures.
  • Notes on detail textures: Use high-contrast textures with a lot of fine detail. Avoid textures with high-level variation in them or you will see tiling patterns on your landscape.
  • About the water: The water in the pictures uses a modified version of Zak's Ocean Shader. Thanks, Zak!
  • About the sky: It is a skybox rendered with Terragen.
  • About the trees and grass in the first picture: The trees are just individual meshes. The grass is billboarded (rectangular textures that are rotated to always face the camera) using a custom groundcover system.
  • How to use splatting in Truevision3d: I'll write up an example soon.