Dynamic Dreams (in construction)

Posted by Julien on January 22nd, 2008

PlaneStateAfter a few weeks building some tools to help me develop and debug dynamic dreams more easily, I’m back to  working on the dreams themselves. I have six dynamic dreams about to go into testing. There is still quite a lot of work to do before a public release, but they are kind of usable and shouldn’t crash explorer randomly :)

The most visible thing lacking is a proper configuration UI. Most of the settings are currently either hard-coded or read from a XML file (instead of the registry).

Those dreams are ports of XboxMediaCenter screensavers. Those are licensed under the GPL, so all source code will be available with the public release.

There are other screensavers in the collection, but they are not yet ready for testing. I will probably not release all of them (some do not make good dreams or are too hard to port).

Here is a description of the Dreams:MatrixTrails

  • Asteroids: a simple asteroids game simulation (note: the IA is not really good at the game…).
  • BioGenesis: this dream implements a ‘game of life’ simulation. Not spectacular, but kind of mesmerizing to look at :)
  • MatrixTrails: the famous matrix letter effect. Really nice one!
  • PingPong: the pong game (without score)
  • PlaneState: this one is an adaptation of the PlaneState Screensaver. The different configurations are hard-coded and chosen randomly on startup.
  • Stars: moving through a star field. A great demo, but probably not recommended for everyday use.
BioGenesis Asteroids
PingPong Stars

Don’t hold you breath though, they probably won’t be released publicly until Stardock makes the Dream SDK available.

DreamBuilder - A command-line Dream builder

Posted by Julien on January 21st, 2008

If you have tried to make Dreams in the past, you have been using DreamMaker. This application allows you to take a video file (or several of them in case of a trigger-based Dream) and "compile" it into a .Dream file. This Dream file also contains other information such as the name of the author, a website URL, copyright and permissions info, and a preview image.

MatrixTrails.xml - Notepad2One of the current limitations of DreamMaker is the lack of a save/load mechanism, requiring you to retype everything each time you want to create a new Dream (or update an existing one). While this might not be a big deal with video and trigger-based Dreams, it begins to be a real pain the moment you start creating dynamic Dreams (even more so when you have 8 or 10 of them in development/testing at the same time).

Enter DreamBuilder: a command line tool to build Dreams. It uses a simple XML configuration file to load the info needed to build a Dream file. No more re-typing ! Now you can have the Dream creation cleanly integrated into you build process.

DreamBuilder is using the DreamMaker.dll file (part of the DreamMaker distribution) under the hood to create the Dream file, so the Dream files created will be the same that DreamMaker would have created. Error messages that DreamMaker normally shows are redirected to the console.

Pre-requisites:

Usage:

DREAMBUILDER inputFile [/O<outputDirectory>] [/D<variable>=<value>]

    inputFile             Path the dream definition file
    /O<outputDirectory>   Path to the output directory
    /D<variable>=<value>  Defines a variable to be replaced in the XML configuration file.
                          Several such variables can be defined. 

By default, the Dream file will be created in the current directory, but you can specify an output directory (such as the default Dream directory in "My Documents/Stardock/Dreams")

Configuration file:

Here is the example configuration file (included in the distribution).

<?xml version="1.0" encoding="utf-8" ?>
<dream>
    <!-- Dream name - max size: 100 characters -->
    <name></name>
    <!-- Dream description - max size: 600 characters -->
    <description></description>
    <!-- Author name - max size: 100 characters -->
    <author></author>
    <!-- Author url - max size: 200 characters -->
    <url></url>
    <!-- Dream copyright information (optional) - max size: unknown -->
    <copyright></copyright>
    <!-- Dream permissions information (optional) - max size: unknown -->
    <permissions></permissions>

    <!-- full/relative path to preview file - max size: 256x256 - BMP, JPG, JPEG or PNG only -->
    <preview></preview>

    <!-- 3 possibilities: video / trigger / dynamic (if more than one is defined, the first one found is used, others are ignored) -->
    <data>

        <!-- Video dream - full/relative path to video file - max size: 150MB - AVI, MPG, MPEG or WMV only -->
        <video></video>

        <!-- Triggered video dream - type: only "time" is allowed at the moment-->
        <triggers type="time">
            <!-- Trigger definition - at least two different triggers need to be defined -->
            <trigger>
                <!-- Time to trigger the video - in hh:mm:ss format  -->
                <time></time>
                <!-- full/relative path to the file - max size: 150MB - AVI, MPG or WMV only -->
                <path></path>
            </trigger>
        </triggers>

        <!-- Dynamic Dream -->
        <dynamic>
            <!-- Path to 32-bit dynamic dream dll -->
            <dll32></dll32>
            <!-- Path to 64-bit dynamic dream dll -->
            <dll64></dll64>
            <!-- Additional content (optional) - max number of files: 150 -->
            <resources>
                <resource>
                    <!-- full/relative path to the file -->
                    <file></file>
                    <!-- target path (relative to the root dream folder) -->
                    <path></path>
                </resource>
            </resources>
        </dynamic>

    </data>

