Welcome to MSDN Blogs Sign in | Join | Help

Gundam Astray Red Frame

Here are some shots of my first Gundam model.

Gundam Astray Red Frame gallery

It's a Gundam Astray Red Frame in 1/100 scale. The color scheme calls for a bright red for the frame but I wanted to experiment with something darker so I went for Hull Red which I then went over in Clear Red because it wasn't red enough. The result is a kind of chocolate color and I'm still not sure I like it. Most of the panel lines were done with oil paint and mineral spirits and took a very long time to clean up. Then, right at the end, I tried Copic Multi Liner inking pens which give a great result very quickly. In future I'll use those and/or my Koh-I-Noor Rapidograph pens which I haven't tried yet.

Airfix 1:48 Hawker Hurricane Mk I

Kit

I bought the kit for about $13 from the local HobbyTown USA store in Redmond Town Center early in 2007. Prior to that, it must have been nearly thirty years since I'd bought and built a plastic scale model kit and that would have almost certainly been an Airfix one too, probably from a model shop in Wakefield, Yorkshire . Most of the kits in the Redmond store are by Tamiya, Dragon, Hasegawa, Revell, Italeri and Bandai so I was surprised when I saw this kit and was reminded of the familiar brand from my youth. The kit isn't particularly well detailed compared to, say, the Hasegawa Hurricane Mk II kit. But the Hasegawa is nearly twice as expensive.

As a kid, my kit builds were a mess. I'd get polystyrene cement smeared on surfaces and canopies, there'd be gaps in the seams, I wouldn't be surprised if once or twice I slapped my decals on first and then tried to paint around them! Building and painting were always fun, but rushed, processes. Now I've finished my first model as an adult and I see that the polystyrene pieces in the box provide a canvas (a three-dimensional one: in some ways as blank and daunting as a real canvas, in other ways as simple as painting-by-numbers) that challenges the modeler to dress it up in the illusion of a real painted, dirtied and worn 1:1 scale object.

Build

I first washed the sprues with dish soap, rinsed and dried them. I used a Squadron sprue nipper to remove the pieces from their sprue. It stayed sharp for this project but it got blunt surprisingly quickly during the next. I tried sharpening it with a Dremel grinding stone but I wasn't happy with the result. So I tried a pair of diagonal cutting pliers which are shown in the photograph. As soon as I felt the effortless and precise action of the pliers, the nippers went straight in the waste basket.

There was a lot of flash on the kit's pieces so I did a lot of scraping (with a craft knife) and sanding during the build. Similarly the fuselage, wings and tail all needed a lot of filling and sanding to smooth out the seams. For filler I used Squadron white putty and a cocktail stick. The pieces were joined with Model Master Liquid Cement For Plastic Models and I used Staples rubber bands to hold the halves of the fuselage together while the cement dried.

Paint

I'd had to paint the cockpit during the build. I gave it a coat of flat black first to act as shadows, then went over that with dark green on a fairly dry brush. Finally I gave it a little shading and character with various shades of Doc O'Brien's weathering powders.

Before proceeding I wiped the model down with Polly S plastic prep and then airbrushed it with white primer. The color scheme I chose was that of No.85(F) squadron, RAF Advance Striking Force, Lille/Seclin, France, April 1940.

I used Tamiya acrylic flat earth and dark green for the upper side camouflage pattern and it took me several attempts probably due to my inexperience with an airbrush. I don't know if it was because I wasn't cleaning it properly or whether I didn't have the paint thickness and air pressure well enough matched but I had several performance problems with the Badger airbrush. The main issue was controlling the color: far too often I'd get either all or nothing out of it, and the needle is prone to sticking in the fully open position. The Paasche airbrush (the red one in the photograph below) hasn't given me any such problems so far and it feels far more smooth, robust and precise in use. In future I'll use the Badger for clear coats and perhaps for primer and the Paashe for controlled painting.

To smooth down my poor paint job I used 400 grade sandpaper which had the unfortunate side effect of taking off some panel lines on the left wing. I also used Tamiya polishing compound on a painter's rag and I think that helped to even out and subdue the gradients between the two colors. The flat black and white underside required some masking in order to get a straight line down the center of the undercarriage. I began by painting the white half.

Despite my masking efforts, some white paint managed to get through creases in the polythene onto the fuselage and tail fin and had to be touched up. I couldn't face masking up again for the black half so I just hand-brushed that with some care. There is, predictably, a world of difference in finish and smoothness between the airbrushed and hand-brushed halves as you can see in the photograph below. More polishing helped but I think I learned my lesson there. As it happens, though, you may not notice any real consequence of my impatience when you see the final photographs at the end.

To seal the paint and prepare the model with a gloss surface for the decals, I applied a generous coat of Future floor finish from the airbrush.

In remorse for my earlier mask-avoidance, I spent some time doing some sterile-drape-looking masking for a little airbrushing on the wing roots. I guess modeling is a little like surgery at times; more evidence of that in the following section.

Repair and customize

According to research I did, the kit had located the hole for the foot stirrup in the wrong place, and the directions show it being mounted perpendicular to the fuselage instead of parallel with it. I filled the existing hole with putty and made a new one with a drill bit in a pin vise. I used the same tool to make a hole in the top of the tail fin to take a small aerial mast which I made from some heat-stretched sprue. For the aerial itself I stretched cotton twine between the two masts and another from the forward mast to the fuselage.

I decided to model the kit with the canopy open so I cut the canopy in two with a razor saw then carved the fuselage so that the rear portion of the canopy would sit down well in its retracted position. In the earlier photograph of the unpainted fuselage the light green area behind the seat is the area I stripped back with a craft knife and sandpaper.

