Archive for the ‘Technology’ Category

Omni Consumer Products launches sandwich-purchasing app

April 11th, 2012

OCP's new iPhone app

16th and Mission’s The Sandwich Place is littered with signs for a new app for your phone that lets you order (and pay) online.

The app is apparently from Omni Consumer Products, best known for Delta City and their robot police force. Before you can say “I’ll buy that for a dollar!” let me point out that the app itself is free. All you gotta do is place your order, drive your 6000 SUX down to the restaurant and pick it up.

Using an Evoluent VerticalMouse 4 on Linux

April 10th, 2012

Evoluent’s VerticalMouse 4 is one of the better ergonomic computer mice I’ve used. It’s comfortable, it doesn’t take much getting used to, and the price isn’t unreasonable.

While it works great on Windows and Mac, the same can’t be said for Linux. The button mappings cause some truly odd behavior, particularly with the scroll wheel.

Fortunately, there’s a quick fix.

First let’s play with xinput to make sure the settings are what you want. The following command will print out a list of input devices on your system:

xinput list

There should be a line that looks something like this:

Evoluent VerticalMouse 4 id=10

The important thing here is the ID number, which in this case is 10. It will vary from one computer to the next.

Now we can assign a new button mapping. I like to keep it simple, so this will only activate the left and right mouse buttons (on either side of the scroll wheel) and will set the scroll wheel to scroll and act as middle click. If you want a different setup, I recommend reading this and this and playing with these values in xinput until your mouse does what you want.

xinput --set-button-map 10 1 3 0 4 5 0 0 0 2 0 0

Note that I bolded the first parameter: as you may have guessed, that 10 is whatever ID you found above.

Got it working? Good. Thing is, xinput will only temporarily set your mouse buttons. Once you reboot, they’re gone.

To make these changes persist we need to create an Xorg settings file. First we’ll need the USB ID of your mouse. The following command will list all the USB devices on your system:

lsusb

One of them should look kinda like this:

Bus 004 Device 004: ID 1a7c:0191 Evoluent VerticalMouse 4

The funny text I bolded is the device ID. (Again, it will likely be different on your system.) Now you can create a config file for your mouse. Note that this works on Ubuntu, perhaps your distro stores configuration files elsewhere.

sudo touch /usr/share/X11/xorg.conf.d/90-evoluent.conf
sudo gedit /usr/share/X11/xorg.conf.d/90-evoluent.conf

Copy and paste the following into the file, remembering to swap out your mouse’s USB ID and the button mapping string (if you changed it.)

Also, note that the button mapping string does NOT start with the device ID you used above; that was only for xinput.

Section "InputClass"
Identifier "Evoluent"
MatchUSBID "1a7c:0191"
Option "ButtonMapping" "1 3 0 4 5 0 0 0 2 0 0"
EndSection

Easy, right? Well okay, not at all. The lack of a good mouse configuration UI is a nasty oversight on modern Linux systems. Someone needs to make one.

How to setup Rhythmbox 2.95 as an Ampache client

April 2nd, 2012

Ampache, for those who don’t know, is a personal streaming music service. It lets you play your MP3s anywhere there’s an internet connection.

You don’t need anything special to play music via Ampache, just a web browser. But certain music applications integrate full Ampache support, which means you can browse all your MP3s from within the app.

On Linux, I use Rhythmbox to play music. There’s an Ampache client for it, but it’s not as easy to install as it should be with newer versions of Rhythmbox.

Here’s what worked for me.

  1. Make sure Rhythmbox is not currently running.
  2. Install or upgrade to Rhythmbox 2.95. For Ubuntu Oneiric, you can grab it off this PPA.
  3. If you don’t have it, install Subversion. Check out the code for the Ampache plugin:

    svn checkout http://rhythmbox-ampache.googlecode.com/svn/branches/for_rhythmbox-gtk+3/ rhythmbox-ampache-read-only

  4. Copy the files.

    cd rhythmbox-ampache-read-only/
    mkdir ~/.local/share/rhythmbox/plugins
    mv ampache/ ~/.local/share/rhythmbox/plugins

  5. Run the installer.

    cd ~/.local/share/rhythmbox/plugins/ampache
    sudo python setup.py install

  6. Now open Rhythmbox.
    • Go to Edit -> Plugins
    • Check the box next to “Ampache Library”
    • With Ampache Library selected, click “Preferences”
    • Enter your server info here.
    • Now close the dialog and double-click Ampache in the Rhythmbox sidebar.