</dream>

DreamBuilder is checking the XML configuration file against an XML Schema, so it will tell you if there is an error in your configuration (but the message might be a bit cryptic).

Visual Studio 2005 Command PromptDreamBuilder allows you to use relative paths when defining the files to use. By default, it will look for the files relative to the current directory.

This might be a problem if you are executing it from another folder that the one containing the files. This is why I introduced variable replacement: it provides a way to dynamically replace content in the configuration file. I use it for path handling, but you can also use it for other things such as adding a version number to the dream name.

The replacement step is happening before the file is parsed, so you can go crazy if you want, and generate the resource list at compile time for example.

You can have as many variables as you want (simply by adding another variable definition to the command line). To define a variable "name" with the value "Julien", you use the following define: "/Dname=Julien". You can then add a new variable to the XML configuration file: $name$. DreamBuilder will warn you if a variable exists without a substitution.

Example:

As an example, here is the config file I use for the MatrixTrails dynamic Dream:

<?xml version="1.0" encoding="utf-8" ?>
<dream>
    <name>MatrixTrails</name>
    <description>Matrix Trails Dream</description>
    <author>Julien Templier</author>
    <url>http://julien.wincustomize.com/</url>
    <copyright>Copyright (c) 2008, Julien Templier[...]</copyright>
    <permissions>This program is free software; you can redistribute it and/or [...]</permissions>

    <preview>$resdir$/MatrixTrails.png</preview>

    <data>
        <dynamic>
            <dll32>$builddir$/MatrixTrails32.dll</dll32>
            <dll64>$builddir$/MatrixTrails64.dll</dll64>

            <resources>
                <resource>
                    <file>$resdir$/MatrixTrails.tga</file>
                    <path>resources</path>
                </resource>
            </resources>
        </dynamic>
    </data>

</dream>

You can see all the files have a variable at the beginning of the path. Those will be replaced when the Dream is built.

In Visual Studio, I then added a post-build step calling DreamBuilder that takes care of defining the right variables:

DreamBuilder $(ProjectDir)/Resources/$(ProjectName).xml /O$(TargetDir) /Dresdir=$(ProjectDir)/Resources /Dbuilddir=$(TargetDir)

That way, each time a build succeeds, a Dream is generated that can be easily tested & distributed.

Download:

DreamBuilder is currently available as a zipped file (to be extracted to the directory of you choice). You might want to add it to your path to be able to call it from anywhere.

DreamBuilder (ZIP)

A MSI file is planned that will take care of adding the installation folder to the path.

LogonSwitcher 0.8 Technical Preview

Posted by Julien on August 16th, 2007

I’ve been sitting on that one for quite some time. It’s still not in a good enough state to be called a beta (or even alpha), hence the technical preview. It comes bundled with one logon (by yours truly :) ). The included logon is still a work in progress: stock buttons, no custom sound, no loading animation, etc.LogonSwitcher

What’s missing/not working:

  • Logon editor (won’t be in 1.0)
  • No check for image format when applying a logon (images in the wrong format will break the logon UI, resulting in a black screen)
  • Replacing UIFile files is disabled (considering removing support for it as doing it correctly is a lot of work: simply replacing them might be too dangerous)
  • No documentation
  • a gazillion little and not so little UI bugs

Installation instructions:

  1. Extract zip file to a directory of your choice
  2. Run LogonSwitcher.exe
  3. Drag&Drop Nature.logonswitcher onto the program window or use the import button
  4. Click Apply (and pray)

DISCLAIMER:  As ALWAYS, USE WITH CAUTION. BACKUP/CREATE A RESTORE POINT BEFORE INSTALL.

Please leave your feedback (either in the comments or through the contact form) !