Probably the trickiest surgical job I did was repairing a wheel strut. There are four objects in the following photograph. On the left is a wheel strut from the kit which I was lucky enough to find undamaged on the carpet beside my dogs. Doubtless it got there due to some carelessness of mine. To the right of that is a damaged kit strut I found in the mouth of one of my dogs. The wheel end had been chewed off raggedly but by the time I took this photograph I'd already beveled the end in anticipation of repairing it with a new fragment. The next object is an example of the type of sprue piece I used to carve and sand the strut fragment taking shape on the right.

Then it was a case of splicing together the two pieces. I beveled off the new strut fragment and glued it to the damaged kit strut. I then filled with a little putty and sanded off. It took four evenings of work from discovering the damaged piece to getting to the stage in the photograph below. As I'm sure you can tell, the repaired strut is the one on the left.

I painted both struts flat black then dry-brushed them with aluminum. Then I dusted a little with the weathering powders. The struts are not identical but the repaired piece (still on the left) turned out better than I had hoped for.

Weather

With the color scheme, decals and repairs done, and the last pieces attached, the model was ready for the final stage: making a freshly-painted scale model look like a life-sized, dirty and worn vehicle. This basically involves scaling up the model's shadows and simulating the effects of weather and use. The shadows in the nooks and crannies and panel lines of a 1:48 scale model are barely visible: they do not look like vehicle shadows reduced to 1:48 scale. Applying a thin wash of black or brown darkens and deepens the recesses of the model both improving the shadows and giving the illusion of collected dirt. Other techniques involve applying paint chip effects either with dabs of a bare metal color or masking off prior to painting. Rain streaks, rust and dust are other options.

Before weathering I gave the model another coat of Future floor finish. This seals in the decals and provides a gloss surface so the wash runs off the flat areas yet still pools in the recesses. I made a wash from 1 part black and brown artists' oils with about 9 parts mineral spirits. There were a few places where the wash did run into recesses but most of the panel lines on this model are raised. What worked for me was to place a drop of wash each side of a raised line and then use a fingertip to blend and smooth the paint up into the corner of the panel line. A little dry-brushing along the ridge of the panel line with chrome silver completed the effect. For the paint chips I first tried a silver leafing pen but I wasn't convinced by the results. What I preferred was to place tiny dabs of chrome silver with a fine brush and blend the occasional one with my finger. In other places dry-brushing was effective.

To clean up excess wash I dipped either a rag or a napkin or a Q-tip in mineral spirits and wiped the area down. Using oils for the wash on top of the Future (which is acrylic) meant that the oil thinner would only affect the wash layer. Using an acrylic wash and hence acrylic thinner would have been hazardous to the Future.

Finally I dusted the model with Doc O'Brien's weathering powders; the rusty brown color this time.

Finish

The final sealing coat was flat clear lacquer mixed about 1 to 1 with thinner. I'll leave you with some photographs of the finished model.

Kerning and animating text glyphs

This sample shows how to transform glyphs in a TextBlock. The kinds of things you can do here are letter-pair kerning and animating the translation or rotation of individual glyphs.

Posted by stevewhitepsfd | 1 Comments

Attachment(s): AnimatedText.zip

Expression Interactive Designer preview available!

Today the Expression team is delighted to announce the availability of a preview version of Expression Interactive Designer. This preview version is the January 2006 Community Technology Preview [1]

We have compiled a set of sample applications and tutorials specifically for this CTP and you can find them on the official Expression team blog [2].

 

There are lots more resources about Expression on the Microsoft Expression web site. [3]

 

If you enjoyed the previous Channel 9 video [4] featuring the Expression Interactive Designer team then you'll want to check out the new video Robert Scoble hosted and posted today [5]

 

 

[1] http://www.microsoft.com/downloads/details.aspx?familyid=ed9f5fb2-4cfc-4d2c-9af8-580d644e3d1d&displaylang=en

 

[2] http://blogs.msdn.com/expression

 

[3] http://www.microsoft.com/products/expression/

 

[4] http://channel9.msdn.com/Showpost.aspx?postid=115387

 

[5] http://channel9.msdn.com/showpost.aspx?postid=157843

Sparkle, development teams, and what ‘no code’ means

Microsoft Expression “Sparkle Interactive Designer” (Sparkle for short) was announced and demonstrated at the Professional Developers’ Conference in Los Angeles last month. To find out what this powerful tool is all about, see the Expression Home Page, the Sparkle Team on Channel9, and Eric Rudder’s PDC keynote.

 

So, what is the Sparkle tool good for and who will use it? Well first of all, if you’re evaluating the Windows Presentation Foundation (WPF) today, you’ll have noticed that Visual Studio currently has no design surface for XAML source code. In time, Visual Studio will have design support (codenamed ‘Cider’) for WPF suitable for the needs and wishes of software developers. What Sparkle will offer over and above Visual Studio’s WPF designer is a set of features aimed at professional user-experience designers.

 

The kind of designers I’m talking about have creative and technical skills including graphic design, usability design, and interaction design. The North Face demo (also shown at PDC) is a beautiful and striking example of how WPF brings the development of creative interactions within reach and obviates a specialization in 3D computer graphics.

 

Developers with design sensibilities will also use Sparkle, just like designers with programming sensibilities already use Visual Studio. These skill combinations are very common – what’s less common is to be excessively talented in both spheres. So Sparkle will not ‘turn developers into designers’ nor ‘require designers to be developers’ but it will give the members of large development teams the opportunity to specialize whilst preserving the MSBuild format of projects transferred between Sparkle and Visual Studio.

 

