Saturday, 21 June 2014

Not-So-Mini

Have you noticed how big retro small cars are becoming?

Take the Fiat 500. The original, from 1957, was a masterpiece of miniaturisation. The 50th anniversary reprise was heavier, longer, wider, taller, but almost certainly safer.


Volkswagen's 1997 re-imagining of the original Beetle was nowhere near as bloated. But then, the original Beetle wasn't a particularly small car.


 (Note that all the images here are to the same scale)

Another big (cough) culprit is BMW with their 21st century Mini ... sorry MINI ... series. The abandoned Mini Rocketman model would have reversed the trend, but as it is, they just keep getting bigger.

 

Sunday, 15 June 2014

Candy Crush Saga

Candy Crush Saga is undoubtedly the crack cocaine of casual games. Alas, I too have fallen victim to its dubious charms. So much so that I've decided to go cold turkey after reaching Level 100 ("proof" below).


Fortunately, I managed to get to this milestone without making any micro-payments or mugging pensioners on their way back from the Post Office for the price of an extra life.

So no more furtive "match three" highs for me: I'm on the wagon. If anyone sees me with a coconut wheel beneath my mouse, poised for a chained combo, you have my permission to slap me across the face and give me a shot of insulin.

Monday, 26 May 2014

I Couldn't Care Fewer T-Shirt

 
I brake all you're rule's.
And couldn't care fewer!

Wednesday, 23 April 2014

RGB/HSV in HLSL 5

It's been over three years since I started this thread on performing RGB/HSV conversions in HLSL. In those days, I was working with the XBox360 GPU, which has a component-wise 'max4' instruction that I took full advantage of. AMD's GCN architecture has 'min3'/'med3'/'max3' in hardware. However, the focus of GPU hardware designers seems to be shifting away from specialist SIMD pipelines. All this means that something like

  float V = max(R, max(G, B));

doesn't get optimised as well as you might hope.

But, given time, the Internet (or more specifically, Sam Hocevar and Emil Persson) comes up with the solution. And very elegant it is too.

HSV (and HSL) can be computed easily from HCV, where H is the hue [0..1], C is the chroma [0..1] and V is the value [0..1]. The core of a RGB-to-HCV conversion requires the RGB components to be sorted and the smallest and largest extracted:

  float U = min(R, min(G, B));
  float V = max(R, max(G, B));
  float C = V - U;

Any fool knows that three numbers can be sorted using, at most, three comparisons. So why are we doing (effectively) four comparisons? To make things worse, we then go on to compare the largest with the three components again to determine the hue offset.

So, here is the crux of Sam and Emil's optimization:

  float Epsilon = 1e-10;
  float4 P = (G < B) ? float4(B, G, -1.0, 2.0/3.0) : float4(G, B, 0.0, -1.0/3.0);
  float4 Q = (R < P.x) ? float4(P.xyw, R) : float4(R, P.yzx);
  float V = Q.x;
  float C = V - min(Q.w, Q.y);
  float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);

'Q.x' contains the largest RGB component, V, and either 'Q.w' or 'Q.y' contains the smallest, U. By shuffling components of P and Q, we get the hue offset and divisor "for free." Also note the cunning use of 'Epsilon' to remove the need to check for division-by-zero. More details here.

Once we have hue/chroma/value, we can compute the HSV saturation [0..1]:

  float S_hsv = C / (V + Epsilon);

Similarly, we can compute the HSL lightness [0..1] and saturation:

  float L = V - C * 0.5;
  float S_hsl = C / (1 - abs(L * 2 - 1) + Epsilon);

In terms of speed ... a notoriously difficult thing to estimate for GPU shaders ... this new RGB-to-HCV function is no slower than the old one and faster for many configurations.

However (and here I feel a tad smug), my original implementation of HSV-to-RGB is still faster than Sam's alternative. Though I'm sure that with a particularly aggressive optimizer on a more scalar configuration, there'd be hardly anything in it.

  float R = abs(H * 6 - 3) - 1;
  float G = 2 - abs(H * 6 - 2);
  float B = 2 - abs(H * 6 - 4);
  float3 RGB = ((saturate(float3(R,G,B)) - 1) * S + 1) * V;

I've placed the HLSL snippets on my main website; I hope no typos have crept in like last time.

For completeness, I've left in the HCY and HCL conversions.

Cocktail Transitions

Continuing my use of a JSON database of cocktails as a launch-pad for investigations into (fairly) recent HTML features, I've been looking at CSS3 transitions.

They're fiddly blighters and the rendering efficiency of different browsers varies appallingly, but they're interesting to play with.

Sunday, 16 March 2014

Computus 3

It's been a few years since my last look at calculating the date of Easter Sunday using only Z80 machine code, but I thought I'd finally re-visit it. In particular, I wanted to look in detail at Al Petrofsky's awesome optimizations of my lame attempts.



If you want a master-class in optimizing integer calculations on archaic CPUs (and who doesn't?) look no further than Al's solution. It's the product of deep understanding of:
  • The Z80 instruction set,
  • Integer multiplication-by-constants,
  • Integer division-by-constants,
  • Modulo arithmetic, and
  • Easter computus.
At only two hundred or so opcodes, and no branches, it's a beautiful distillation.

Saturday, 22 February 2014

Cocktail Venn Diagram

Many years ago, I worked on a project that involved creating a nice, clean database of alcoholic cocktails. That project never came to fruition, so the database has been languishing unused ever since. But then, on a Friday evening at work, we were discussing humorous data presentations whilst drinking cocktails. The two topics melded into an obvious question: "Has anyone done a Venn diagram of cocktails?"

The answer, according to Google Images, was "No!"

Then I remembered my under-used dataset, so I set to work coming up with some kind of Venn (or Euler) diagram. It turns out that these little blighters are quite difficult to construct beyond about four overlapping sets. Indeed, it is still a fairly active area of academic research.

I took my database of 289 drinks, and found the most common ingredients:
  1. vermouth (sweet and dry),
  2. gin,
  3. rum (dark and light),
  4. whisky,
  5. vodka,
  6. lemon juice,
  7. bitters (including Angostura),
  8. lime juice,
  9. orange juice, and
  10. brandy (including cognac)
I had planned to draw a diagram of those top ten ingredients, but quickly pruned it down to the six main, base spirits:
  1. vermouth,
  2. gin,
  3. rum,
  4. whisky,
  5. vodka, and
  6. brandy
This still turned out to be frustratingly difficult. But after an evening at the kitchen table with pencils and copious amounts of scrap paper, I came up with this:


It's almost symmetrical with the fortuitous but curious fact that no drink in my database contains both vodka and whisky.

A bit of time spent with Inkscape, JSON, HTML5 canvases and JavaScript allowed my to come up with an interactive web page demonstrating these intersections.