|
Written by Markus Ewald
|
|
Thursday, March 17 2011 09:54 |
|
A few hours ago, I uploaded a new release of the Nuclex Framework
to CodePlex. There has been an intermediate release, R1323, which I didn't
announce here because it was more or less just a stop-gap measure to
stop reports for issues in the old (old, old) R1242 release where my
Nuclex.Input library was still subclassing XNA's Window.
This is what changed from R1242 to R1404:
-
Thanks to a generous contribution by Adrian Tsai, the TrueType importer now accepts
standard Windows font names - this is a big step towards being a drop-in replacement for
XNA's own sprite font importer.
-
The TrueType importer now lets users choose different hinting algorithms. No hinting
will result in MacOSish blurred text that stays true to the font's metrics. The
auto hinter from FreeType is a nice compromise between forcing strokes into a pixel
raster for sharpness and retaining the font's look (and imho the best option).
Native will produce a perfect match with Windows' font rendering, producing sharp
letters that may deviate from the font's actual metrics a bit.
-
You can now decide whether SpriteFonts imported by the TrueType importer are centered
on their baseline or on their upper end (like XNA). This, together with the improved
font name lookup turns the Nuclex TrueType importer into a 100% drop-in replacement
for XNA's font processor.
-
Nuclex.Input's game pads now provide a method
.GetExtendedState() with
which you can access all of DirectInput's 128 possible buttons, 24 axes and 8 sliders.
I designed this so that there's zero overhead if you don't use the
.GetExtendedState() method. The ExtendedGamePadState
already normalizes axes for you (from -1.0 to +1.0 for axes and 0.0 to 1.0 for sliders)
and in general is much nicer to work with than using DirectInput directly!
-
Nuclex.Input now supports TouchPanel input. That includes mocking TouchPanel input:
You can easily simulate the TouchPanel in your unit tests:
var m = new MockInputManager();
m.GetTouchPanel().Press(42, 10.0f, 10.0f);
m.GetTouchPanel().Move(42, 20.0f, 10.0f);
m.GetTouchPanel().Release(42);
-
The GUI is now based on the Nuclex.Input library. That will allow me to soon
implement TouchPanel input and make the GUI usable on Windows Phone 7. Note that
you can easily hack Windows Phone 7 support into a project by converting
touch input into mouse input. Due to the modular design of Nuclex.Input, you don't
have to touch a single line of code, simple create your own
IInputCapturer!
-
The game state manager has undergone a redesign. Existing projects shouldn't be in
trouble, the redesign gets rid of the GameStateManager reference (you can remember
the Reference yourself if you want your states to initiate a transition themselves).
Pop-up game states similar to XNA's game state management example are now supported.
-
Upgraded to NMock 3.0. This is mostly an internal change but it really helps being
refactoring-friendly as my unit tests no longer contain method names hardcoded in
strings anymore.
-
All assemblies in the Nuclex Framework are now signed with a strong name, this no longer
preventing you from signing your own assemblies.
-
And of course, all issues that were reporting through various channels have been
fixed -- excluding two possible problems I can't yet reproduce, but will mention here
for honesty: the AffineThreadPool might sometimes be skipping a task under heavy load
and there might be a problem in the PrimitiveBatch when it is handed large amounts of
vertices. I couldn't reproduce these issues and they're not occurring in my own game,
but if anyone notices such an issue, please contact me!
|
|
Written by Markus Ewald
|
|
Friday, February 11 2011 12:10 |
|
I'm running a small home server that, amongst many other things, stores my
music collection, software, virtual machines and more. As any computer user
is able to testify, no matter how much hard drive space you've got on a rig,
you will run out of it eventually.
So last week, I decided to replace my aging 500 GB drives with three brand
new 2 TB drives (my choice fell on Western Digital's WD2000EARS drives, btw -
only 5400 RPM but dirt cheap and because this is for long-term storage, all
I want is space, not speed). I partitioned all three of them using the exact
same commands in fdisk (launched with fdisk -c -u /dev/sd*). Before
I did that, all drives appeared with identical informations when I ran
fdisk -c -u -l. Now?
The first drive now has 18 heads and 6 sectors/track:
Disk /dev/sdb: 2000.4 GB, 2000398934016 bytes
18 heads, 6 sectors/track, 36176196 cylinders, total 3907029168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xa28d6fec
Device Boot Start End Blocks Id System
/dev/sdb1 2048 3906996224 1953497088+ 83 Linux
The second one got 69 heads and also 6 sectors/track:
Disk /dev/sdd: 2000.4 GB, 2000398934016 bytes
69 heads, 6 sectors/track, 9437268 cylinders, total 3907029168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x78f7deaf
Device Boot Start End Blocks Id System
/dev/sdd1 2048 3906996224 1953497088+ 83 Linux
And the third one got 18 heads again, but only 3 sectors/track:
Disk /dev/sdc: 2000.4 GB, 2000398934016 bytes
18 heads, 3 sectors/track, 72352392 cylinders, total 3907029168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xbef707e2
Device Boot Start End Blocks Id System
/dev/sdc1 2048 3906996224 1953497088+ 83 Linux
I know that heads and sectors on modern hard drives no longer have any
relationship to the physical number of heads and sectors on the drive,
but why do I get 3 different results from running the same command 3 times,
on 3 identical drives?
They all have the same capacity in the end and my raid array is
running fine, but this confuses the hell out of me :D
|
|
Written by Markus Ewald
|
|
Thursday, December 09 2010 12:03 |
|
There has been a discussion on the XNA forums regarding a slight decrease in the visual quality
of SpriteFonts from XNA 3.1 to XNA 4.0: XNA 4.0 renders SpriteFont
differently (and not for the better).
There are two changes that might have impacted visual quality: XNA 4.0 uses premultiplied
alpha everywhere (whereas XNA 3.1 processed the alpha channel as-is) and, as revealed by
"Krome Studios", The FontDescriptionProcessor in XNA 4.0 generates
a texture with DXT3 (a form of compression that limits each block of 4x4 pixels to contain
only 4 different colors and reduces the alpha channel to 4 bits of precision or 16 levels,
see Wikipedia).
Because I've written a custom FontDescriptionProcessor for XNA 4.0 which outputs compatible
SpriteFonts but uses FreeType instead of Windows' GDI font
API, I decided to do a little comparison.
Read on for the results!
|
|
Written by Markus Ewald
|
|
Saturday, November 06 2010 14:56 |
|
More than a year ago, I did some benchmarking in XNA 3.1, comparing the vertex throughput I could
achieve on my GeForce 8800 via XNA's DynamicVertexBuffer
class versus just calling GraphicsDevice.DrawUserPrimitives().
Here's my earlier benchmark: Efficiently
Rendering Dynamic Vertices.
In all cases, DrawUserPrimitives() was marginally faster than the DynmicVertexBuffer, but it appeared
to be a very bad idea to use a DynamicVertexBuffer on the Xbox 360. I had a really nice
discussion with Shawn Hargreaves on the XNA forums where he provided a lot of in-depth information
about how things work on the Xbox 360: .
One of today's threads on
the AppHub forums reminded me if my earlier benchmarks, so I decided to dig out my old benchmark
and redo it in XNA 4.0. The benchmark uses my Nuclex Framework's PrimitiveBatch class,
which underwent some changes since then, so I repeated the XNA 3.1 benchmarks in addition to
getting the new data for XNA 4.0.
|
|
Written by Markus Ewald
|
|
Tuesday, October 12 2010 15:47 |
|
I just love listening to music in bed, right before going to sleep.
You can close your eyes and focus, experiencing the music like a movie
and less like the background noise music is often degraded to during
the day. After moving my home office to a different floor, however, my
bedroom is no longer close enough to my PC to do this (I used a rather
quirky solution, using a game pad to remote-control WinAmp and later
shut down my PC :D).
This put me on a quest for a replacement. Because I ripped my entire
CD library as FLAC
and stored it on my home server (running Gentoo
Linux and serving the music files as a network share via Samba),
I was looking for a player that supported FLAC and, ideally, would play
music from a standard network share. This is what I ultimately decided on:
That's a Logitech
Squeezebox Boom.
I admit that I half expected this category of devices to not exist at
all, because a "normal" person doesn't have a home server or a PC that's
always on. And when I found something I expected some half baked showpiece
hardware, but was yet again positively surprised. Read on for my personal
review of this brilliant device!
|
|
Written by Markus Ewald
|
|
Saturday, October 02 2010 13:19 |
|
There's a new release of the Nuclex Framework
available on CodePlex!
The new release adds a new library, Nuclex.Input, which is a very lightweight
library that adds seamless support for DirectInput game pads and joysticks,
well-behaving keyboard text input, event-based input and the ability to mock
any kind of input in your unit tests. Instead of firing up your XBox 360
each time, you can now write simple tests that simulate controllers being
attached and detached.
Also new is full support for XNA 4.0 on x86 and XBox 360. Windows Phone 7
is also supported by most of the libraries. The PC builds all target
the .NET Client Profile, allowing you to reduce the footprint of your
installer. Special .NET 4.0 client profile builds of the third-party
libraries (LZMA, NUnit, NMock, log4net and SlimDX).
Of course, all bugs reported since the last release have been fixed!
|
|
Written by Markus Ewald
|
|
Thursday, September 30 2010 14:16 |
|
Proponents of dependency injection try to design classes so they can either
work autonomously or get all services they rely on handed to them through
their constructor. But even without dependency injection, the situation often
arises where certain classes need to interact with a lot of other objects.
In these cases, you often end up with very complicated constructors and
a lot of duplicate code:
public class RadarBuildingRenderer {
public RadarBuildingRenderer(
ISceneGraph sceneGraph,
IContentManager contentManager,
IAudioManager audioManager,
RadarBuilding building
) {
this.sceneGraph = sceneGraph;
this.contentManager = contentManager;
this.audioManager = audioManager;
this.building = building;
}
private ISceneGraph sceneGraph;
private IContentManager contentManager;
private IAudioManager audioManager;
private RadarBuilding building;
}
Above class takes care of rendering the visual and audible representations
of a RadarBuilding in a computer game. As you can imagine,
the same references will be required by other buildings, think
TankFactoryBuilding, CommandCenterBuilding and so
on - all duplicating the fields, their assignment and the complex constructor.
|
|
Written by Markus Ewald
|
|
Monday, August 23 2010 15:12 |
|
Developers following my twitter feed may already know that in
the past few days, I've been working on a new component for
the Nuclex Framework: Nuclex.Input. This component aims to
solve all problems I ever had with input devices in XNA :)
It's a very simple library that provides input device classes
similar to the ones in XNA (Keyboard,
Mouse,
GamePad),
but instead of 4 game pads, there are 8 (with indexes 5-8 for
DirectInput-based controllers). All input devices
provide events (like KeyPressed and
CharacterEntered on the keyboard or
MouseWheelRotated on the mouse, for example).
Here's a quick run down of the features:
-
Well-behaving keyboard text input
- Honors keyboard layout and system locale
- Supports XBox 360 chat pads
- Very easy to use: just subscribe to an event
-
Support for standard PC game controllers
- Works with any DirectInput-compatible controller
-
Mouse movement with sub-pixel accuracy (postponed)
-
Allows event-based input handling
- Fully type-safe: events instead of message objects
- Only compares states if events have subscribers
- Mouse and keyboard don't have to compare states at all
-
Zero garbage: doesn't feed the garbage collector
Curious? Click on "Read More" to view some code samples!
This component will be in the next release of the Nuclex Framework!
If you want it now: Nightly builds,
Source code (svn)
|
|
Written by Markus Ewald
|
|
Thursday, August 19 2010 11:45 |
|
Last Friday (and I only now notice it was Friday the 13th :D) my screen stopped
working. I dismantled it and found some bad capacitors, then decided to do a small
foto story showing my attempt to get it working again:
My Screen went
Dark :-(.
Today the electronics components I ordered arrived and I could finally replace
those capacitors I found to be broken last time.
Soldering in the new capacitors was surprisingly easy. I remember that when I
did this in my childhood, I spread solder everywhere except where I wanted it to ;)
|
|
Written by Markus Ewald
|
|
Wednesday, September 15 2010 11:48 |
|
There are lots of small tricks a programmer learns over time. With this
post, I'm starting a little column called Code Better in which
I'll share some of my own tricks! If you want to show off some useful
tricks of your own, I'd be happy to publish them here, too :)
The first trick is a simple technique to make complicated if statements
more readable. Let's take a look at this beast:
// Only access the height field if the position is within
if(
(x >= 0) && (y >= 0) &&
(x < this.heightField.Width) &&
(y < this.heightField.Length)
) {
return this.heightField[x, y];
} else { // Position is outside the height field
return 0.0f;
}
The code isn't unreadable per se, but it takes more than a glance to
understand what's going on. The comments help, but there's a more
elegant way that makes those comments entirely redundant:
bool isInsideHeightField =
(x >= 0) &&
(y >= 0) &&
(x < this.heightField.Width) &&
(y < this.heightField.Length);
if(isInsideHeightField) {
return this.heightField[x, y];
} else {
return 0.0f;
}
The beauty in this is that the first thing you see is
bool isInsideHeightField, prominently positioned
at one indent less than the conditions. Your brain registers
the purpose of that block of code before it encounters the actual code.
The if below is also much more obvious. If the position
is inside the height field, look up the value in the height field,
otherwise return zero. Almost like reading english.
Finally, this level of obviousness eliminates the need for any
additional comments in the code!
|
|