Clemens Vasters has written an excellent blog entry about subject-area specialization in which he discusses what he calls visualization developers. Visualization is a component of interaction and the members of this sector of the development team may equally well be called interaction designers and possibly, for the trickier coding, interaction developers.

 

Which brings me onto what code means and, more importantly, what no code means. The community regularly describes HTML, XAML, C#, VB.NET, etc as code which implies that any formalized, syntactically-constrained encoding is code (whether the logic is declarative or imperative). But often, in demonstrations of WPF and Sparkle, the speaker (myself included!) points out that no code was written and I think this deserves some clarification.

 

Typing XAML into Notepad or Visual Studio is, arguably, coding and the no code assertion is hard to support. Similarly, a Sparkle project with no code is an empty one. Rather, what’s compelling about WPF is that the semantics of the code is incredibly rich so you need less of it. What’s compelling about designing on a surface in Sparkle or Visual Studio is that the tool generates the code for you. It so happens that declarative code is more practical for tools to generate than imperative code and that a design surface is able, in real-time, to reflect edits to declarative source code whereas imperative source code is built before it is expressed. So it’s likely that great tool support, making XAML so friendly, is the reason we often overlook it as code.

Sparkle Hayter and the Sparkle Fan

I’ve been a member of the Microsoft UK PSfD team for three and a half years now but, beginning on Monday, I’m moving to a new role in Redmond. Being an ADC has definitely been the best job experience I’ve had to date: the application development consultancy work with customers is challenging and rewarding in equal measure and my team-mates have been an inspiration and a great bunch of friends.

Our managers encourage our development in every way even if that means eventually losing us from the team. I’m excited to be moving to the corporate campus in Redmond to join the Expression Interactive Designer team as a technical writer. That means I’ll be producing conceptual writing, tutorials and sample applications. Needless to say, I'll be blogging a lot about what I get up to.

EID's codename is Sparkle and today my colleagues bought me a book by a writer called Sparkle Hayter. They think that kind of thing is funny! ;-)

I, however, am a great fan of Sparkle and I'm sure you will be too.

 

Posted by stevewhitepsfd | 6 Comments
Filed under:

My two SxS articles are now published in MSDN

I've removed the SxS articles from the blog now because they've recently been published on MSDN. Please see my MSDNography links section.

Avalon 3D File System Visualizer (FolderTreemap3D)

Download the FolderTreemap3D sample

(Requires Windows Server 2003 or Windows XP, .NET Framework 2.0 SDK Beta 2 (or Visual Studio 2005 Beta 2), and WinFX Beta 1 RC Runtimes and SDK)

 

Ben Shneiderman developed the treemap style of visualization in the early 1990s in response to the common problem of a filled hard disk. For this application, Professor Shneiderman needed an alternative to the incumbent tools (i.e. File Manager and Explorer) which, although strong at quantitative presentation of one hierarchical level of files at a time, don’t offer the aggregation needed for a high-level, qualitative view. A treemap’s strength is the reverse: perspective (or context) is more important than precision. If you’ve ever trawled up and down through the levels of a hierarchy seeking the largest files and folders as candidates for deletion then you’ll appreciate the perspective a treemap gives.

 

The ‘squarified’ treemap is a refinement which minimizes the aspect ratio of each node rectangle and this is the variation I have used. But with any flat treemap, the depth of hierarchical nesting of a node is not obvious to the viewer. It occurred to me that, if a node’s nesting level is represented by its distance along the z axis, then an orthographic 3D projection would appear to be a flat treemap when viewed from the front but would reveal the spacing along the z axis when rotated. I was also curious to see the same 3D model projected with perspective.

 

I have used color to distinguish folder nodes (transparent) from file nodes (colored dark in proportion to their depth). Examine the image at the beginning of the post. The entire image is a visualization of the %windir%/Microsoft.NET/Windows folder which contains the Avalon runtimes. What does the image tell us? Well, first (and without having to expand any nodes) we can see that the \Windows folder contains a single child folder named \v6.0.4030 which in turn contains the \Avalon folder and a number of files. The \Avalon folder contains one large .msi file at a deeper level than the files inside \v6.0.4030. We get a qualitative sense of the relative sizes of the files and folders – e.g. PresentationCore.dll and PresentationFramework.dll are approximately the same size as one another and both much smaller than avalon.msi. We can also see that there is a large number of small files which we could zoom closer to if we wanted to see their names.

 

The following image moves up a folder and shows, amongst other things, the combined size of the Avalon runtimes (the \Windows folder) in relation to the remainder of the .NET Framework. We can also see that, for example, System.ServiceModel.dll is a little larger than PresentationCore.dll and PresentationFramework.dll.

 

Here are the pieces which go into this sample:

  1. A generic DatatreeNode class used to build a ‘datatree’ of the data to be visualized. Using this extension point, any data which can be represented as a hierarchy (e.g. your Exchange/Outlook folders) can be processed into a treemap.
  2. A routine to recurse into a file system folder and build a datatree from it.
  3. A TreemapNode class (and ancillary classes) used to build a treemap from a datatree.
  4. A routine to arrange the treemap into layers for back-to-front rendering. As the scene uses semi-transparent materials, it is defined back to front to aid correct alpha blending.
  5. A routine to walk the treemap layers from furthest (from the eye) to nearest and to process each node in each layer as follows:
    1. Create a tree of Visuals consisting of a TextBlock inside a Viewbox inside a Border.
    2. Create a VisualBrush from the above and use it as the material on a plane (a MeshGeometry3D) which is placed appropriately on the z axis.
  6. A custom Viewport3D in which to display and manipulate the scene (the same one I introduced in the Nendo Nessie post).

