QtScriptGenerator and QFile

QtScriptGenerator from Qt Labs is a great way of getting scripting functionality into your apps. However, one has to remember some simple rules – it’s Javascript. As such, you’d be forgiven for writing this:

var flibble = "Hello World";
var my_file = new QFile("hello.txt");
my_file.write(flibble);
my_file.close();

That, won’t work. In fact, it’ll bomb out at line 3 of that script and not close the file. So, obviously really, QFile::write() doesn’t actually support sending strings so, we need to convert it first:

var flibble = "Hello World";
var ba = QByteArray(flibble);
var my_file = new QFile("hello.txt");
my_file.write(ba);
my_file.close();

Job done. It seems really obvious when you think about it – but… heh I imagine someone might Google this at some point.

0 Comments

Green Man Gaming Launched – One week on

Last week, Green Man Gaming was launched and the world of digital distribution changed forever. I’m not just saying that because I’m one of the founders, I’m saying that because it really has done this.

There was a lot of people that doubted that it could be done from a technical point of view – and even why would publishers put games on the service? There was also a lot of SecuROM hating. In fact, I’ll briefly cover that now:

GMG doesn’t actually use any of the restrictive options of SecuROM bar one. The license reactivation of ‘x’ days. The value of x changes game to game depending on a number of different factors but all it really means is that the game just has to connect to the internet every few days. This is not the kind of constant internet connection that a certain publisher has been doing recently – but more the Spotify approach. That is, you can happy use the game offline – you just have to connect every now and again.

No Spyware is installed, nothing is actively hidden and tools are available from Sony DADC to remove any traces. I hate restrictive DRM, but since implementing SecuROM for Green Man Gaming, I can happily say that it got a bad name for reasons beyond Sony’s control. I’ve had no problems using it in VMWare/Parallels and in normal versions of Windows too. There’s been no tickets raised by customers on this topic either, which is great. Must be doing something right!

0 Comments

DLR Status now available on Tube Notify

It’s taken me a little longer than expected to get around to it – but if you load up Tube Notify on your iPhone now (no update to the application is required) you’ll see the DLR status has now appeared. Sorry it’s taken so long!

0 Comments

Lawsuit alleges Palm Pre violates GPL

The Palm Pré is a nifty little phone. However, the fact that you can view PDFs on it, albeit useful, is under scrutiny as it appears Palm failed to check the licenses of the software they were using.

When working on closed/embedded projects that you distribute, the GPL requires you to make you application open source as well – the LGPL requires you use the library in a DLL/.so form – it’s all fairly simple. License checking is time consuming but worthwhile as it means you end up with a product that you have at least tried to protect from potential lawsuits.

That also said, open source developers should consider dual licensing (a bit like Nokia with Qt). This way, if a large company wants to use your code, you make a reasonable amount of money out of it to fund the GPL/LGPL versions.

Doing it that way may well mean breaking Stallman’s view of the world – but there is his view… and the way the world actually works.

Lawsuit alleges Palm Pre violates copyright – Artifex, copyright, gpl, GPL violation – Techworld.

0 Comments

D3D Screenshots with Anti-Aliasing… quickly

A little while ago now, I looked at how d3dx is actually quite slow and looked at why that was and that it’s better to use Direct3D directly to do such things. Generally when one wants to take a screenshot, it needs to beveryfast as to not interfere with the gameplay. This post breaks down what to do when presented with an anti-aliased display so that screenshot taking is nice and quick:

	LPDIRECT3DSURFACE9 pd3dsBack = NULL;

	if ( SUCCEEDED ( device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pd3dsBack) ))
	{
		D3DSURFACE_DESC desc;
		pd3dsBack->GetDesc(&desc);

		LPDIRECT3DSURFACE9 pd3dsCopy = NULL;
		if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
		{
			if (SUCCEEDED(device->CreateRenderTarget(desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pd3dsCopy, NULL)))
			{
				if (SUCCEEDED(device->StretchRect(pd3dsBack, NULL, pd3dsCopy, NULL, D3DTEXF_NONE)))
				{
					pd3dsBack->Release();
					pd3dsBack = pd3dsCopy;
				}
				else
					pd3dsCopy->Release();
			}
		}
	}

