/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_SortingMaterialIdGenerator.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include namespace nw { namespace gfx { NW_UT_RUNTIME_TYPEINFO_ROOT_DEFINITION(SortingMaterialIdGenerator); //---------------------------------------- IMaterialIdGenerator* SortingMaterialIdGenerator::Builder::Create( os::IAllocator* allocator ) { NW_NULL_ASSERT(allocator); void* memory = allocator->Alloc(sizeof(SortingMaterialIdGenerator)); NW_NULL_ASSERT(memory); MaterialKeyValueArray materials; MaterialKeyValueArray materialsWorkSpace; if (m_Description.isFixedSizeMemory) { materials = MaterialKeyValueArray(m_Description.maxMaterials, allocator); materialsWorkSpace = MaterialKeyValueArray(m_Description.maxMaterials, allocator); } else { materials = MaterialKeyValueArray(allocator); materialsWorkSpace = MaterialKeyValueArray(allocator); } SortingMaterialIdGenerator* generator = new(memory) SortingMaterialIdGenerator( allocator, materials, materialsWorkSpace); return generator; } //--------------------------------------------------------------------------- //! @brief ソート比較用関数オブジェクトです。 //--------------------------------------------------------------------------- struct MaterialKeyValueCompare : public std::binary_function { bool operator() (const internal::MaterialKeyValue& lhs, const internal::MaterialKeyValue& rhs) { return lhs.key < rhs.key; } }; struct MaterialSubKeyValueCompare : public std::binary_function { bool operator() (const internal::MaterialKeyValue& lhs, const internal::MaterialKeyValue& rhs) { return lhs.subKey < rhs.subKey; } }; struct MaterialUniqueIdCompare : public std::unary_function { bool operator() (const internal::MaterialKeyValue& keyValue, const u32 uniqueId) { return keyValue.uniqueId < uniqueId; } bool operator() (const u32 uniqueId, const internal::MaterialKeyValue& keyValue) { return keyValue.uniqueId > uniqueId; } }; //---------------------------------------- void SortingMaterialIdGenerator::Accept(Material* material) { internal::MaterialKeyValue materialKeyValue; materialKeyValue.key = reinterpret_cast(material->GetOriginal().ptr()); materialKeyValue.material = material; bool isPushed = m_Materials.push_back(materialKeyValue); NW_ASSERT(isPushed); } //---------------------------------------- void SortingMaterialIdGenerator::Generate() { // ResMaterialData を基にソートします。 std::sort( m_Materials.begin(), m_Materials.end(), nw::gfx::MaterialKeyValueCompare() ); u32 lastPtrKey = 0x0; u32 uniquePtrId = 0; // ResMaterialData が同一のノードを統合しつつ ResBinaryShaderData を基にキーを作成します。 MaterialKeyValueArray::iterator materialPtrEnd = m_Materials.end(); for (MaterialKeyValueArray::iterator iter = m_Materials.begin(); iter != materialPtrEnd; ++iter) { if (lastPtrKey != (*iter).key) { ++uniquePtrId; ResMaterial resMaterial = (*iter).material->GetOriginal(); NW_ASSERT(resMaterial.IsValid()); ResShaderProgramDescription resDescription = (*iter).material->GetDescription(); NW_ASSERT(resDescription.IsValid()); u32 key = reinterpret_cast(resDescription.GetOwnerShaderData()); internal::MaterialKeyValue materialKeyValue; materialKeyValue.uniqueId = uniquePtrId; materialKeyValue.key = key; materialKeyValue.subKey = resMaterial.GetFragmentLightingTableHash(); materialKeyValue.material = (*iter).material; m_MaterialsWorkSpace.push_back(materialKeyValue); lastPtrKey = (*iter).key; } (*iter).uniqueId = uniquePtrId; } // ResBinaryShaderData を基にソートします。 std::sort( m_MaterialsWorkSpace.begin(), m_MaterialsWorkSpace.end(), nw::gfx::MaterialKeyValueCompare() ); // ResBinaryShaderData が同一であるマテリアル列の内部を ResFragmentLightingTable の Hash 値を基にソートします。 u32 sortStartIndex = 0; u32 sortEndIndex = 0; u32 lastShaderKey = 0; u32 endIndex = m_MaterialsWorkSpace.size() - 1; for (int index = 0; index < endIndex + 1; ++index) { if (lastShaderKey != m_MaterialsWorkSpace[index].key || index == endIndex) { sortEndIndex = index; int diff = (sortEndIndex - sortStartIndex); // 同一キーが3ノード以上連続した場合にソートを行います。 if (diff >= 3) { std::sort(m_MaterialsWorkSpace.begin() + sortStartIndex, m_MaterialsWorkSpace.begin() + sortEndIndex, nw::gfx::MaterialSubKeyValueCompare() ); } sortStartIndex = index; } lastShaderKey = m_MaterialsWorkSpace[index].key; } // 統合したノードを展開しながら MaterialId を 1 から順に付けます。 u32 materialId = 1; MaterialKeyValueArray::iterator shaderEnd = m_MaterialsWorkSpace.end(); for (MaterialKeyValueArray::iterator shaderIter = m_MaterialsWorkSpace.begin(); shaderIter != shaderEnd; ++shaderIter) { ::std::pair range = equal_range(m_Materials.begin(), m_Materials.end(), (*shaderIter).uniqueId, MaterialUniqueIdCompare()); for (MaterialKeyValueArray::iterator ptrIter = range.first; ptrIter != range.second; ++ptrIter) { ResMaterial resMaterial = (*ptrIter).material->GetOriginal(); resMaterial.SetMaterialId( materialId ); ++materialId; } } // 生成後はマテリアルのリストを解放します。 m_Materials.clear(); m_MaterialsWorkSpace.clear(); } } // namespace gfx } // namespace nw