There’s a lot of information to be seen in the images here, but even more information emerges when you are able to manipulate the model yourself with the mouse. Download and build the sample and evaluate it yourself. To toggle mouse manipulation mode, use Ctrl + right-mouse-click. See the Nendo Nessie post for more details.

 

Furthermore, information is always lost when flattening (i.e. projecting) a 3D scene for display on a traditional CRT or LCD monitor. Flat displays rely on artificial depth cues (e.g. perspective or color) to tell the eye how far away an object is. The same 3D data shown on a stereoscopic or a holographic display would preserve depth information so that the eye and brain sense true depth and can more fluently read the scene.

 

It would be an interesting exercise to use the sample’s treemap generation logic inside a custom Panel.

I’ll leave you with another of Ben Shneiderman’s visualizations – structured flowcharts – which may offer an interesting future project for someone to realize in Avalon.

 

Posted by stevewhitepsfd | 11 Comments
Filed under:

Building Avalon Apps: Basics and Behind-the-scenes. Part 2

Command-line build 2: XAML-only NavigationApplication

In the previous post I showed how to build a very basic C#-only Avalon application. At the end I mentioned that declaring and initializing UI is probably not best done with imperative code. This time I’ll go to the other extreme and declare a very simple application entirely in markup. In future posts I’ll settle for a mixture of markup and code-behind.

 

If you’re familiar with ASP.NET then you’ll know about markup files and code-behind files. The idea is that UI is defined in markup, and application logic is separated out into the code-behind file. This way, in an idea world, a developer can drop a basic UI into markup, make it functional in the code-behind, then let a designer take the markup and make it beautiful. It also means that the UI and application logic needn’t be compiled at the same time.

 

Although Windows Forms doesn’t have markup, it does have the InitializeComponent method into which the Forms Designer writes a lot of UI initialization code. This gives some separation of static layout from application logic but, because the UI is initialized in imperative code, it’s not as toolable as markup. It also means the UI and application logic must be compiled together.

 

XAML is Avalon’s markup. XAML can be used to declare any CLR object and it’s effectively a persistence format for CLR objects. When used with Avalon, XAML is a persistence format for Avalon objects, and Avalon offers far better flexibility and customization than ASP.NET or WinForms. XAML is XML so it is extremely toolable and it can be parsed and/or compiled separately from the application logic, even being loaded dynamically at runtime as a control tree.

 

With the Beta 1 RC bits, the Application we created in the previous post purely in C# can’t be done purely in XAML (I’m told it will be possible in future bits). However, we can do a NavigationApplication purely in XAML. A navigation application has a similar paradigm to a web application or a Wizard in that it has pages between which the user nagivates and a Journal in which navigation history is remembered.

 

First we’ll create a file in which to declare the application class. Create a folder called XAML-only NavApp and, in it, create a new text file called NavApp.xaml. Declare an empty NavigationApplication element with a StartupUri of Page1.xaml like this:

 

<NavigationApplication xmlns="http://schemas.microsoft.com/winfx/avalon/2005" StartupUri="Page1.xaml"/>

 

In XAML, elements correspond to type names and attributes correspond to property names (unless recognised by XML, e.g. the default XML namespace declaration). What we’re doing here is declaring a partial type deriving from System.Windows.Navigation.NavigationApplication. We’ll shortly be processing this markup through a XAML markup parser. The markup parser will know the NavigationApplication type because we’ve specified a default XML namespace which identifies the Avalon types. I haven’t named the derived type so it’ll get a default name (actually _Application). The markup parser will also assume we want a singleton instance of this class and it will generate the code to instantiate one also. We’ll look more closely at what gets generated from this XAML after we’ve built it.

 

Next, create Page1.xaml containing a Page element as follows:

 

<Page xmlns="http://schemas.microsoft.com/winfx/avalon/2005" Text="Hello from Page1">

     <TextBlock>

          <Hyperlink NavigateUri="Page2.xaml" Text="Go to Page2"/>

     </TextBlock>

</Page>

 

Again the Avalon XML namespace is required. The value of the Page element’s Text attribute will appear in the navigation application’s main window caption when this page is shown. Nested inside the Page element is a TextBlock element which is a control used to display simple text content. The markup parser has a set of rules by which it determines what a child element represents relative to its parent. A child element may be a complex property of its parent (e.g. Button.Background); a member of the collection stored in its parent’s default property; part of its parent’s content tree; or something else.

 

In this case the TextBlock is interpreted as being the value of the Page’s Child property (which is of type UIElement; and TextBlock is a UIElement). Inside the TextBlock is a Hyperlink element which is interpreted as the TextBlock’s content.

 

Again, this XAML is declaring a new partial type deriving from Page. Whereas the markup parser will instantiate an application instance for us without being explicitly asked, it does not do so for other classes declared in XAML. However, the application’s StartupUri is set to Page1.xaml which is a fairly explicit request for an instance of our Page-derived class and the markup parser will generate code which will result in one. As I’ll show in a moment, this instance is actually created at runtime by another parser.

 

Next, create Page2.xaml:

 

<Page xmlns="http://schemas.microsoft.com/winfx/avalon/2005" Text="Hello from Page2"/>

 