The first thing you’ll notice is we grab the back buffer and query whether it has multi-sampling. If it is, we create a new render target and then render the scene onto it. This is far quicker to do than trying to take a shot of a multi-sampled scene as you’ve forced the GPU to do the rendering down onto a surface with no multi-sampling. Job done! That way you can then continue with LockRect() etc. and take the shot as you would do normally.

This makes taking shots of multi-sampled scenes not more than 1-2ms longer than those that aren’t. Enjoy!

1 Comment

Well surprise surprise – when an App is free – people download!

Over the last 48 hours, I offered Tube Notify for free on the App Store. I did this for one reason and one reason only. One has to spend money to make money. In this case, I wanted to get feedback on the app. The problem with the App Store is you can’t offer time limited demos to potential customers. Instead they make their purchase decision based on other factors. The main one being… Feedback.

150 people took advantage of the fact the app was free – that’s pretty good considering the fact that it’s no longer on the front page of the Travel Section. Out of that, I got 4 feedback reports and I now have a listed average! That average being 3/5. Can’t really grumble with that – so if you got the app for free and gave feedback, thank you.

Now to get to work on the next update for it…

0 Comments

Tube Notify hits the iPhone App Store

After 11 days of waiting, my first ever App hits iTunes. Regular readers of my posts (there are some, really) will have noticed what it was all about after seeing my Push on the iPhone post which covered doing Apple Push Notifications using Django on the server side. I did get around to pushing up a nice page on github to cover it and you can find that over at the django-iphone-push page.

Available on the App StoreThe app is called “Tube Status Push Notifications” and it is… available in the App Store for the small price of 59p. It would have been free, but paying for the server infrastructure that runs it means that I have to recoup at least some of the costs. You can find out more about the app over on the Tube Notify page.

During the approval process I was a bit put off by the fact that Tube Deluxe managed to get push notifications out the door first. I wrote this app while push notifications were quite new. I also did it as a learning exercise writing an application I wanted. When Tube Deluxe 4.0 came out, I did give it a go. It has some things better, some things worse. Here, however, is the main thing – Tube Notify takes < 10 seconds to load up, even on GPRS (the little round dot at the top). I built the app for speed on loading, no one wants to wait to read information.

So, in short, a different application that serves a different purpose. I didn’t write it to make a lot of money, I wrote it to learn the iPhone SDK and for myself. I then gave it to others to test for a few weeks and then here we are! I hope others enjoy using it in the field as much as I do!

0 Comments

Push on the iPhone

I have recently started doing development on the iPhone. It’s great fun. I am particularly interested in the Push aspect of this. I’m also a big fan of Python.

There’s a number of RESTful things that can be done with Ruby on Rails. However, the whole ‘packaged application’ thing is quite new to that framework. To Django, it’s the staple diet of how to get things done. So I’m currently part way through a generic application for Django for sending APN (Apple Push Notification) requests as well as dealing with the feedback connection.

Currently I have the push side working quite well. Just a warning, this is my first stab at this and it requires Python 2.6, or the relevant backports for ssl and json installed on 2.5.

from django.db import models
from django.conf import settings

from socket import socket

import datetime
import struct
import ssl
import binascii
import json

