/**
 * Terminates (or disconnects from) SPURS.
 * Return is:
 * CELL_SPURS_OK if SPURS terminates ok, or if it was previously terminated/
 *   never initialized.
 * CELL_SPURS_EBUSY if there are existing Scenes which would need SPURS.
 */
int spursConfiguration_terminate() 
{
	if (!g_bSpursInitialized) 
	{
		return CELL_SPURS_OK;
	}

	if (g_uiSpursReferenceCounter) 
	{
		return CELL_SPURS_EBUSY;
	}
	int iReturn;
	bool bUserSpurs=g_bUserSpursGiven;

	g_bSpursInitialized=false;
	g_bUserSpursGiven=false;

	iReturn=cellSpursShutdownTaskset(&g_spursTaskSet);
	if (iReturn!=CELL_OK) 
	{
		return -1;
		//fprintf(stderr, "Bullet: Error shutting down SPURS task set: %i\n", iReturn);
	}

	iReturn=cellSpursJoinTaskset(&g_spursTaskSet);
	if (iReturn!=CELL_OK) 
	{
		return -2;
		//fprintf(stderr, "Bullet: Error joining SPURS task set: %i\n", iReturn);
	}

	if (!bUserSpurs) 
	{
		int iReturn=cellSpursFinalize(g_spursInstance);

		if (iReturn!=CELL_OK) 
		{
			return -3;
			//fprintf(stderr, "Bullet: Error shutting down SPURS: %d\n", iReturn);
		}

		free(g_spursInstance);
	}

	g_spursInstance=0;

	// Not loading SPURS task from file anymore
	//unloadBulletSpursElfs();
// printf code is commented out for the time being
//#warning TODO: Clean up SPU printf thread.

	return CELL_SPURS_OK;
}
hkDefaultDemo::~hkDefaultDemo()
{

#if HK_CONFIG_THREAD == HK_CONFIG_MULTI_THREADED

	if (m_jobThreadPool)
	{
		m_jobThreadPool->removeReferenceLockUnchecked();
	}

	delete m_jobQueue;

	if (m_spuUtil)
	{

		#if defined (HK_PLATFORM_PS3_PPU)
			// free resources if necessary
			int ret = cellSpursFinalize ( hkGetSpursInstance() );
			if (ret)
			{
				HK_ERROR(0x73e432b3, "cellSpursFinalize failed :" << ret);
			}
			void* spurs = hkGetSpursInstance();

			hkAlignedDeallocate<char>( (char*)spurs );
		#endif
	}
#endif

	for ( int i = 0; i < m_steppers.getSize(); ++i )
	{
		m_steppers[i]->removeReference();
	}

	if(m_mouseActive)
	{
		mouseUp();
	}
	if ( m_lastProgress )
	{
		delete m_lastProgress;
	}

	cleanupGraphics();

	for( int i = 0; i < m_delayedCleanup.getSize(); ++i )
	{
		m_delayedCleanup[i]->removeReference();
	}

	if (m_forcedShadowsOn)
	{
		m_env->m_options->m_enableShadows = false; // reset
	}
	else if (m_forcedShadowsOff)
	{
		m_env->m_options->m_enableShadows = true;// reset
	}
	
#if defined (HK_USE_CHARACTER_FACTORY)
 	if (m_characterFactory)
 	{
 		delete m_characterFactory;
 	}
#endif
}
int initializeSpursTaskSet(CellSpurs *pSpurs, int iSPUCount, uint8_t *puiPriorities) 
{
	uint8_t auiLocalPriorities[8]={1,1,1,1,1,1,1,1};
	uint8_t *pPriorities=auiLocalPriorities;
	int iReturn;
	int iNumSPUs=iSPUCount;

	// Not loading from a file anymore
// 	if (loadBulletSpursElfs()!=CELL_SPURS_OK) {
// 		fprintf(stderr, "Bullet: Cannot load SPURS programs.");
// 		return CELL_SPURS_EINVAL;
// 	}

	if (pSpurs) 
	{
		g_bUserSpursGiven=true;

		pPriorities=puiPriorities;
		iNumSPUs=iSPUCount;
		g_spursInstance=pSpurs;
	} 
	else 
	{
		g_bUserSpursGiven=false;

		// E We need to figure out the priority for the SPURS handler thread.
		// E We'll do this by getting the current thread priority, and making
		// E the SPURS handler thread slightly higher priority.
		sys_ppu_thread_t idCurrentThread;
		int iCurrentThreadPriority;

		iReturn=sys_ppu_thread_get_id(&idCurrentThread);
		if (iReturn!=CELL_OK) 
		{
			//fprintf(stderr, "Bullet: Cannot get current thread ID (%d)\n", iReturn);
			return CELL_SPURS_EINVAL;
		}

		iReturn=sys_ppu_thread_get_priority(idCurrentThread,
											&iCurrentThreadPriority);
		if (iReturn!=CELL_OK) 
		{
			//fprintf(stderr, "Bullet: Cannot get current thread priority (%d)\n", iReturn);
			return CELL_SPURS_EINVAL;
		}

		g_spursInstance=(CellSpurs *) memalign(128, sizeof(CellSpurs));
		if (!g_spursInstance)
		{
			//fprintf(stderr,"Cannot allocate room for SPURS\n");		
			return CELL_SPURS_EINVAL;
		}
		
		sys_spu_initialize(iNumSPUs, 0);
		// E Initialize spurs, setting SPU count, priorities, and letting SPURS
		// E know that it should NOT release the SPUs when there is no work to
		// E be done.
		iReturn=cellSpursInitialize(g_spursInstance, iNumSPUs,
									SPURS_SPU_THREAD_PRIORITY,
									iCurrentThreadPriority - 1, false);
		if (iReturn!=CELL_OK) 
		{
			//fprintf(stderr, "Bullet: Cannot initialize SPURS (%d)\n", iReturn);
			free(g_spursInstance);
			return CELL_SPURS_EINVAL;
		}
	}

	// Create SPU printf support.
//	sys_event_queue_attribute_t queue_attr;    /* Event queue attributes */

	// E Create an event queue that the SPU can use to send printf
	// E commands to the PPU for debugging.
// 	sys_event_queue_attribute_initialize(queue_attr);
// 	iReturn=sys_event_queue_create(&_g_SpuPrintfEventQueue, &queue_attr,
// 									_SpursSupportGetUniqueEventQueueKey(),
// 									SPU_PRINTF_EVENT_QUEUE_SIZE);
// 
// 	if (iReturn!=CELL_OK) 
// 	{
// 		return CELL_SPURS_EMISC;
// 	}

	// E We need a thread on the PPU side to handle SPU printf requests.
	// E It will wait indefinitely for messages in the queue we just created.
// 	iReturn = sys_ppu_thread_create (&_g_SpursPrintfThread,
// 										_SpursPrintfThreadMain, 
// 										(uint64_t) 0, SPU_PRINTF_THREAD_PRIO,
// 										SPU_PRINTF_THREAD_STACK_SIZE, 
// 										SYS_PPU_THREAD_CREATE_JOINABLE,
// 										"Bullet_spu_printf_handler");

// 	if (iReturn != CELL_OK) 
// 	{
// 		return CELL_SPURS_EMISC;
// 	}

	// E Now, we attach the PPU-side printf support to SPURS
// 	uint8_t uiPrintfPort=SPU_PRINTF_EVENT_QUEUE_PORT;
// 
// 	iReturn=cellSpursAttachLv2EventQueue(g_spursInstance, _g_SpuPrintfEventQueue,
// 										 &uiPrintfPort, 0);
// 	if (iReturn!=CELL_OK) {
// 		return CELL_SPURS_EMISC;
// 	}

	iReturn=cellSpursCreateTaskset(g_spursInstance, &g_spursTaskSet, 0, pPriorities,
								   iNumSPUs);

	if (iReturn!=CELL_OK) 
	{
		cellSpursFinalize(g_spursInstance);
		free(g_spursInstance);
		return CELL_SPURS_EINVAL;
	}

	g_bSpursInitialized=true;

	return CELL_SPURS_OK;
}