2005.11.30 06:37 PM

DirectAnimation via Interop

(updates below)

I recently had to investigate whether it is possible to use the Microsoft DirectAnimation ActiveX control (DirectAnimationCtl.DAViewerControlWindowed via damin.dll) and some DirectX Image Transforms (DXImageTransform.Microsoft.Wipe via dxtmsft.dll) together in a .NET Windows Forms application via interop. While I discovered that it is indeed possible, I also found that the messy multi-interface-based interop wrappers generated by .NET for these libraries make an already difficult, obscure, and largely undocumented situation even worse.

Short of providing access to my sample code (here's a ZIP file containing the C# project and binares) and showing the significant code below, there's not much for me to add. I'm not an expert on DirectX or DirectAnimation, and until I tackled this little project I had never used the latter in a winforms application. My only previous exposure to DirectAnimation was in Internet Explorer, which is where I think it was originally intended to be used. If you're looking for resources, here are some links to get you started:

DirectX Media: Multimedia Services for Microsoft Internet Explorer and Microsoft Windows
Adding Theatrical Effects to Everyday Web Pages with DirectAnimation (from 1997!)
Multimedia Extensions to HTML+TIME
Internet Explorer, DHTML Behaviors, anim:DA Element | anim Behavior

So, after generating the interop libraries for the above named components and referencing them in my project, I added an instance of the (now) AxHost-based DAViewerControlWindowed to my form and added the following sample image wiping transformation logic to my button's click event:

using DirectAnimation;
using DXTMSFTLib;

...

private void ShowWipeButton_Click(object sender, System.EventArgs e) {

  // AxDAViewer refers to the AxHost-based DirectAnimation interop object
  // placed on the form.

  if (AxDAViewer.Image != null) {
    AxDAViewer.Stop();
  }
  
  DAStatics mlStatics = (DAStatics)AxDAViewer.MeterLibrary;
  
  IDAImage[] inputs = new IDAImage[2];
  inputs[0] = mlStatics.ImportImage(@"http://www.ewbi.com/ewbi.develop/graphics/dasample.ready.jpg");
  inputs[1] = mlStatics.ImportImage(@"http://www.ewbi.com/ewbi.develop/graphics/dasample.fire.jpg");
  
  DANumber forward = mlStatics.Interpolate(0, 1, 2.5);
  DANumber backward = mlStatics.Interpolate(1, 0, 2.5);
  DABehavior wipeEvaluator = mlStatics.Sequence((DABehavior)forward, (DABehavior)backward).RunOnce();
  
  DXTWipeClass wipeEffect = new DXTWipeClass();
  wipeEffect.GradientSize = .5F;
  wipeEffect.WipeStyle = DXWIPEDIRECTION.DXWD_VERTICAL;
  
  IDADXTransformResult txResult = mlStatics.ApplyDXTransform(wipeEffect, inputs, wipeEvaluator);
  
  AxDAViewer.Image = (IDAImage)txResult.OutputBvr;
  AxDAViewer.Start();
  
}

Success, but it took a lot of trial and error to get the variable types correct (notice all the casting - yuck). Note also that the components I generated the interop libraries against were both version 6.3 on Windows XP SP1. If you've got something different, I have no idea whether they'll work.

Good luck!


Update 4/25/2006 4:23:00PM

Based on a comment from Tom, I updated the sample project to include a wiping slideshow example. Here's the relevant code:

private void ShowSlideshowButton_Click(object sender, System.EventArgs e) {

  // Continuous slideshow with wipe, which requires two images, but can be made to work  
  // using every-other sets with matched delays.

  if (AxDAViewer.Image != null) {
    AxDAViewer.Stop();
  }
  
  string[] pictures = new string[6];
  
  pictures[0] = @"http://www.ewbi.com/ewbi.develop/graphics/1.jpg";
  pictures[1] = @"http://www.ewbi.com/ewbi.develop/graphics/2.jpg";
  pictures[2] = @"http://www.ewbi.com/ewbi.develop/graphics/3.jpg";
  pictures[3] = @"http://www.ewbi.com/ewbi.develop/graphics/4.jpg";
  pictures[4] = @"http://www.ewbi.com/ewbi.develop/graphics/5.jpg";
  pictures[5] = @"http://www.ewbi.com/ewbi.develop/graphics/6.jpg";
  
  int delay = 2;
  int len = (int)Math.Floor(pictures.Length/2); 
  
  DAStatics mlStatics = (DAStatics)AxDAViewer.MeterLibrary;
  
  ArrayList inputs1 = new ArrayList();
  ArrayList inputs2 = new ArrayList();
  int i = 0;
  for (; i < len; i++) {
    inputs1.Add(mlStatics.ImportImage(pictures[2*i]));
    inputs2.Add(mlStatics.ImportImage(pictures[2*i+1]));
  }
  inputs1.Add(mlStatics.ImportImage(pictures[((pictures.Length < (2*i)) ? (2*i) : 0)]));

  IDAArray inputarray1 = mlStatics.Array(inputs1.ToArray());
  IDAArray inputarray2 = mlStatics.Array(inputs2.ToArray());
        
  DANumber index = (DANumber)mlStatics.Interpolate(.5, len+.5, len*2*delay).RepeatForever();
  DANumber index2 = (DANumber)mlStatics.Interpolate(0, len, len*2*delay).RepeatForever();
  
  DABehavior[] wipePics = new DABehaviorClass[2];
  wipePics[0] = inputarray1.NthAnim(index);
  wipePics[1] = inputarray2.NthAnim(index2);      
  
  DANumber forward = mlStatics.Interpolate(0, 1, delay);
  DANumber backward = mlStatics.Interpolate(1, 0, delay);
  DABehavior wipeEvaluator = mlStatics.Sequence((DABehavior)forward, (DABehavior)backward).RepeatForever();

  DXTWipeClass wipeEffect = new DXTWipeClass();
  wipeEffect.GradientSize = .5F;
  wipeEffect.WipeStyle = DXWIPEDIRECTION.DXWD_HORIZONTAL;
        
  IDADXTransformResult txResult = mlStatics.ApplyDXTransform(wipeEffect, wipePics, wipeEvaluator);
  
  AxDAViewer.Image = (IDAImage)txResult.OutputBvr;
  AxDAViewer.Start();

}


Comments

This is areally good sample. Thanks. The problem is I need to show multiple images as in a slide show. I've been at it for 6 hours now and am stumped. Any Ideas?

THX

Tom | 2006.04.12 05:06 PM

Tom - Sorry for the delay, I'm overloaded at the moment. I will try to look closer at your question next week.

ewbi.develops | 2006.04.14 05:12 PM

Tom - Hope you make it back to check this out. I added a wipe-based slideshow button and handler to the sample project linked to in the post above. It shows how to pass more than 2 pictures through the 2-pic wipe effect using matched delays. Good luck.

ewbi.develops | 2006.04.25 04:09 PM

Thanks for the sample code. It was really useful! I'd like to add that if this doesn-t work for the user, and they see a blue turquoise rectangle instead, they need to do 1 or 2 things:

1. Set screen depth to a lower value (like 16 bits, vs. 32 bits) via control panel Display Settings applet.

2. Disable DirectDraw acceleration via dxdiag.exe

I was totally stumped why this would work on some machines and not others until I exhausted all other possibilities and ran across this one. On some machines, at certain resolutions DD accel apparently does not work or is not supported by the hardware and this causes silent failures.

Cheers,
Brian

Brian W | 2007.11.05 07:20 AM

Thanks for sharing that info, Brian.

ewbi.develops | 2007.11.05 09:41 AM


TrackBack

TrackBack URL:  https://www.typepad.com/services/trackback/6a00d8341c7bd453ef00d834b7a96f69e2

Listed below are links to weblogs that reference DirectAnimation via Interop: