/* 
 * 
 * Confidential Information of Telekinesys Research Limited (t/a Havok).  Not for disclosure or distribution without Havok's
 * prior written consent.This software contains code, techniques and know-how which is confidential and proprietary to Havok.
 * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2008 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
 * 
 */

#include <Demos/demos.h>
#include <Demos/Common/Api/Serialize/SimpleLoad/SimpleLoadDemo.h>


// Serialize includes
#include <Common/Base/System/Io/IStream/hkIStream.h>
#include <Common/Base/Reflection/hkClass.h>
#include <Common/Base/Reflection/Registry/hkTypeInfoRegistry.h>
#include <Common/Serialize/Packfile/Binary/hkBinaryPackfileReader.h>
#include <Common/Serialize/Packfile/Xml/hkXmlPackfileReader.h>
#include <Common/Serialize/Util/hkStructureLayout.h>
#include <Common/Serialize/Util/hkRootLevelContainer.h>
#include <Common/Base/System/Io/FileSystem/hkNativeFileSystem.h>

// We can optionally version the packfile contents on load
// This requires linking with hkcompat
#define SIMPLE_LOAD_WITH_VERSIONING
#include <Common/Serialize/Version/hkVersionUtil.h>
#if defined(SIMPLE_LOAD_WITH_VERSIONING)
#	include <Common/Serialize/Version/hkVersionRegistry.h>
	void maybeVersionContents(hkPackfileReader* reader)
	{
		if( hkVersionUtil::updateToCurrentVersion( *reader, hkVersionRegistry::getInstance() ) != HK_SUCCESS )
		{
			HK_WARN_ALWAYS(0, "Couldn't update version, skipping.\n");
		}
	}
#else
	void maybeVersionContents(hkPackfileReader* reader)
	{
		if( hkString::strCmp( reader->getContentsVersion(), hkVersionUtil::getCurrentVersion() ) != 0 )
		{
			HK_WARN_ALWAYS(0, "Versioning is disabled, but file is from an older version.\n");
		}
	}
#endif

#include <Physics/Utilities/Serialize/hkpPhysicsData.h>

#include <Physics/Dynamics/Entity/hkpRigidBody.h>
#include <Physics/Dynamics/Phantom/hkpPhantom.h>


// We have a different binary file depending on the compiler and platform
static inline void SimpleLoadDemo_getBinaryFileName(hkString& e)
{
	e.printf("/Resources/simple_L%d%d%d%d.hkx", 
		hkStructureLayout::HostLayoutRules.m_bytesInPointer,
		hkStructureLayout::HostLayoutRules.m_littleEndian? 1 : 0,
		hkStructureLayout::HostLayoutRules.m_reusePaddingOptimization? 1 : 0,
		hkStructureLayout::HostLayoutRules.m_emptyBaseClassOptimization? 1 : 0);
}