It may take some time to sync with your server, but once it does you should be good to go. Personally I find this plugin to work a lot better than the Amache plugins for Amarok and Banshee, but your mileage may vary.

Dopefish Ex: Human Revolution

November 23rd, 2011

Dopefish screenshot from Deus Ex: Human Revolution

The image above is from the game Deus Ex: Human Revolution.

Recognize it? Remember the Dopefish? The big, dumb fish that appeared in the water level of Keen 4? If not, you missed out on the golden age of PC gaming. (Go buy a 386 and we’ll talk.)

Images of the Dopefish have been snuck into video games for nearly two decades. It’s like the “Andre the Giant Has a Posse” poster of gaming.

Incidentally, Deus Ex: Human Revolution contains a number of other subtle Easter Eggs.

Setting up Ubuntu as an iTunes music server

November 20th, 2011

If you’re like me, you’ve got a home network with a couple computers and a buttload of music in MP3, OGG, and FLAC format sitting on your Ubuntu server. You want to be able to keep all your music on that server, but play it from any computer.

What to do?

There’s a few solutions to this. If you want your music to play anywhere in the world, you can use Ampache. Ampache works great with Winamp and many other players. But on the downside, it requires some tricky setup and doesn’t work nicely with iTunes.

Another option is Forked-daapd, a strangely named piece of software that allows sharing your music with iTunes on a local network. It also works with iTunes compatible software such as Rhythmbox. Best of all, it’s super easy to setup.

This is all you have to do:

  1. Install the forked-daapd package. From the command line, you can do this:
    sudo apt-get install forked-daapd
  2. Edit /etc/forked-daapd.conf as root. Directions are in the file, but you’ll want to edit the directory to point to the path(s) of your music folders (it will recursively scan subfolders for mp3s, etc.) You may want to enable transcoding if you have OGG, FLAC or other formats that iTunes doesn’t like. Oh, and don’t forget to change the name of the share to something more fun.
  3. Restart forked-daapd with sudo /etc/init.d/forked-daapd restart

Now open iTunes and see if your server appears. It should show up on the sidebar. If you click on it, there will be a handful of songs almost immediately. It may take a while for Forked-daapd to index all your music, so be patient.

That’s it! Now you’re ready to party!

Programming in Vala

January 18th, 2011

As some of you may know, I work for an open source software non-profit called Yorba. Our best known product is Shotwell, a photo management application that’s similar to Picasa or iPhoto, but created for Linux. It’s the default photo app these days in both Ubuntu and Fedora.

What many of our users don’t know is we don’t develop our software in C or C++… we use Vala.

So what the hell is Vala?

The cool thing about Vala is that it’s a fully compiled, statically typed OOP language designed to be built for Gtk applications. The syntax is very similar to Java or C#, but the garbage collection is based entirely on reference counting. In other words, you get the simplicity of a modern language with the speed of a fully compiled program. Vala bindings are already available for Gtk, Gdk, GLib, Gee, and many other libraries. Or you can create your own bindings when needed by creating a Vapi file. There’s a documentation program, Valadoc, which generates pretty HTML documentation for your classes.

The entire Vala package is available under an LGPL license, which is a free software/open source license. You’ll never have to worry about Microsoft or Oracle stepping on your toes.

Here’s the “Hello World” app from the Vala tutorial.

class Demo.HelloWorld : GLib.Object {
    public static int main(string[] args) {
        stdout.printf("Hello, World\n");
        return 0;
    }
}

Save your file as hello.vala. You can compile from the command line with:
valac hello.vala
Now watch closely… the Vala compiler actually just creates a .c file! It’s what’s called a “source compiler” in that it converts source code from one language to source code in a different language.

Next, valac automatically invokes GCC to compile the .c file into an executable binary.

Run your demo code with:
./hello

Simple, huh?

Vala syntax includes the language constructs you’d expect in 2011, including:

  • interfaces
  • single inheritance
  • non-nullable variables
  • foreach loops
  • delegates
  • signals
  • reflection
  • built-in multidimensional arrays
  • type inference

There’s plenty more sample code and tutorials on Gnome’s Vala site.

Documentation for some of the most common library bindings is available at Valadoc.org.

Okay, ready for the bad news? Despite being a relatively feature-complete language, there’s really no perfect IDE for Vala yet. If you’re used to powerful graphical debuggers, class browsers, and jumping around the code like in Eclipse and Visual Studio, you’re out of luck.

The only Vala IDEs at the moment are:

  • MonoDevelop: A great start, but for the features it’s rather heavy.
  • Valide: I was never able to get this one to even compile! But the screenshots look promising.
  • Valencia: This is Yorba’s GEdit plugin, which provides only barebones Vala functionality on top of GEdit, including jump to definition and autocomplete.

So there you go, that’s Vala. It’s still a young language, but it takes away the headaches of developing Gtk apps in C, and it doesn’t have the uncomfortable legacies of C++. Give it a shot!

Inanimate Racer

October 22nd, 2010

Today I was surprised to find a (semi-serious) review of a game I created back in high school, “Inanimate Racer.” The point of the game was that you could only race objects that didn’t move.

Here’s the review:

If you’re interested in playing(?) Inanimate Racer, there’s also a Flash remake of the game available here.

Accelerated 2D graphics with OpenGL and SDL: part 1

October 13th, 2010

As some of you know, I’m working on an old-school puzzle game with Hryx. This game makes use of OpenGL’s graphics capabilities, but not for 3D graphics. Nope, the game is entirely two dimensional.

So why OpenGL? Because it’s really, really fast on most systems. Much faster than the slowpoke graphics in SDL.

This is going to be part one of a two part series on doing 2D graphics using OpenGL. And step one? Getting some 2D sprites loaded.

Loading the sprite with SDL_image
Now since we’re using SDL for our game, we decided on the excellent SDL_image to do the image loading.

Using SDL_image to load a sprite into memory is absurdly easy.

string filename = "myImage.png";
SDL_Surface* surface = IMG_Load( filename.c_str() );

That’s it!

But wait… that loads the graphic into an SDL surface. We need it to be an OpenGL texture! Damn.

OpenGL textures
In OpenGL, there’s no such thing as a “sprite.” You just have “textures.” So we’ll need to take our sprite and map it to a texture. The texture will be referenced with an integer (a GLuint) rather than a pointer.

But there’s an interesting restriction we have to work around that SDL simply doesn’t have. On most systems, OpenGL textures must have dimensions are are powers of two: 2, 4, 8, 16, and so on.

So once we load our SDL_Surface, we’ll make a new surface where we’ve rounded up the dimensions to the next highest power of two. The new surface will be filled with the alpha “color” and then we can blit (copy) over the existing image to the top left corner of our new image.

SDL_PixelFormat *format = surface->format;
Uint32 width = surface->w;
Uint32 height = surface->h;
Uint32 widthPow = (unsigned) pow( 2, ceil( log( width ) / log( 2 ) ) );
Uint32 heightPow = (unsigned) pow( 2, ceil( log( height ) / log( 2 ) ) );

// Create new empty surface.
SDL_Surface* newSurface = SDL_CreateRGBSurface( SDL_SRCALPHA,
	   widthPow, heightPow, 32,
	   rmask, bmask, gmask, amask );

// Fill sprite with alpha.
Uint32 alpha = 0;
alpha = SDL_MapRGBA( format, 0, 0, 0, amask );
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.h = heightPow;
rect.w = widthPow;
int ret = SDL_FillRect( newSurface, &rect, alpha);
surface->flags &= !SDL_SRCALPHA;

SDL_SetAlpha( newSurface, SDL_SRCALPHA, SDL_ALPHA_TRANSPARENT );

// Copy image data to our new surface.
ret = SDL_BlitSurface( surface, 0, newSurface, 0 );

Great, we got our surface loaded. Now it’s time to create an OpenGL texture, then take our SDL surface and copy it to the texture.

// This will be our OpenGL texture.
GLuint texture = 0;

// Bind the texture.
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
glGenTextures(1, &texture );
glBindTexture(GL_TEXTURE_2D, texture);