class iPhone(models.Model):
    """
    Represents an iPhone used to push

    udid - the iPhone Unique Push Identifier (64 chars of hex)
    last_notified_at - when was a notification last sent to the phone
    test_phone - is this a phone that should be included in test runs
    notes - just a small notes field so that we can put in things like "Lee's iPhone"
    failed_phone - Have we had feedback about this phone? If so, flag it.
    """
    udid = models.CharField(blank=False, max_length=64)
    last_notified_at = models.DateTimeField(blank=True, default=datetime.datetime.now)
    test_phone = models.BooleanField(default=False)
    notes = models.CharField(blank=True, max_length=100)
    failed_phone = models.BooleanField(default=False)

    class Admin:
        list_display = ('',)
        search_fields = ('',)

    def send_message(self, alert, badge=0, sound="chime", sandbox=True,
                        custom_params={}, action_loc_key=None, loc_key=None,
                        loc_args=[], passed_socket=None):
        """
        Send a message to an iPhone using the APN server, returns whether
        it was successful or not.

        alert - The message you want to send
        badge - Numeric badge number you wish to show, 0 will clear it
        sound - chime is shorter than default! Replace with None/"" for no sound
        sandbox - Are you sending to the sandbox or the live server
        custom_params - A dict of custom params you want to send
        action_loc_key - As per APN docs
        loc_key - As per APN docs
        loc_args - As per APN docs, make sure you use a list
        passed_socket - Rather than open/close a socket, use an already open one

        This requires IPHONE_APN_PUSH_CERT in settings.py to be the full
        path to the cert/pk .pem file.
        """
        aps_payload = {}

        alert_payload = alert
        if action_loc_key or loc_key or loc_args:
            alert_payload = {'body' : alert}
            if action_loc_key:
                alert_payload['action-loc-key'] = action_loc_key
            if loc_key:
                alert_payload['loc-key'] = loc_key
            if loc_args:
                alert_payload['loc-args'] = loc_args

        aps_payload['alert'] = alert_payload

        if badge:
            aps_payload['badge'] = badge

        if sound:
            aps_payload['sound'] = sound        

        payload = custom_params
        payload['aps'] = aps_payload

        s_payload = json.dumps(payload, separators=(',',':'))

        fmt = "!cH32sH%ds" % len(s_payload)
        command = '\x00'
        msg = struct.pack(fmt, command, 32, binascii.unhexlify(self.udid), len(s_payload), s_payload)

        if passed_socket:
            passed_socket.write(msg)
        else:
            host_name = 'gateway.sandbox.push.apple.com' if sandbox else 'gateway.push.apple.com'
            s = socket()
            c = ssl.wrap_socket(s,
                                ssl_version=ssl.PROTOCOL_SSLv3,
                                certfile=settings.IPHONE_APN_PUSH_CERT)
            c.connect((host_name, 2195))
            c.write(msg)
            c.close()

        return True

    def __unicode__(self):
        return u"iPhone %s" % self.udid

So how do we use it? Well rather easy. First you need to set up your certificates with Apple. You’ll need to set up a specific AppID and provisioning profile for your application (i.e. you can’t use *).

The guide on Apple’s site covers how to do this. Python needs it in a combined PEM format to work. Other sites claim you have to export from Keychain Access and that you’ll need to convert both to .pem. I only had to convert the private key:

openssl pkcs12 -in pkey.p12 -out pkey.pem -nodes -clcerts
cat cert.pem pkey.pem > iphone_ck.pem

I then altered my settings.py to have the new entry I added:

IPHONE_APN_PUSH_CERT = os.path.join(PROJECT_ROOT, "iphone_ck.pem")

Note the full path. I always have this at the top of settings.py to make my like easier:

import os
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

Now, it’s just case of making your iPhone app register with push and getting a unique ID. You have to use your real phone to do this. If you’re in a hurry and just want to test it out you can cheat and just pop this in applicationDidFinishLaunching delegate:

	// Register for push notifications
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

Then you probably want this to get the ID out into the console:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
	// Registration was successful so we'll
	// set up our device token etc.
	deviceToken = devToken;
	NSLog(@"devToken=%@",deviceToken);
    self.registered = YES;
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
	// This is expected on the emulator so that's fine
    NSLog(@"Error in registration. Error: %@", err);
}

Then you’ll be good to go! Run the app on the phone and the console will output the ID. Created an iPhone object and send a message. Job done.

10 Comments

Visual C++ Runtime Hell

Visual Studio post version 6 has an interesting time with its runtime library. For those that remember back that far, Visual C++ 6 used a library called msvcrt.dll / msvcrtd.dll. These libraries are included, to this day, in all versions of Windows and remain perfect compatible with Visual C++ 6 compiled binaries.

A lot of other analysis has gone into this on other blogs. I won’t repeat all of it here, but be sure to check out the blog of the KovoIRC developer.

Let’s start out with a simple program. It’s quite basic, but it’s a good starting point. I have made a small Win32 Console Project in Visual Studio making sure that I have made a directory made for the solution and the project directory sits within it.

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
  char* x = new char[100];

  memcpy(x, "Hello World", 11);
  puts(x);
  delete [] x;

  return 0;
}