[download#3#nohits]

TaskManagerEx for Windows Vista

Posted by Julien on August 16th, 2007

TaskManagerEx is a Task Manager add-on I’ve been using for a while. It adds a lot of new functions to the standard task manager. It will allow access to processes modules, opened files and kernel handles lists, as well as memory map & file properties. In addition to those, it also slightly improves the Task Manager UI by adding an icon in front of each running process and by highlighting service processes. Windows Task Manager (Extended) (2)

The currently available version runs on Vista but due to changes to the Task Manager, the context menu functionality is broken.

The updated version has the following changes:

  • New icons for services, “unknown” processes & main program
  • Updated context menu (moved items to a submenu to reduce clutter)
  • Removed splash screen & Russian translation
  • New image for tooltips
  • New toolbar images (WIP)
  • Source code cleanup

TaskManagerEx for Vista

Currently listening to Mika - Life In Cartoon Motion - Grace Kelly

Volume Control, DesktopX plugin and other news

Posted by Julien on March 1st, 2007

Volume Control and the DXVolumeControl plugin have been uploaded to Wincustomize. You should be able to get them in a few days. Here are the links: Volume Control and DXVolumeControl (they haven’t been moderated as of today, so you will have to wait a little bit).

After finishing the Vista version of the Volume Control widget, I actually added a XP compatibility layer to the DXVolumeContol plugin, so the only thing the vista version has over the XP one is true synchronization between the volume mixer and the plugin (on XP, the callbacks function are not working). This allows me to only have one version of the plugin running on both operating systems (less work needed on my side, which always is better :) ).

Work on LogonSwitcher has been slower than I wanted. Version 0.7 should go to my two beta-testers today. Still a lot of work needed on the UI, but the basic functionality is in. I added a bunch of logon using really nice pictures from flickr (under a CC license). I still need to do a full logon with all new graphics (this is going to take a lot of time :-D

 Corrected some problems with the export functionality. Some of those only happen when using multiple file format (that won’t be the case for the first release).

Currently listening to Norah Jones - Somewhere Over the Rainbow/What a Wonderful World

DXVolumeControl / Volume Control for Vista

Posted by Julien on February 25th, 2007

After finishing the Volume Control widget, I wanted to have something I could actually use. Unfortunately, the current version of DesktopX does not support the new way of changing volume in Vista. Changing volume with the DX API only changes the volume for the DX application (or widget if you are running outside of DesktopX).

Enter DXVolumeControl, a plugin I wrote a month ago to control the master volume in Vista. I just updated it to allow control of muting state (and respond to it via a callback). I also added a peak value property (read-only) to get the playing sample peak value.

The Volume Control for Vista widget will have the following enhancements over the XP version:

  • Volume meter reacts to volume change from the mixer panel or another application
  • Muting state change is reflected on the widget
  • The volume overlay opacity changes with the audio peak value (looks really cool :-D )

Currently listening to Kubb - Wicked Soul

Volume Control

Posted by Julien on February 25th, 2007

When I did the DXMouseWheel plugin, it was to be used in a volume control widget. As far as I know, nobody has released one yet, so why not do it myself ?

I started from a speaker image shared by vica on DeviantArt in 2002 (he said it was ok to improve on it in the comments but I sent him an email just to be sure, and I’m waiting for his authorization). I then added a red glow for the mute state and a blue glow for the 10 different ON states.

Armed with the speaker image and the eleven overlays, I jumped into DesktopX and created new objects for the speaker, the overlays and the volume text.

The script was pretty simple. I added the DXMouseWheel plugin (of course :) ) and wrote the required code to respond to the mouse wheel and the middle button.

Less than two hours later (yep, I’m still slow when it comes to DX and VBScript), I have a nice little widget that allows to control the volume with the mouse wheel and mute it by pressing the middle button.

Coming to Wincustomize soon !

Getting closer to 1.0

Posted by Julien on February 23rd, 2007

Today I corrected a bunch of remaining issues with LogonSwitcher. The logon preview now shows the password box correctly, the main logon list has better looking borders, etc. I tested a little bit more under VPC to make sure it applies a full logon (not only a new background) I also added some new logons using nice images from Flickr (I’m using images under CC BY or CC BY-NC-SA, so it’s to distribute them).

It still need to be tested thoroughly, and that’s why I recruited two beta testers to get some feedback and to help me refine the UI. The poor ones don’t know what they are getting into :P

On another matter, I finally updated my project page, adding the remaining pages. I still need to write descriptions for some projects, but at least nobody is going to get a 404 error anymore.

Updating resources files with BMP and PNG files (with managed code)

Posted by Julien on February 23rd, 2007

This only concerns Bitmap resources (RT_BITMAP). Updating others type of resources is easier and doesn’t require specific code.

  • BMP files