// Convert surface to Open GL format.
gluBuild2DMipmaps(GL_TEXTURE_2D, 4,
	widthPow, heightPow, GL_RGBA,GL_UNSIGNED_BYTE, newSurface->pixels);

// Free our temporary SDL buffers.
SDL_FreeSurface( surface );
SDL_FreeSurface( newSurface );

Easy, huh?

Dealing with 24-bit surfaces
Up until now we’ve only dealt with is 32-bit images. One thing I hadn’t dealt with until now is 24-bit color-keyed images. A color-keyed image means you have RGB but no alpha or “A” channel to tell you what should be invisible. Instead, you just take one color (often black) and just say that it’s 100% transparent.

What we’re going to have to do is make the SDL_surface color keyed before we copy it to the OpenGL texture.

First, we’re going to need some functions for plotting individual pixels on an SDL texture. Unfortunately there’s no built in functions for this, so I stole some from this site.

Uint32 GetPixel( SDL_Surface *surface, int x, int y )
{
	Uint32 color = 0;
	char* pPosition = ( char* ) surface->pixels;
	pPosition += ( surface->pitch * y );
	pPosition += ( surface->format->BytesPerPixel * x );
	memcpy ( &color , pPosition , surface->format->BytesPerPixel );
	return color;
}

void SetPixel( SDL_Surface *surface, int x, int y, Uint32 color )
{
	char* pPosition = ( char* ) surface->pixels;
	pPosition += ( surface->pitch * y );
	pPosition += ( surface->format->BytesPerPixel * x );
	memcpy ( pPosition , &color , surface->format->BytesPerPixel );
}

Cool, now we can plot pixels! Feel free to go crazy and write a routine to draw circles or something!

But all we really need to do here is to take pixels that correspond with our color key and set the alpha channel to the alpha mask channel color.

if ( 24 == format->BitsPerPixel )
{
   Uint32 colorKey = format->colorkey;

   for ( int y = 0; y < surface->h; ++y )
   {
	   for (int x = 0; x < surface->w; x++)
	   {
		   Uint32 color = GetPixel( surface, x, y );
		   if ( color == colorKey )
		   {
			   SetPixel( newSurface, x, y, 0 );
		   }
	   }
   }
}

Putting it all together
Here is the final code to load an image file to a texture using SDL.

#include 
#include 
#include 
#include 
#include 

#if SDL_BYTEORDER == SDL_LIL_ENDIAN
   static const Uint32 rmask = 0x000000FF;
   static const Uint32 bmask = 0x0000FF00;
   static const Uint32 gmask = 0x00FF0000;
   static const Uint32 amask = 0xFF000000;
#else
   static const Uint32 rmask = 0xFF000000;
   static const Uint32 bmask = 0x00FF0000;
   static const Uint32 gmask = 0x0000FF00;
   static const Uint32 amask = 0x000000FF;
#endif

Uint32 GetPixel( SDL_Surface *surface, int x, int y )
{
	Uint32 color = 0;
	char* pPosition = ( char* ) surface->pixels;
	pPosition += ( surface->pitch * y );
	pPosition += ( surface->format->BytesPerPixel * x );
	memcpy ( &color , pPosition , surface->format->BytesPerPixel );
	return color;
}

void SetPixel( SDL_Surface *surface, int x, int y, Uint32 color )
{
	char* pPosition = ( char* ) surface->pixels;
	pPosition += ( surface->pitch * y );
	pPosition += ( surface->format->BytesPerPixel * x );
	memcpy ( pPosition , &color , surface->format->BytesPerPixel );
}