Your first question is probably; Why are you creating a buffer using new then using memcpy and delete? The answer is that I want to make sure I use the new/delete operators. sprintf isn’t available, so I can’t use that.

Visual Studio Runtime Picker

Visual Studio Runtime Picker

Let’s statically link the runtime with it and produce a release executable. That produces a 53KB EXE. Ok, that’s not fair, there’s features in other runtimes we can’t use. So let’s turn off the security checking etc. Still 53KB.

Normal Static Linked Binary Size

Normal Static Linked Binary Size

Now we have our base point. Let’s do the following:

  1. Convert the solution directory to a GIT repo
  2. Add the git submodule from git://github.com/leepa/libctiny.git
  3. Add the new sub project to the solution in Visual Studio
  4. Add a Project Dependency to the HelloBlogPost project so it depends on MiniCrt

Git makes managing these things insanely easy. By using a git submodule you get to ensure you stay at the point you want to, but update it easily if needs be. Basically, it’s a great way of including 3rd party libraries in a project.

To do all this we can do the following (assuming msysGIT in Windows).

git.exe init
# You probably now want to do your
# adds/commits and .gitignore
# stuff
git.exe submodule add  -- "git://github.com/leepa/libctiny.git"  "libctiny"

Ace, now let’s try and compile again… 4KB. That’s a bit better isn’t it? The same program but a much small runtime footprint.

EXE Size with libctiny

EXE Size with libctiny

Isn’t that much better? For when you just need to do simple executable files, this can’t be beat. I can’t take credit for the library, I just added it a public Git repository and fixed a couple of new intrinsic functions that Visual Studio 2008 defines (ohama @ Google updated it to VS2005).

Credits: Under the Hood: Reduce EXE and DLL Size with LIBCTINY.LIB & omaha – Software installer and auto-updater for Windows.

0 Comments

d3dx – Not that great?

So, you’re writing a game, and you want to take a screenshot. The most common code sample you’ll probably find around the web will look something like this:

LPDIRECT3DSURFACE9 pd3dsBack = NULL;
LPDIRECT3DSURFACE9 pd3dsTemp = NULL;
if (SUCCEEDED(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pd3dsBack)))
{
    D3DSURFACE_DESC desc;
    pd3dsBack->GetDesc(&desc);
    if (SUCCEEDED(device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pd3dsTemp, NULL))
    {
        if (SUCCEEDED(device->GetRenderTargetData(pd3dsBack, pd3dsTemp)))
        {
            LPD3DXBUFFER pBuf;
            D3DXSaveSurfaceToFileInMemory(&pBuf, D3DXIFF_BMP, t, NULL, NULL);
        }
        pd3dsTemp->Release();
    }
    pd3dsBack->Release();
}

Now what’s wrong with that? You’ll end up with a BMP in pBuf and then you can do stuff with it, like save it. Or you can use the more direct D3DXSaveSurfaceToFile to save direct to disk (although, handy hint, push the buffer to a thread and save it outside of the rendering loop… no pause in the renderer then.

This code only works with non-multisampled displays too. There is way around that, that’s outside the scope of this post. So… what’s wrong using D3DX to save a picture? Let’s consider these issues that I have come up against:

  • It’s slow – very very slow. If you try and save a PNG it’ll take upwards of a second. JPG is faster!? BMP is fastest.
  • It sometimes doesn’t even take the shot – you’ll just get a bunch of zeroes

Yep, something isn’t quite right there. I’m using the November 2008 SDK and I get a bunch of zeroes from the surface in certain circumstances. Why? Well that’s a very good question. I have no idea why. However, if I make use of LockRect and copy the right bits out that way I get a 100% success rate of reading back the BackBuffer.

So, the surface clearly always has the data, but D3DX fails to read it properly. Obviously, without the source code to D3DXSaveSurfaceToFileInMemory I can’t do any more research into the matter. Taksi has some interesting samples on the topic (although it’s geared to copying the pitch data as well and in fact converting pitch, which you won’t always need to do).

0 Comments