Inserting BMP files is quite easy. You only have to remove the header and you are good to go.

int BMP_HEADER_BYTES = 14;
FileStream stream = new FileStream(file, 

                                   FileMode.Open,
                                   FileAccess.Read,
                                   FileShare.Read);

BinaryReader reader = new BinaryReader(stream);
byte[] data = reader.ReadBytes((int)reader.BaseStream.Length);

GCHandle gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr bitmap = Marshal.UnsafeAddrOfPinnedArrayElement(data, BMP_HEADER_BYTES);

uint size = (uint)(data.GetLength(0) - BMP_HEADER_BYTES);
UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID, bitmap, size);

gcHandle.Free();
stream.Close();
  • PNG files

It’s a bit more difficult with PNG files. You must add a header before inserting the image data. You also need to rotate the image before inserting because of the bitmap is copied and read (alternatively, you can insert a negative height into the header, but I haven’t tested it).

Also note that we do not set the compression to BI_PNG (5) and the size of the image in the BITMAPINFO header.

[StructLayout(LayoutKind.Sequential)] 
class BITMAPINFO {
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;     
public int biCompression;     
public int biSizeImage;     
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant; }

// Load file 
Bitmap pngFile = new Bitmap(file);
// Required due to the way bitmap is copied and read
pngFile.RotateFlip(RotateFlipType.RotateNoneFlipY);
BitmapData data = pngFile.LockBits(new Rectangle(0, 0,
                                                 pngFile.Width, pngFile.Height),
                                   ImageLockMode.ReadOnly,
                                   PixelFormat.Format32bppArgb); 

byte[] dataBuffer = new byte[data.Height * data.Stride]; 
Marshal.Copy(data.Scan0, dataBuffer, 0, data.Height * data.Stride); 
pngFile.UnlockBits(data);
// Setup Header 
BITMAPINFO header = new BITMAPINFO(); 
header.biSize = Marshal.SizeOf(typeof(BITMAPINFO));
header.biWidth = pngFile.Width; 
header.biHeight = pngFile.Height;
header.biPlanes = 1; 
header.biBitCount = 32; 

// Convert the structure to an array 
byte[] buffer = new byte[header.biSize];
GCHandle h = GCHandle.Alloc(buffer , GCHandleType.Pinned); 
Marshal.StructureToPtr(header, h.AddrOfPinnedObject(), false);
h.Free(); 

// Write header + data 
MemoryStream memory = new MemoryStream(); 
memory.Write(buffer, 0, buffer.Length);
memory.Write(dataBuffer, 0, dataBuffer.Length);
byte[] imageData = memory.GetBuffer(); 
GCHandle gcHandle = GCHandle.Alloc(imageData, GCHandleType.Pinned); 
IntPtr firstCopyElement = Marshal.UnsafeAddrOfPinnedArrayElement(imageData, 0);

UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID,                
	       firstCopyElement, (uint)imageData.GetLength(0));

gcHandle.Free(); 
memory.Close();

Updating bitmap resources (with png files)

Posted by Julien on February 20th, 2007

Today’s probably the worst day I’ve had for quite some time. I didn’t sleep well last night. I’ve been feeling dizzy since this morning. I haven’t had much appetite for breakfast or lunch. And yet, today I finally resolved the problem that’s been bugging me for at least two weeks. How ironic !

To replace the logon screen, LogonSwitcher is modifying several images in resource dlls (I’m preparing an article on that). Some of the images in those resources are stored as “Image” resources and others as “Bitmap” resources. The first kind is easy to replace. Just open the file, map the contents and copy the bits to the resource. Done ! But the latter is a little bit more complicated.

You can have store several formats in “Bitmap” resources. The two I’m using are BMP and PNG. BMP are easy, you just have to remove the header and copy the contents of the file to the resource. But with PNG files, that doesn’t work…

I’ve been trying to make it work for more than a week with no luck, trying several things… What doesn’t help is that I haven’t been able to find any documentation on that precise subject. There is a lot of info on updating resources, but nothing specifically for PNG files. Or at least I couldn’t find it.

Finally, the actual working solution is 23 lines long :( Gahhhhhhhh !

I learned way more that I would have liked about win32 resources, PE, DIB, bitmaps formats. Not that there is anything wrong with learning new things, but with pure win32 programming, the more you learn about it, the more you realize that you know almost nothing. And that’s discouraging.

PS: if that sounds like incoherent rambling, re-read the first paragraph :)