Now create a project file called NavApp.csproj which contains:

 

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>

    <AssemblyName>NavApp</AssemblyName>

    <OutputPath>.\</OutputPath>

    <OutputType>winexe</OutputType>

  </PropertyGroup>

  <ItemGroup>

    <Reference Include="System" />

    <Reference Include="WindowsBase" />

    <Reference Include="PresentationCore" />

    <Reference Include="PresentationFramework" />

    <ApplicationDefinition Include="NavApp.xaml" />

    <Page Include="Page1.xaml" />

    <Page Include="Page2.xaml" />

  </ItemGroup>

  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

  <Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />

</Project>

 

The NavApp.csproj file contains the same Assembly references as the project file in the previous post, but it also has ApplicationDefinition and Page item types. These item types are built by code inside the PresentationBuildTasks.dll I mentioned in the previous post, and the WinFX targets tell MSBuild about that dll.

 

Choose Start – All Programs – WinFX SDK – Release Build Environment and change directory to your XAML-only NavApp folder. Issue the command msbuild and confirm that the build succeeded.

 

If you can resist running the application right away you might be interested to look at the generated intermediate files in your \obj\release folder. The .baml files contain a binary version of the XAML (i.e. tokenized XAML). The .g.cs files are generated C# source files.

 

When we built our project, the Page XAML files were parsed into a corresponding .g.cs source file and a corresponding .baml file. Inside Page1.g.cs you’ll see that a class called _Page1 has been generated. In this class is logic to load the page’s BAML from a managed resource embedded in the assembly. However, although Connect is called (the purpose which is to give the class the opportunity to wire up any event handlers), InitializeComponent is not, as can be witnessed by setting breakpoints. A class called System.Windows.Navigation.NavigationService is actually used behind the scenes to load the BAML and parse it into an tree of user-interface elements.

 

Inside NavApp.g.cs (which was generated from NavApp.xaml) the _Application class is defined, deriving from NavigationApplication. And in its constructor the StartupUri is set to the same value we set in markup.

 

NavApp.Main.g.cs does not correspond to any XAML file but it is generated by virtue of the fact that we are building an application. Our Main method is generated in this class along with a ResourceLoader class which you can see being instantiated in the _Application class. However, the ResourceLoader is now a deprecated mechanism. In the Main method our application singleton instance is created, and it is stored in a private static member by the Application base class constructor. This enables the instance to be accessed via System.Windows.Application.Current as you can see happening in _Page1.MyApplication.

 

Also during the build process, the generated .g.cs source files are then compiled into an assembly. All that remains of the markup is the BAML which is deserialized into CLR objects at runtime by the System.Windows.Serialization.Parser class. This class can be used to (de)serialize any BAML or XAML at runtime.

 

If you now run the navigation application you will see the chrome at the top of the window which contains the navigation buttons. The chrome actually belongs to an instance of a NavigationWindow which has been automatically created for us, and our Pages are placed inside that. The Journal is the name for the mechanism which remembers our navigation history which you can see by using the navigation buttons’ drop-down buttons after you have navigated with the hyperlink.

 

Next time I’ll move into Visual Studio 2005 and combine XAML with code-behind in order to benefit from the advantages of each.

 

Posted by stevewhitepsfd | 3 Comments
Filed under:

Building Avalon Apps: Basics and Behind-the-scenes. Part 1

I thought it would be interesting to walk through building some very basic Avalon applications. Some topics I want to introduce include Avalon’s application model; the interplay between declarative XAML markup and imperative CLR code-behind; what happens at build time; and some behind-the-scenes details at runtime.

 

The WinFX Beta 1 RC bits

To follow along you’ll need to install the WinFX Beta 1 RC Runtimes and SDK on XP or Windows Server 2003 if you haven’t already.

 

Although Avalon and Indigo are each parts of WinFX (i.e. the Windows Frameworks), their assemblies are installed to slightly different destinations in the Beta 1 RC. For instance, Indigo’s System.ServiceModel.dll can be found in %WINDIR%\Microsoft.NET\Framework\v2.0.50215. But the Avalon runtimes (WindowsBase.dll, PresentationCore.dll and PresentationFramework.dll, etc) can be found in %WINDIR%\Microsoft.NET\Windows\v6.0.4030. This separation may become clearer on Longhorn but it suggests that Indigo is part of the .NET Framework whereas Avalon is part of WinFX proper. This is supported by the following table:

 

Assembly

AssemblyProductAttribute

AssemblyVersion

AssemblyVersion of .NET F/W Referenced

System.ServiceModel

Microsoft(R) .NET Framework

2.0.0.0

2.0.0.0

WindowsBase

Microsoft (R) Windows (R) Operating System

6.0.4030.0

2.0.0.0

PresentationCore

Microsoft (R) Windows (R) Operating System

6.0.4030.0

2.0.0.0

PresentationFramework

Microsoft (R) Windows (R) Operating System

6.0.4030.0

2.0.0.0

 

Another of Avalon’s assemblies is PresentationBuildTasks.dll which contains the MSBuild Tasks which process XAML into CLR source code files and into a binary representation called BAML.

 

The first two applications will use command-line builds; I’ll get to Visual Studio 2005 later.

 

Command-line build 1: C#-only Application

Let’s begin by building an Avalon application entirely in C#. Create a folder called C#-only App and, in it, create a new text file called App.cs. Add the following code to the file:

 

using System;

 

class EntryPoint

{

     [STAThread]

     static void Main() {}

}

 

So far there is nothing to distinguish this from a regular .NET application. It has a UI thread and an entry point. Now add a using statement for System.Windows. Notice the subtle difference here: if we were writing a Windows Forms application we would use System.Windows.Forms. Next, in Main, instantiate a new Application (actually System.Windows.Application) and call its Run method. Your file should now look like this:

 

using System;

