bool RTree::save(PxOutputStream& stream) const
{
	// save the RTree root structure followed immediately by RTreePage pages to an output stream
	bool mismatch = (littleEndian() == 1);
	writeChunk('R', 'T', 'R', 'E', stream);
	writeDword(mVersion, mismatch, stream);
	writeFloatBuffer(&mBoundsMin.x, 4, mismatch, stream);
	writeFloatBuffer(&mBoundsMax.x, 4, mismatch, stream);
	writeFloatBuffer(&mInvDiagonal.x, 4, mismatch, stream);
	writeFloatBuffer(&mDiagonalScaler.x, 4, mismatch, stream);
	writeDword(mPageSize, mismatch, stream);
	writeDword(mNumRootPages, mismatch, stream);
	writeDword(mNumLevels, mismatch, stream);
	writeDword(mTotalNodes, mismatch, stream);
	writeDword(mTotalPages, mismatch, stream);
	writeDword(mUnused, mismatch, stream);
	for (PxU32 j = 0; j < mTotalPages; j++)
	{
		writeFloatBuffer(mPages[j].minx, RTreePage::SIZE, mismatch, stream);
		writeFloatBuffer(mPages[j].miny, RTreePage::SIZE, mismatch, stream);
		writeFloatBuffer(mPages[j].minz, RTreePage::SIZE, mismatch, stream);
		writeFloatBuffer(mPages[j].maxx, RTreePage::SIZE, mismatch, stream);
		writeFloatBuffer(mPages[j].maxy, RTreePage::SIZE, mismatch, stream);
		writeFloatBuffer(mPages[j].maxz, RTreePage::SIZE, mismatch, stream);
		WriteDwordBuffer(mPages[j].ptrs, RTreePage::SIZE, mismatch, stream);
	}

	return true;
}
bool writeHeader(NxI8 a, NxI8 b, NxI8 c, NxI8 d, NxU32 version, bool mismatch, NxStream& stream)
	{
	// Store endianness
	NxI8 streamFlags = littleEndian();
	if(mismatch)	streamFlags^=1;

	// Export header
	saveChunk('N', 'X', 'S', streamFlags, stream);	// "Novodex stream" identifier
	saveChunk(a, b, c, d, stream);					// Chunk identifier
//	stream.storeDword(version);						// Version number
	writeDword(version, mismatch, stream);

	return true;
	}
bool readHeader(NxI8 hdr1, NxI8 hdr2, NxI8 hdr3, NxI8& a, NxI8& b, NxI8& c, NxI8& d, NxU32& version, bool& mismatch, const NxStream& stream)
	{
	// Import header
	NxI8 h1, h2, h3, h4;
	readChunk(h1, h2, h3, h4, stream);
	if(h1!=hdr1 || h2!=hdr2 || h3!=hdr3)
		return false;

	NxI8 fileLittleEndian = h4&1;
	mismatch = fileLittleEndian!=littleEndian();

	readChunk(a, b, c, d, stream);

	version = readDword(mismatch, stream);
	return true;
	}
bool RTree::load(PxInputStream& stream, PxU32 meshVersion)
{
	PX_ASSERT((mFlags & IS_DYNAMIC) == 0);
	PX_UNUSED(meshVersion);

	release();

	PxI8 a, b, c, d;
	readChunk(a, b, c, d, stream);
	if(a!='R' || b!='T' || c!='R' || d!='E')
		return false;

	bool mismatch = (littleEndian() == 1);
	if(readDword(mismatch, stream) != mVersion)
		return false;

	readFloatBuffer(&mBoundsMin.x, 4, mismatch, stream);
	readFloatBuffer(&mBoundsMax.x, 4, mismatch, stream);
	readFloatBuffer(&mInvDiagonal.x, 4, mismatch, stream);
	readFloatBuffer(&mDiagonalScaler.x, 4, mismatch, stream);
	mPageSize = readDword(mismatch, stream);
	mNumRootPages = readDword(mismatch, stream);
	mNumLevels = readDword(mismatch, stream);
	mTotalNodes = readDword(mismatch, stream);
	mTotalPages = readDword(mismatch, stream);
	mUnused = readDword(mismatch, stream);

	mPages = static_cast<RTreePage*>(
		Ps::AlignedAllocator<128>().allocate(sizeof(RTreePage)*mTotalPages, __FILE__, __LINE__));
	Cm::markSerializedMem(mPages, sizeof(RTreePage)*mTotalPages);
	for (PxU32 j = 0; j < mTotalPages; j++)
	{
		readFloatBuffer(mPages[j].minx, RTreePage::SIZE, mismatch, stream);
		readFloatBuffer(mPages[j].miny, RTreePage::SIZE, mismatch, stream);
		readFloatBuffer(mPages[j].minz, RTreePage::SIZE, mismatch, stream);
		readFloatBuffer(mPages[j].maxx, RTreePage::SIZE, mismatch, stream);
		readFloatBuffer(mPages[j].maxy, RTreePage::SIZE, mismatch, stream);
		readFloatBuffer(mPages[j].maxz, RTreePage::SIZE, mismatch, stream);
		ReadDwordBuffer(mPages[j].ptrs, RTreePage::SIZE, mismatch, stream);
	}

	return true;
}
void AstRange::dump(ostream& str) {
    this->AstNode::dump(str);
    if (littleEndian()) str<<" [LITTLE]";
}