text: // This code contains NVIDIA Confidential Information and is disclosed to you
  // under a form of NVIDIA software license agreement provided separately to you.
  //
  // Notice
  // NVIDIA Corporation and its licensors retain all intellectual property and
  // proprietary rights in and to this software and related documentation and
  // any modifications thereto. Any use, reproduction, disclosure, or
  // distribution of this software and related documentation without an express
  // license agreement from NVIDIA Corporation is strictly prohibited.
  //
  // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
  // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
  // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
  // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
  //
  // Information and code furnished is believed to be accurate and reliable.
  // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
  // information or for any infringement of patents or other rights of third parties that may
  // result from its use. No license is granted by implication or otherwise under any patent
  // or patent rights of NVIDIA Corporation. Details are subject to change without notice.
  // This code supersedes and replaces all information previously supplied.
  // NVIDIA Corporation products are not authorized for use as critical
  // components in life support devices or systems without express written approval of
  // NVIDIA Corporation.
  //
  // Copyright (c) 2008-2018 NVIDIA Corporation. All rights reserved.
  // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
  // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.  
  
  
  // PT: this file is a loader for "raw" binary files. It should NOT create SDK objects directly.
  
  #include <stdio.h>
  #include "foundation/PxPreprocessor.h"
  #include "RawLoader.h"
  #include "RendererColor.h"
  #include "RendererMemoryMacros.h"
  #include "SampleAllocatorSDKClasses.h"
  #include "PxTkFile.h"
  
  using namespace SampleRenderer;
  
  RAWObject::RAWObject() : mName(NULL)
  {
  	mTransform = PxTransform(PxIdentity);
  }
  
  RAWTexture::RAWTexture() :
  	mID			(0xffffffff),
  	mWidth		(0),
  	mHeight		(0),
  	mHasAlpha	(false),
  	mPixels		(NULL)
  {
  }
  
  RAWMesh::RAWMesh() :
  	mNbVerts		(0),
  	mNbFaces		(0),
  	mMaterialID		(0xffffffff),
  	mVerts			(NULL),
  	mVertexNormals	(NULL),
  	mVertexColors	(NULL),
  	mUVs			(NULL),
  	mIndices		(NULL)
  {
  }
  
  RAWShape::RAWShape() :
  	mNbVerts	(0),
  	mVerts		(NULL)
  {
  }
  
  RAWHelper::RAWHelper()
  {
  }
  
  RAWMaterial::RAWMaterial() :
  	mID				(0xffffffff),
  	mDiffuseID		(0xffffffff),
  	mOpacity		(1.0f),
  	mDoubleSided	(false)
  {
  	mAmbientColor	= PxVec3(0);
  	mDiffuseColor	= PxVec3(0);
  	mSpecularColor	= PxVec3(0);
  }
  
  #if PX_INTEL_FAMILY
  	static const bool gFlip = false;
  #elif PX_PPC
  	static const bool gFlip = true;
  #elif PX_ARM_FAMILY
  	static const bool gFlip = false;
  #else
  	#error Unknown platform!
  #endif
  
  	PX_INLINE void Flip(PxU32& v)
  	{
  		PxU8* b = (PxU8*)&v;
  
          PxU8 temp = b[0];
  		b[0] = b[3];
  		b[3] = temp;
  		temp = b[1];
  		b[1] = b[2];
  		b[2] = temp;
  	}
  
  	PX_INLINE void Flip(PxI32& v)
  	{
  		Flip((PxU32&)v);
  	}
  
  	PX_INLINE void Flip(PxF32& v)
  	{
  		Flip((PxU32&)v);
  	}
  
  static PxU8 read8(File* fp)
  {
  	PxU8 data;
  	size_t numRead = fread(&data, 1, 1, fp);
  	if(numRead != 1) { return 0; }
  	return data;
  }
  
  static PxU32 read32(File* fp)
  {
  	PxU32 data;
  	size_t numRead = fread(&data, 1, 4, fp);
  	if(numRead != 4) { return 0; }
  	if(gFlip)
  		Flip(data);
  	return data;
  }
  
  static PxF32 readFloat(File* fp)
  {
  	PxF32 data;
  	size_t numRead = fread(&data, 1, 4, fp);
  	if(numRead != 4) { return 0; }
  	if(gFlip)
  		Flip(data);
  	return data;
  }
  
  static PxTransform readTransform(File* fp, PxReal scale)
  {
  	PxTransform tr;
  	tr.p.x = scale * readFloat(fp);
  	tr.p.y = scale * readFloat(fp);
  	tr.p.z = scale * readFloat(fp);
  
  	tr.q.x = readFloat(fp);
  	tr.q.y = readFloat(fp);
  	tr.q.z = readFloat(fp);
  	tr.q.w = readFloat(fp);
  
  	PX_ASSERT(tr.isValid());
  
  	return tr;
  }
  
  static void readVertexArray(File* fp, PxVec3* verts, PxU32 nbVerts)
  {
  	const size_t size = 4*3*nbVerts;
  	size_t numRead = fread(verts, 1, size, fp);
  	if(numRead != size) { return; }
  
  	if(gFlip)
  	{
  		for(PxU32 j=0;j<nbVerts;j++)
  		{
  			Flip(verts[j].x);
  			Flip(verts[j].y);
  			Flip(verts[j].z);
  		}
  	}
  }
  
  static void readUVs(File* fp, PxReal* uvs, PxU32 nbVerts)
  {
  	const size_t size = 4*2*nbVerts;
  	size_t numRead = fread(uvs, 1, size, fp);
  	if(numRead != size) { return; }
  
  	if(gFlip)
  	{
  		for(PxU32 j=0;j<nbVerts*2;j++)
  			Flip(uvs[j]);
  	}
  }
  
  static void readVertices(File* fp, PxVec3* verts, PxU32 nbVerts, PxReal scale)
  {
  	readVertexArray(fp, verts, nbVerts);
  
  	for(PxU32 j=0;j<nbVerts;j++)
  		verts[j] *= scale;
  }
  
  static void readNormals(File* fp, PxVec3* verts, PxU32 nbVerts)
  {
  	readVertexArray(fp, verts, nbVerts);
  }
  
  static void readVertexColors(File* fp, PxVec3* colors, PxU32 nbVerts)
  {
  	readVertexArray(fp, colors, nbVerts);
  }
  
  static void readName(File* fp, char* objectName)
  {
  	PxU32 offset=0;
  	char c;
  	do
  	{
  		size_t numRead = fread(&c, 1, 1, fp);
  		if(numRead != 1) { c = '\0';}
  		objectName[offset++] = c;
  	}while(c);
  	objectName[offset]=0;
  }
  
  bool loadRAWfile(const char* filename, RAWImportCallback& cb, PxReal scale)
  {
  	File* fp = NULL;
  	PxToolkit::fopen_s(&fp, filename, "rb");
  	if(!fp)
  		return false;
  
  	// General info
  	const PxU32 tag				= read32(fp);
  	const PxU32 generalVersion	= read32(fp);
  	const PxU32 nbMaterials		= read32(fp);
  	const PxU32 nbTextures		= read32(fp);
  	const PxU32 nbMeshes		= read32(fp);
  	const PxU32 nbShapes		= read32(fp);
  	const PxU32 nbHelpers		= read32(fp);
  
  	(void)tag;
  	(void)generalVersion;
  	char objectName[512];
  
  	// Textures
  	for(PxU32 i=0;i<nbTextures;i++)
  	{
  		RAWTexture data;
  
  		readName(fp, objectName);
  		data.mName				= objectName;
  		data.mTransform			= PxTransform(PxIdentity);	// PT: texture transform not supported yet
  		data.mID				= read32(fp);
  
  		RendererColorAlloc* pixels = NULL;
  		if(read8(fp))
  		{
  			data.mWidth			= read32(fp);
  			data.mHeight		= read32(fp);
  			data.mHasAlpha		= read8(fp)!=0;
  			const PxU32 nbPixels = data.mWidth*data.mHeight; 
  			pixels				= SAMPLE_NEW(RendererColorAlloc)[nbPixels];
  			data.mPixels		= pixels;
  			for(PxU32 i=0;i<nbPixels;i++)
  			{
  				pixels[i].r = read8(fp);
  				pixels[i].g = read8(fp);
  				pixels[i].b = read8(fp);
  				if(data.mHasAlpha)
  					pixels[i].a = read8(fp);
  				else
  					pixels[i].a = 0xff;
  			}
  		}
  		else
  		{
  			data.mWidth			= 0;
  			data.mHeight		= 0;
  			data.mHasAlpha		= false;
  			data.mPixels		= NULL;
  		}
  
  		cb.newTexture(data);
  		DELETEARRAY(pixels);
  	}
  
  	// Materials
  	for(PxU32 i=0;i<nbMaterials;i++)
  	{
  		RAWMaterial data;
  		data.mID				= read32(fp);
  		data.mDiffuseID			= read32(fp);
  		data.mOpacity			= readFloat(fp);
  		data.mDoubleSided		= read32(fp)!=0;
  
  		data.mAmbientColor.x	= readFloat(fp);
  		data.mAmbientColor.y	= readFloat(fp);
  		data.mAmbientColor.z	= readFloat(fp);
  
  		data.mDiffuseColor.x	= readFloat(fp);
  		data.mDiffuseColor.y	= readFloat(fp);
  		data.mDiffuseColor.z	= readFloat(fp);
  
  		data.mSpecularColor.x	= readFloat(fp);
  		data.mSpecularColor.y	= readFloat(fp);
  		data.mSpecularColor.z	= readFloat(fp);
  
  		cb.newMaterial(data);
  	}
  
  	// Meshes
  	for(PxU32 i=0;i<nbMeshes;i++)
  	{
  		RAWMesh data;
  
  		readName(fp, objectName);
  		data.mName					= objectName;
  		data.mTransform				= readTransform(fp, scale);
  		//
  		data.mNbVerts				= read32(fp);
  		data.mNbFaces				= read32(fp);
  		const PxU32 hasVertexColors = read32(fp);
  		const PxU32 hasUVs			= read32(fp);
  		data.mMaterialID			= read32(fp);
  
  		PxVec3Alloc* tmpVerts		= SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
  		PxVec3Alloc* tmpNormals		= SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
  		PxVec3Alloc* tmpColors		= NULL;
  		PxReal* tmpUVs				= NULL;
  
  		data.mVerts					= tmpVerts;
  		data.mVertexNormals			= tmpNormals;
  		data.mVertexColors			= NULL;
  		data.mUVs					= NULL;
  
  		readVertices(fp, tmpVerts, data.mNbVerts, scale);
  		readNormals(fp, tmpNormals, data.mNbVerts);
  
  		if(hasVertexColors)
  		{
  			tmpColors = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
  			data.mVertexColors = tmpColors;
  			readVertexColors(fp, tmpColors, data.mNbVerts);
  		}
  
  		if(hasUVs)
  		{
  			tmpUVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*data.mNbVerts*2);
  			data.mUVs = tmpUVs;
  			readUVs(fp, tmpUVs, data.mNbVerts);
  		}
  
  		PxU32* tmpIndices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*data.mNbFaces*3);
  		data.mIndices = tmpIndices;
  		const size_t size = 4*3*data.mNbFaces;
  		size_t numRead = fread(tmpIndices, 1, size, fp);
  		if(numRead != size) 
  		{ 
  			SAMPLE_FREE(tmpIndices);
  			SAMPLE_FREE(tmpUVs);
  			DELETEARRAY(tmpColors);
  			DELETEARRAY(tmpNormals);
  			DELETEARRAY(tmpVerts);
  			return false; 
  		}
  		if(gFlip)
  		{
  			for(PxU32 j=0;j<data.mNbFaces*3;j++)
  			{
  				Flip(tmpIndices[j]);
  			}
  		}
  
  		cb.newMesh(data);
  
  		SAMPLE_FREE(tmpIndices);
  		SAMPLE_FREE(tmpUVs);
  		DELETEARRAY(tmpColors);
  		DELETEARRAY(tmpNormals);
  		DELETEARRAY(tmpVerts);
  	}
  
  	// Shapes
  	for(PxU32 i=0;i<nbShapes;i++)
  	{
  		RAWShape data;
  
  		readName(fp, objectName);
  		data.mName		= objectName;
  		data.mTransform = readTransform(fp, scale);
  		//
  		data.mNbVerts	= read32(fp);
  		PxVec3Alloc* tmp = SAMPLE_NEW(PxVec3Alloc)[data.mNbVerts];
  		data.mVerts		= tmp;
  		readVertices(fp, tmp, data.mNbVerts, scale);
  
  		cb.newShape(data);
  
  		DELETEARRAY(tmp);
  	}
  
  	// Helpers
  	for(PxU32 i=0;i<nbHelpers;i++)
  	{
  		RAWHelper data;
  
  		readName(fp, objectName);
  		data.mName		= objectName;
  		data.mTransform	= readTransform(fp, scale);
  	}
  	return true;
  }
  