using System.Windows;

 

class EntryPoint

{

     [STAThread]

     static void Main()

     {

          Application app = new Application();

          app.Run();

     }

}

 

If we build and run this, we’ll have a running Avalon application but it will have no way of interacting with the user (unless you count Task Manager!). So let’s have the app show a window. In Main, instantiate a new Window (System.Windows.Window) and call its Show method. Your Main method should look like this:

 

     static void Main()

     {

          Application app = new Application();

          (new Window()).Show();

          app.Run();

     }

 

We’ll be using the Microsoft Build Engine (MSBuild) to build our application, so create a project file called App.csproj in your application folder. Inside it put the minimum contents to perform an Avalon build:

 

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>

    <AssemblyName>App</AssemblyName>

    <OutputPath>.\</OutputPath>

    <OutputType>winexe</OutputType>

  </PropertyGroup>

  <ItemGroup>

    <Reference Include="System" />

    <Reference Include="WindowsBase" />

    <Reference Include="PresentationCore" />

    <Reference Include="PresentationFramework" />

    <Compile Include="App.cs" />

  </ItemGroup>

  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

</Project>

 

The only thing of note, the only part which is different from a normal C# MSBuild project, is the set of assemblies referenced (the ones we talked about earlier).

 

Now, to build the application from a command-prompt choose Start – All Programs – WinFX SDK – Debug Build Environment and at the prompt change directory to your C#-only App folder. Issue the command msbuild. Confirm that the build succeeded.

 

Run App.exe and note the default window which is shown. Now, to customize the window a little. Add a new class to App.cs called MyWindow which derives from Window. In the class’s constructor set the window’s Text to “Hello from MyWindow”.

 

class MyWindow : Window

{

     internal MyWindow()

     {

          this.Text = "Hello from MyWindow";

     }

}

 

Change the code in Main so it instantiates a MyWindow instead of a Window. Build and run again and note the window’s caption is the value you set the Text property to.

 

So far there’s nothing to distinguish this as an Avalon window so let’s put some Avalon controls inside it. Add a using statement for System.Windows.Controls. In MyWindow’s constructor, declare an object reference and assign a new Button (System.Windows.Controls.Button) to it. Cast the object to a ContentControl and set its Content to “Some text content”. Finally set the MyWindow’s Content to the object.

 

     internal MyWindow()

     {

          this.Text = "Hello from MyWindow";

          object o = new Button();

          (o as ContentControl).Content = "Some text content";

          this.Content = o;

     }

 

Notice how both the Button and the MyWindow have a Content property of type object. This is because both derive from System.Windows.Controls.ContentControl. This idea that there is no constraint on what can be contained within a control is Avalon’s evolution of text content. In the above code the Button’s content is still plain old text but it could be any object whatsoever (including the root of a tree of content), e.g. a Shape, a Control, a Panel or a business object. The MyWindow’s content is a Button, but would normally be a Panel of some kind inside which the remainder of the window’s content would be laid out.

 

I made the variable o have type object to show that the Content property of the MyWindow is of type object. But this also enables us to instantiate any ContentControl and assign it to o. Try instantiating a CheckBox instead of a Button.

 

Build and run. Notice that the Button is filling the window. This is because the default behavior for Buttons is to stretch to fill their container. There are many rules around layout which I’ll cover in a later post. For now, though, cast the Button object to a FrameworkElement and set its horizontal and vertical alignment to Center and, so that we can see it clearly, set its LayoutTransform to new ScaleTransform(5,5). You’ll also need to add a using statement for System.Windows.Media which is the namespace containing the ScaleTransform class. Your entire code file should finally look like this:

 

using System;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Media;

 

class EntryPoint

{

     [STAThread]

     static void Main()

     {

          Application app = new Application();

          (new MyWindow()).Show();

          app.Run();

     }

}

class MyWindow : Window

{

     internal MyWindow()

     {

          this.Text = "Hello from MyWindow";

          object o = new Button();

          (o as ContentControl).Content = "Some text content";

          (o as FrameworkElement).HorizontalAlignment = HorizontalAlignment.Center;

          (o as FrameworkElement).VerticalAlignment = VerticalAlignment.Center;

          (o as FrameworkElement).LayoutTransform = new ScaleTransform(5,5);

          this.Content = o;

     }

}

 

The casts are there only to highlight which classes define the various properties. If you like you can change o’s type to Button and remove all the casts. Build and run and notice the difference to the Button’s layout and scale transformation.

 

So far the application consists exclusively of imperative code which would arguably be more suitable in the form of declarative XAML markup. In the next post I’ll look at a XAML-only application (a NavigationApplication in fact) and after that we’ll mix the two modes and begin to use Visual Studio 2005.

 

Posted by stevewhitepsfd | 2 Comments
Filed under:

Arthur, Nendo Nessie, and Avalon 3D

Download the ArthurTest sample

Download nessie.obj

Just before I started working at Microsoft nearly three years ago, I wrote a hobby project called Windows OpenGL Classes (WOC). It’s written in VC++ 6.0 (but it compiles with VS.NET 2002) and it’s a kind of MFC for OpenGL. So it provides classes for application and window, as well as scene-graph and rendering management, and even a very flexible declarative animation system. It features geometry-generation and normal-calculation and the ability to read and write Wavefront OBJ files. The main feature missing from WOC is picking (i.e. selection, or hit-testing). I never got round to implementing picking, so I never got to experiment with 3D Windows controls which is something I’m greatly interested in.

 