SimpleLoadDemo::SimpleLoadDemo( hkDemoEnvironment* env) 
	: hkDefaultPhysicsDemo(env) 
{
	// Disable warning: 'm_contactRestingVelocity not set, setting it to REAL_MAX, so that the new collision restitution code will be disabled'
	hkError::getInstance().setEnabled(0xf03243ed, false);

	// Setup the camera
	{
		hkVector4 from(31, 31, 14);
		hkVector4 to(2.5f, -2, -.3f);
		hkVector4 up(0, 0, 1);
		setupDefaultCameras( env, from, to, up );
	}

	hkString path("Common/Api/Serialize/SimpleLoad");
	hkPackfileReader* reader = HK_NULL;
	{
		hkString fileName;

		switch (m_variantId)
		{
			case hkPackfileReader::FORMAT_BINARY:
			{
				SimpleLoadDemo_getBinaryFileName(fileName);
				reader = new hkBinaryPackfileReader();
				break;
			}
		
			case hkPackfileReader::FORMAT_XML:
			{
				fileName = "/Resources/simple.xml";
				reader = new hkXmlPackfileReader();	
				break;
			}

			default:
			{
				HK_ASSERT2(0xdbc0f1bd, 0, "Bad demo variant");
			}
		}

		path += fileName;
	}


	// Load the entire file
	// Open a stream to read the file
	hkStreamReader* strmrdr = hkNativeFileSystem::getInstance().openReader( path.cString() );
	hkIstream infile( strmrdr );
	strmrdr->removeReference();
	HK_ASSERT2( 0x215d080c, infile.isOk(), "Could not open '" << path.cString() << "' for reading." );

	// hkPackfileReader::detectFormat() will detect what format a file is (xml/binary).
	// You can use to make a generic loading function that sniffs a file contents, and
	// creates the appropriate type of hkPackfileReader.
	HK_ASSERT2( 0xdbcf8c61, m_variantId == hkPackfileReader::detectFormat(infile.getStreamReader()), "File is not in the correct format");

	reader->loadEntireFile(infile.getStreamReader());

	maybeVersionContents(reader);

	// Get a handle to the memory allocated by the reader, and add a reference to it.
	// This allows us to delete the reader.
	m_packfileData = reader->getPackfileData();
	m_packfileData->addReference();

	// Get the top level object in the file
	hkRootLevelContainer* container = static_cast<hkRootLevelContainer*>( reader->getContents( hkRootLevelContainerClass.getName() ) );
	HK_ASSERT2(0xa6451543, container != HK_NULL, "Could not load root level obejct" );

	m_physicsData = static_cast<hkpPhysicsData*>( container->findObjectByType( hkpPhysicsDataClass.getName() ) );
	HK_ASSERT2(0xa6451544, m_physicsData != HK_NULL, "Could not find physics data in root level object" );

	// We can now delete the reader. Note we still keep a reference to the allocated data.
	reader->removeReference(); // same as delete since we have the only reference

	HK_ASSERT2(0xa6451535, m_physicsData->getWorldCinfo() != HK_NULL, "No physics cinfo in loaded file - cannot create a hkpWorld" );


	// Create a world and add the physics systems to it
	m_world = new hkpWorld( *m_physicsData->getWorldCinfo() );
	m_world->lock();

	// Register all collision agents
	hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() );

	// Add all the physics systems to the world
	for ( int i = 0; i < m_physicsData->getPhysicsSystems().getSize(); ++i )
	{
		m_world->addPhysicsSystem( m_physicsData->getPhysicsSystems()[i] );
	}

	// Setup graphics - this creates graphics objects for all rigid bodies and phantoms in the world
	setupGraphics();

	m_world->unlock();
}

SimpleLoadDemo::~SimpleLoadDemo()
{
	// Re-enable warning
	hkError::getInstance().setEnabled(0xf03243ed, true);

	m_world->markForWrite();
	m_world->removeReference();
	m_world = HK_NULL;
	m_packfileData->removeReference();
}

hkDemo::Result SimpleLoadDemo::stepDemo()
{
	return hkDefaultPhysicsDemo::stepDemo();
}

#if defined(HK_COMPILER_MWERKS)
#	pragma force_active on
#	pragma fullpath_file on
#endif

static const char helpString[] = \
"This demo demonstrates how to load a simple physics file.";

enum
{
	BINARY	= hkPackfileReader::FORMAT_BINARY,
	XML		= hkPackfileReader::FORMAT_XML
};

HK_DECLARE_DEMO_VARIANT(SimpleLoadDemo, PRIME_SERIALIZE, "Binary",	BINARY ,	"Shows how to load a simple binary physics file", helpString);
HK_DECLARE_DEMO_VARIANT(SimpleLoadDemo, PRIME_SERIALIZE, "XML",		XML,	"Shows how to load a simple xml physics file", helpString);

/*
* Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20080529)
*
* Confidential Information of Havok.  (C) Copyright 1999-2008 
* Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
* Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
* rights, and intellectual property rights in the Havok software remain in
* Havok and/or its suppliers.
*
* Use of this software for evaluation purposes is subject to and indicates 
* acceptance of the End User licence Agreement for this product. A copy of 
* the license is included with this software and is also available at
* www.havok.com/tryhavok
*
*/
