void draw_picker_colours (mat4 P, mat4 V, mat4 M[3]) {
	if (debug_colours) {
		glBindFramebuffer (GL_FRAMEBUFFER, 0);
	} else {
		glBindFramebuffer (GL_FRAMEBUFFER, g_fb);
	}
	glViewport (0, 0, g_gl_width, g_gl_height);
	glClearColor (0.0, 0.0, 0.0, 1.0);
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glUseProgram (g_pick_sp);
	// set colour
	vec3 id = encode_id (255);
	glUniform3f (g_pick_unique_id_loc, id.v[0], id.v[1], id.v[2]);
	glUniformMatrix4fv (g_pick_P_loc, 1, GL_FALSE, P.m);
	glUniformMatrix4fv (g_pick_V_loc, 1, GL_FALSE, V.m);
	glUniformMatrix4fv (g_pick_M_loc, 1, GL_FALSE, M[0].m);
	
	glBindVertexArray (g_sphere_vao);
	glDrawArrays (GL_TRIANGLES, 0, g_sphere_point_count);
	
	// 2nd sphere
	id = encode_id (65280);
	glUniformMatrix4fv (g_pick_M_loc, 1, GL_FALSE, M[1].m);
	glUniform3f (g_pick_unique_id_loc, id.v[0], id.v[1], id.v[2]);
	glDrawArrays (GL_TRIANGLES, 0, g_sphere_point_count);
	
	// 3rd sphere
	id = encode_id (16711680);
	glUniformMatrix4fv (g_pick_M_loc, 1, GL_FALSE, M[2].m);
	glUniform3f (g_pick_unique_id_loc, id.v[0], id.v[1], id.v[2]);
	glDrawArrays (GL_TRIANGLES, 0, g_sphere_point_count);
	
	glBindFramebuffer (GL_FRAMEBUFFER, 0);
}
ID SiNewShader(const char *plugin_name)
{
	struct Plugin **plugins = ScnGetPluginList(scene);
	struct Plugin *found = NULL;
	const int N = (int) ScnGetPluginCount(scene);
	int i = 0;

	for (i = 0; i < N; i++) {
		if (strcmp(plugin_name, PlgGetName(plugins[i])) == 0) {
			found = plugins[i];
			break;
		}
	}
	if (found == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}
	if (ScnNewShader(scene, found) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Shader, GET_LAST_ADDED_ID(Shader));
}
ID SiNewMesh(const char *filename)
{
	struct Mesh *mesh = NULL;
	struct Accelerator *acc = NULL;
	struct PrimitiveSet primset;

	mesh = ScnNewMesh(scene);
	if (mesh == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}
	if (MshLoadFile(mesh, filename)) {
		set_errno(SI_ERR_FAILLOAD);
		return SI_BADID;
	}

	acc = ScnNewAccelerator(scene, ACC_GRID);
	if (acc == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	MshGetPrimitiveSet(mesh, &primset);
	AccSetPrimitiveSet(acc, &primset);

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Accelerator, GET_LAST_ADDED_ID(Accelerator));
}
ID SiNewCurve(const char *filename)
{
	struct Curve *curve = NULL;
	struct Accelerator *acc = NULL;
	struct PrimitiveSet primset;

	curve = ScnNewCurve(scene);
	if (curve == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}
	if (CrvLoadFile(curve, filename)) {
		set_errno(SI_ERR_FAILLOAD);
		return SI_BADID;
	}

	acc = ScnNewAccelerator(scene, ACC_GRID);
	if (acc == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	CrvGetPrimitiveSet(curve, &primset);
	AccSetPrimitiveSet(acc, &primset);

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Accelerator, GET_LAST_ADDED_ID(Accelerator));
}
ID SiNewLight(const char *arg)
{
	if (ScnNewLight(scene, arg) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Light, GET_LAST_ADDED_ID(Light));
}
ID SiNewCamera(const char *arg)
{
	if (ScnNewCamera(scene, arg) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Camera, GET_LAST_ADDED_ID(Camera));
}
ID SiNewRenderer(void)
{
	if (ScnNewRenderer(scene) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Renderer, GET_LAST_ADDED_ID(Renderer));
}
ID SiNewTurbulence(void)
{
	if (ScnNewTurbulence(scene) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Turbulence, GET_LAST_ADDED_ID(Turbulence));
}
ID SiNewFrameBuffer(const char *arg)
{
	if (ScnNewFrameBuffer(scene) == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_FrameBuffer, GET_LAST_ADDED_ID(FrameBuffer));
}
ID SiNewVolume(void)
{
	struct Volume *volume = NULL;

	volume = ScnNewVolume(scene);
	if (volume == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Volume, GET_LAST_ADDED_ID(Volume));
}
/* TODO change argument name accelerator */
ID SiNewObjectInstance(ID accelerator)
{
	const struct Entry entry = decode_id(accelerator);

	if (entry.type == Type_Accelerator) {
		struct Accelerator *acc = NULL;

		acc = ScnGetAccelerator(scene, entry.index);
		if (acc == NULL) {
			set_errno(SI_ERR_BADTYPE);
			return SI_BADID;
		}

		/* TODO come up with another way to pass acc */
		if (ScnNewObjectInstance(scene, acc) == NULL) {
			set_errno(SI_ERR_FAILNEW);
			return SI_BADID;
		}
	}
	else if (entry.type == Type_Volume) {
		struct ObjectInstance *object = NULL;
		struct Volume *volume = NULL;
		int err = 0;

		volume = ScnGetVolume(scene, entry.index);
		if (volume == NULL) {
			set_errno(SI_ERR_BADTYPE);
			return SI_BADID;
		}

		object = ScnNewObjectInstance(scene, NULL);
		if (object == NULL) {
			set_errno(SI_ERR_FAILNEW);
			return SI_BADID;
		}

		err = ObjSetVolume(object, volume);
		if (err) {
			set_errno(SI_ERR_FAILNEW);
			return SI_BADID;
		}

	}
	else {
		set_errno(SI_ERR_BADTYPE);
		return SI_BADID;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_ObjectInstance, GET_LAST_ADDED_ID(ObjectInstance));
}
ID SiNewTexture(const char *filename)
{
	struct Texture *tex = NULL;

	tex = ScnNewTexture(scene);
	if (tex == NULL) {
		set_errno(SI_ERR_FAILNEW);
		return SI_BADID;
	}
	if (TexLoadFile(tex, filename)) {
		set_errno(SI_ERR_FAILLOAD);
		return SI_FAIL;
	}

	set_errno(SI_ERR_NONE);
	return encode_id(Type_Texture, GET_LAST_ADDED_ID(Texture));
}