Of course, Avalon provides most of the above features so I thought it’d be interesting to see if there were any parts of WOC which would add value to Avalon. For this experiment I’ve been using the March CTP of Avalon, running on Windows XP SP2. By the way, if you’d like a primer on 3D in general and Avalon in particular I recommend Daniel Lehenbauer’s blog (http://blogs.msdn.com/danlehen). I’ve called my new project Arthur, and there’s a screenshot of it above. The three main features which I’ll talk about in this post are: interactive camera manipulation, geometry generation, and geometry loading.

 

Help yourself to the ArthurTest sample source code from the link above. In Arthur\Viewport3D.cs you’ll find the definition of a class derived from Avalon’s System.Windows.Controls.Viewport3D. The added value of Arthur’s Viewport3D is to provide mouse manipulation of the camera. Depending on whether the symbol DX is defined, mouse input is handled either via DirectInput (for which you’ll require the DirectX 9 SDK) or via normal mouse input. By default, mouse manipulation is inactive for a viewport. In order to toggle into and out of mouse manipulation mode, use Ctrl+right mouse button. Once in mouse manipulation mode, if you depress both left and right mouse buttons whilst moving the mouse you will pan the scene. If you depress only the right mouse button whilst moving the mouse you will zoom the camera. If you don’t depress either button then you will effectively rotate the entire scene (lights and all). The rotation is actually achieved by moving the camera over the surface of an imaginary sphere. Up/down mouse motion affects the camera’s latitude (clamped to the range [0,180]), and left/right mouse motion affects the camera’s longitude.

 

There is some geometry generation code in Arthur\MeshGenerator.cs – I plan to add to it in time. You can use the static methods to generate meshes, and specify whether you want texture coordinates to be generated. Do be aware, though, that if you choose not to generate texture coordinates then you shouldn’t use an ImageBrush for your material otherwise nothing will be seen. Incidentally, the sphere’s geometry is calculated so that if you do set its material to an ImageBrush, the image will be upright with its center facing the default camera position.

 

Finally, in Arthur\FileLoaders.cs, you will find code to read geometry from Wavefront OBJ files. The ArthurTest sample uses this feature to read in a file called nessie.obj. It’s actually a textured model I created using Nendo 1.1. However, it isn’t textured in the screen shot above because the way OBJ files specify texture coordinates isn’t compatible with Avalon. I need to do some work yet to handle that difference. Another constraint is that the code currently only handles OBJ files having a single group in them.

 

So with the ability to load OBJ files we have an easy way to define geometry. I can use simple OBJ files to demonstrate how Avalon calculates normals when they are not supplied. The following OBJ file content defines two triangles at an angle to one another, sharing two common vertices. For this geometry, Avalon calculates vertex normals and the result is smooth-shading.

 

v -0.5 -0.5 0.5

v -0.5 0.5 0.5

v 0.5 0.5 0.5

v 0.5 -0.5 0

f 1 4 3

f 1 3 2

 

This next OBJ file content defines the same two triangle but this time there is no vertex sharing. For this geometry, Avalon calculates face normals and the result is flat-shading.

 

v -0.5 -0.5 0.5

v -0.5 0.5 0.5

v 0.5 0.5 0.5

v -0.5 -0.5 0.5

v 0.5 0.5 0.5

v 0.5 -0.5 0

f 4 6 5

f 1 3 2

 

As WOC handles its own normals, it can calculate face or vertex normals on request. Arthur doesn’t have that feature yet but it’s on my wish-list. If you do experiment with OBJ files, remember that Avalon (and the OBJ file format) uses a right-hand coordinate system and therefore triangles should be wound counter-clockwise. The ‘v’ and ‘f’ markers signify vertex data (x,y,z values) and face data (either triangles or quads) respectively. Make sure there’s a carriage-return between each set of data.

 

I no longer need WOC’s animation features. But in WOC, just like in Avalon, a camera is a model and can therefore be animated. WOC’s animations are provided by relays of signal-generating objects feeding into chains of functions, and ultimately bound to the properties of models. This way position, colour, etc can be animated. You can see some examples of this animation system in the Graphics Samples section of my website.

 

So what’s next? Well, because Avalon intrinsically provides most of WOC’s value proposition, there’s actually not a great deal more of WOC to port. There are one or two more geometry-generation methods to add (including my favorite, the ripple-grid). I’m very excited by what Avalon has to offer, and I’m looking forward to playing with its picking features to finally do those experiments with 3D controls I’ve been wanting to do. Watch this space!

Computing Real-Time Holographic Video Content With Off-The-Shelf PC Hardware

If, like me, you've been awaiting an update on Mark Lucente's research, you'll find this paper by Tyeler Quentmeyer et al fascinating: http://web.media.mit.edu/~vmb/papers/quentmeyerms.pdf

 

Apparently (http://www.media.mit.edu/spi/) the Spatial Imaging Group at MIT disbanded about the time this paper was published (almost a year ago). I hope this important research is continuing somewhere and is getting enough funding.

Posted by stevewhitepsfd | 3 Comments
Filed under:

Scales

So I’ve talked about classes representing the ideas of note and interval. This post I’ll cover Voices.ScaleClass, Voices.Scale and Voices.KeySignature.

 

A scale is an interesting interplay between notes and intervals within an octave. As an example, the notes C D E F G A B constitute the C major scale. But it is the set of intervals between these notes (the sum of which is an octave) which defines the essence of what it is to be a major scale. Specifically, these intervals are: maj2 maj2 min2 maj2 maj2 maj2 min2. Typically the intervals are summed cumulatively with the initial perfect unison and the final perfect octave assumed, so: maj2 maj3 per4 per5 maj6 maj7. That set of intervals, measured out above a tonic note, locates and names the notes of any major scale.

 

Although a scale can be viewed as a series of notes or as a series of intervals, it’s practical to see the notes as the scale and the intervals as the scale class. So a scale can be defined as a sequence of notes, chosen out of the possible notes in the octave, and beginning on a tonic. And a scale class can be defined as the class of scales between whose notes appears the same sequence of intervals. As I’ve said, that sequence of intervals sums to an octave no matter what the scale class.

 

So, let’s look at a C# class representing scale class. Greatly simplified, Voices.ScaleClass looks like:

 

public class ScaleClass

{

      static ScaleClass()

      {

            _majorScale = new ScaleClass("Major", "2 3 4 5 6 7");

            _dorianMode = new ScaleClass("Dorian Mode", "2 b3 4 5 6 b7");

            ...

            _bluesScale = new ScaleClass("Blues Scale", "b3 4 b5 5 b7");

      }

 

      public static ScaleClass MajorScale { get { return _majorScale; } } static ScaleClass _majorScale;

      public static ScaleClass IonianMode { get { return _majorScale; } }

      public static ScaleClass DorianMode { get { return _dorianMode; } } static ScaleClass _dorianMode;

      ...

      public static ScaleClass BluesScale { get { return _bluesScale; } } static ScaleClass _bluesScale;

 

      internal ScaleClass(string longName, string intervalsString)

      {

            _longName = longName;

            _intervalsString = intervalsString;

      }

      internal string _longName;

      internal string _intervalsString;

}

 

The only real value this class provides is a place to store the _intervalsString field. This field contains a string representation of the sequence of intervals which give the scale class its identity. These intervals have the format of an optional sharp or flat symbol followed by a digital interval quantity. Alternatively they can be the solfeggio symbols: do, di, ra, re, ..., te, ti.

 

The class Voices.Scale has a constructor with the signature:

 

public Scale(ScaleClass scaleClass, Note tonic)

 

What this constructor is interested in is the tonic note and the _intervalsString from scaleClass. It String.Splits intervalsString into a string[] the elements of which it then takes in turn and obtains an Interval from by means of the following method on Voices.Interval:

 

internal static Interval Interval.LookUp(string abbreviation)

 

The constructor proceeds to add each resulting Interval in turn to the tonic Note, thus obtaining the degrees of the scale. It’s a little more complicated than than because Voices.Scale is actually composed of a doubly-linked cyclic list of Voices.ScaleTone.

 

So, of the list nodes (i.e. the tones) in a Scale, those which are ScaleDiatones are the ones corresponding to the tonic note and the notes reached by adding the intervals of the scale class to it. All the rest are plain old ScaleTones.

 

In order to support enumeration, Voices.Scale implements IEnumerable and its implementation of IEnumerable.GetEnumerator simply returns a new instance of the Voices.ScaleToneEnumerator class. As is typical, ScaleToneEnumerator Resets its Current state to ‘one before the first element’ which in this case is the tone at the 11-o’clock position. It implements MoveNext by moving to ScaleTone.Sharp until the 11-o’clock position is reached again.

 

The last class I’ll talk about in this post is KeySignature. A key signature is a pattern of sharp or flat symbols written at the beginning of a musical staff to indicate which degrees of the scale are not natural. Strictly speaking, distinct key signatures exist only for fifteen major scales. Minor scales and the remaining modes re-use the key signatures of their relative major scale. I omitted this detail above for the sake of clarity, but one of the arguments to the ScaleClass constructor is a value from the ScaleClass.Mode enumeration, which looks like this:

 

      public enum Mode

      {

            Major = 0,

            Dorian = 6,

            Phrygian = 5,

            Lydian = 4,

            Mixolydian = 3,

            Minor = 2,

            Locrian = 1

      }

 

There is a field for each mode. The value given to each field represents the degree of the corresponding mode on which the mode’s relative major begins. For example, you may know that the major mode begins on the minor mode’s third degree. This is why Minor has the value 2 (where 0 means first). The constructor of the class Voices.Scale reads n, the integer value of its ScaleClass’s Mode, and then finds the nth degree of the scale being constructed. This way it identifies the major scale on which the scale is based and it is that scale which donates its key signature.

 

The important parts of the KeySignature class are:

 

      public Note[] Accidentals

      {

            get

            {

                  return _accidentals;

            }

      }

      internal Note[] _accidentals;

 

      public bool Sharps

      {

            get { return _sharps; }

      }

      internal bool _sharps = true;

 

The Accidentals property returns an array of Notes in key signature order, and the Sharps property tells us whether the accidentals are sharps or flats.

Even more registration-free COM articles!

So, I spent the past two weekends and every evening between finishing these. Please check them out and let me know what you think.

Registration-Free Activation of COM Components: A Walkthrough

Registration-Free Activation of .NET-Based Components: A Walkthrough

Posted by stevewhitepsfd | 3 Comments
Filed under:

New registration-free COM article

I posted the article "SxS Managed COM With Manifest Resource (WinXP and Win2K3)" some time ago and Jason Buxton was interested in applying it to Visual Basic 6.0 client applications. Well, I've put together an MSDN article proposal which addresses that question and is a general improvement on the original article.

The new article is called Registration-Free Activation of .NET-Based Components: A Walkthrough and can be found in the Software category of my articles section. I'm planning accompanying articles named "Registration-Free Activation of COM Components: A Walkthrough" and "Registration-Free COM in Web Applications: A Walkthrough."

Posted by stevewhitepsfd | 6 Comments
Filed under:
More Posts Next page »
 
Page view tracker