GLuint loadTexture( std::string filename )
{
	SDL_Surface* surface = IMG_Load( filename.c_str() );

	if ( NULL == surface )
	{
	   // Error!
	   return 0;
	}

	SDL_PixelFormat *format = surface->format;
	Uint32 width = surface->w;
	Uint32 height = surface->h;
	Uint32 widthPow = (unsigned) pow( 2, ceil( log( width ) / log( 2 ) ) );
	Uint32 heightPow = (unsigned) pow( 2, ceil( log( height ) / log( 2 ) ) );

	// Create new empty surface.
	SDL_Surface* newSurface = SDL_CreateRGBSurface( SDL_SRCALPHA,
		   widthPow, heightPow, 32,
		   rmask, bmask, gmask, amask );

	// Fill sprite with alpha.
	Uint32 alpha = 0;
	alpha = SDL_MapRGBA( format, 0, 0, 0, amask );
	SDL_Rect rect;
	rect.x = 0;
	rect.y = 0;
	rect.h = heightPow;
	rect.w = widthPow;
	int ret = SDL_FillRect( newSurface, &rect, alpha);
	surface->flags &= !SDL_SRCALPHA;

	SDL_SetAlpha( newSurface, SDL_SRCALPHA, SDL_ALPHA_TRANSPARENT );

	// Copy image data to our new surface.
	ret = SDL_BlitSurface( surface, 0, newSurface, 0 );

	// Change color key to alpha transparency.
	// Used for 24-bit images.
	if ( 24 == format->BitsPerPixel )
	{
	   Uint32 colorKey = format->colorkey;

	   for ( int y = 0; y < surface->h; ++y )
	   {
		   for (int x = 0; x < surface->w; x++)
		   {
			   Uint32 color = GetPixel( surface, x, y );
			   if ( color == colorKey )
			   {
				   SetPixel( newSurface, x, y, 0 );
			   }
		   }
	   }
	}

	// This will be our OpenGL texture.
	GLuint texture = 0;

	// Bind the texture.
	glPixelStorei(GL_UNPACK_ALIGNMENT,4);
	glGenTextures(1, &texture );
	glBindTexture(GL_TEXTURE_2D, texture);

	// Convert surface to Open GL format.
	gluBuild2DMipmaps(GL_TEXTURE_2D, 4,
		widthPow, heightPow, GL_RGBA,GL_UNSIGNED_BYTE,
                newSurface->pixels);

	// Free our temporary SDL buffers.
	SDL_FreeSurface( surface );
	SDL_FreeSurface( newSurface );

	return texture;
}

That’s it! Next time: displaying our new OpenGL texture on the screen as a 2d sprite.

Site is back up… you jerk!

October 6th, 2010

Due to a mistake on my part, this site (and all my other sites) went dead today. Don’t worry, they’re all back up and chugging along nicely now. But this brings up a good question that I and many other webmasters have struggled with:

Why didn’t anyone tell that my sites were down?

Okay, there’s a few reasons you might think of off the top of your head:

  1. During that time, nobody tried to access your site(s).
    Okay, that’s possible. I mean if it was Google, maybe someone would have complained. But MrEricSir.com is only updated a couple times a week, so it’s possible (but statistically unlikely) that nobody tried to visit.

  2. The contact info is ON your site!
    Yes, but no. Plenty of people visit this site through Facebook, Twitter, and other sites where my contact info is easy to find. If you’re not a newbie, you can probably bring up my contact info in seconds. So while the average reader has this excuse, the more computer literate reader wouldn’t say this.
  3. Everyone thought “someone else will tell him.”
    Groupthink is actually a pretty good excuse. It’s like when the guy pulls over to the side of the freeway with smoke pouring out of his engine, and everyone goes driving by without stopping to help because we all assume that someone else will. There’s some merit to this line of reasoning.
  4. Nobody expects the internet to actually work.
    I think this is the number one reason. As our technology gets more complex, it develops more ways to fail. We aren’t surprised at all when a site like Twitter stops working, because hey, it stops working a few times a week. The problem is that unlike MrEricSir.com, there are actually a lot of critical systems out there that depends on the internet. The continued lowering of users’ expectations leads to shoddy work by engineers, and a vicious cycle of needlessly complex systems that fail often is created.

Now all this said, I don’t think that any of these are particularly good reasons. And that last one is downright scary. I’m not trying to pass the blame for my mistake. But when I see that something on the internet doesn’t work, I try to notify someone about it. Usually, they had no idea their site was broken.

As a webmaster I know from experience that fewer than 1 in 100 people will bother report problems; so as you can imagine, when someone bothers to send that e-mail, it’s very much appreciated.

Google is Evil

September 24th, 2010

Google is evil, and now I have proof!

1. Go to http://www.google.com
2. Type in “Google is evil” (without the quotes) and do NOT press enter
3. PROOF!

(Note: requires Google Instant, so this will not work on phones.)

Credit for this goes to 2600′s Google Blacklist.