Introduction

In the past months or years, every single PowerPoint or web page I have seen with a decent design and look, includes pictures that have been "reflected" vertically, as if they were on the top of a reflecting table or so... it's the so-called "web 2.0 reflection". Just like this one:

This kind of effect can be easily achieved with Photoshop, Gimp or whatever, just reflecting the image and applying a distort and a gradient mask, but hey! those 5 minutes per image are priceless if you have to do it with 50 pictures! So I decided to make a small app that allows you to create this kind of effect in 5 seconds, adding some processing effects to improve its functionality.

There are already similar projects out there (see Points of Interest), but I do it just for fun and to practice some new things I'm explaining below.

Topics Covered by this Project

XNA and Windows Forms integration

PropertyGrid control and basic ComponentModel namespace

Basic bitmap manipulation (reflection, alpha, blur, etc.)

Dynamic creation of textures in XNA

Basic maths

Note: This project uses some code samples found in the XNA samples.

Specifications

The application includes the following features:

Automatic reflection using a reflection polygon to specify the shape of the form to reflect

Requirements

Using the Application

The tool strip holds three buttons (on the top): Add point to reflection mark, refresh processing and select a background color for the working area

The processing settings property grid (on the upper left): Lets you set all the properties of the processing and effects

Original bitmaps picture box (on the lower left): Shows the original bitmap

Working area (on the right): Shows the current bitmap state and the Reflection Mark (the border the reflection will follow)

To process a bitmap, the first step is to open it (File->Open). The following picture is a good example to work with, because it has perspective and an irregular shape, which makes the reflection more complex:

As the bitmap occupies the area of almost the entire picture, you'll need to make some room for the reflection. To do so, select an AutoSizeMode to scale the bitmap down (processing settings property grid, 'Scaling' category).

In this example, I selected div1_25, which will reduce the size of the bitmap by 1 quarter. Now the bitmap is smaller in the final result, so you will probably need to re-center it. Such a thing can be done in the property NewLocation (in the example, I translated the bitmap 150 pixels to the right, leaving it at the top of the picture, so the reflection will fit in the bottom part).

After that, move up the "Reflection Mark" so it fits the bottom part of the object to be reflected. Now you can see a normal vertical reflection, which does not fit the shape of the object properly in this case:

Next, create some points to divide the reflection mark (select the star-like button of the toolstrip, and then click on a point inside the reflection mark). This way, it can be adjusted to the shape of the object. For the XBox, we created three points, as you can see in this picture:

Now, move the points to adjust the reflection mark, and you will get a nice adjusted reflection:

To make the alpha gradient more appropriate, adjust the range and set a negative offset to make the reflection more transparent. Finally, put some blur there to hide pixelation and aliasing effects:

Et voilá! The final picture:

Note 1: If the picture being processed has transparency, like the XBox one, you can choose to keep it or to save the final bitmap with the working area's back color as background. This is managed with the setting: KeepTransparency.

Note 2: In order to save the Alpha Gradient correctly, I recommend selecting PNG as the output format.

Using the Code

Note: Although some classes have been designed following the XNA GameComponent-like architecture, none of them really inherit from GameComponent. That's because this is mostly a WinForm application that uses XNA for rendering and maths, not an XNA-Game application that includes WinForms controls.

The structure of the application is quite simple.

First, I start using the XNAWinForm explained in my previous article about XNA integration with WindowsForm, and continue adding all the WinForms elements I'll need in this project: SplitterContainer, PropertyGrid, PictureBox, MenuStrip, ToolStrip, ...

This Form will also contain all the bitmap processing functionality that will be explained later.

Each time the bitmap is processed, it refreshes a texture shown in the screen by the XNAPictureBox class, which basically imitates System.Windows.Forms.PictureBox, rendering the texture with SizeMode = Zoom. XNAPictureBox also uses the PrimitiveBatch class (from XNA samples) to render lines for the picture frame.

Using the PrimitiveBatch class is very easy, as it imitates the SpriteBatch behavior, but to render primitives instead of textures. For example, to draw a line:

The bitmap manipulation process is configured by several settings, stored in the ProcessingSettings class. This class exposes properties for the values so they can be shown in a PropertyGrid. Using ComponentModel attributes, you can configure the appearance and behaviour of each property, like this one:

Next, the ReflectionMark class, which defines the shape of the border used for the reflection, contains a collection of points, and manages point moving and creation based on the following internal state:

publicenum eMouseMode
{
MovePoint,
MoveMark,
CreatePoint,
None,
}

The MouseMode is changed in several situations:

When a MouseClick happens, the state is sometimes changed.

Other times it's changed from outside the ReflectionMark class. For example, when the user selects the "Point Creation" mode by pressing the first button of the ToolStrip.

In order to change the MouseMode state and to move points or the bar, the ReflectionMark should be informed when the user moves the mouse or clicks any button. This could be done reading mouse information through XNA, but in this case I just handled those events from the PanelViewport class.

In the opposite way, when the MouseMode state changes, or the reflection mark is moved or changed in any way, we should inform the XNAWinForm as well, so it can refresh the bitmap or synchronize buttons and controls. I defined some events on the ReflectionMark for that:

Finally, we come to Bitmap Processing. (Please note that a lot of improvement and optimization can be done here). Any suggestions are welcome!

This task is done in the XNAWinForm.ProcessBitmap() method, which first reflects the bitmap and then applies blur and texture alpha (if selected). When all the operations are completed, it refreshes XNAPictureBox texture colors with the result.

Handles the KeepTransparency property by cleaning the final texture to a transparent color or to the WorkingArea's back color.

Scales the original bitmap

Places it into the final texture, in the new location

Reflects the pixels below the ReflectionMark

IMPORTANT NOTE: For performance reasons, the following method is UNSAFE and uses pointer access to bitmap data. If you want to avoid this behaviour, you can rewrite it using Bitmap's GetPixel and SetPixel methods, which will probably be slower.

Share

About the Author

Inaki Ayucar is a Microsoft MVP in DirectX/XNA, and a software engineer involved in development since his first Spectrum 48k, in the year 1987. He is the founder and chief developer of The Simax Project (www.simaxvirt.com) and is very interested in DirectX/XNA, physics, game development, simulation, C++ and C#.