/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ResMesh.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 27935 $ *---------------------------------------------------------------------------*/ #include "../precompiled.h" #include #include namespace nw { namespace gfx { namespace res { namespace { enum { BONE_INDEX_SCALE_INDEX = -2 }; //--------------------------------------------------------------------------- //! @brief 頂点属性のスケール値を表す値のコマンド中でのインデックスを取得します。 //! //! @param[in] usage 設定する頂点属性の Usage 値です。 //! //! @return m_IrScaleCommand 中の値のインデックスです。 //--------------------------------------------------------------------------- s32 QueryScaleCommandIndex(ResVertexAttribute::VertexAttributeUsage usage) { enum { BASE_INDEX = 2 }; switch (usage) { case ResVertexAttribute::USAGE_POSITION: return BASE_INDEX + 4; // attributeScales[0].x case ResVertexAttribute::USAGE_NORMAL: return BASE_INDEX + 3; // attributeScales[0].y case ResVertexAttribute::USAGE_TANGENT: return BASE_INDEX + 2; // attributeScales[0].z case ResVertexAttribute::USAGE_COLOR: return BASE_INDEX + 0; // attributeScales[0].w case ResVertexAttribute::USAGE_TEXTURECOODINATE0: return BASE_INDEX + 8; // attributeScales[1].x case ResVertexAttribute::USAGE_TEXTURECOODINATE1: return BASE_INDEX + 7; // attributeScales[1].y case ResVertexAttribute::USAGE_TEXTURECOODINATE2: return BASE_INDEX + 6; // attributeScales[1].z case ResVertexAttribute::USAGE_BONEWEIGHT: return BASE_INDEX + 5; // attributeScales[1].w case ResVertexAttribute::USAGE_BONEINDEX: return BONE_INDEX_SCALE_INDEX; // attributeScales[2].x case ResVertexAttribute::USAGE_USERATTRIBUTE0: // don't break; case ResVertexAttribute::USAGE_USERATTRIBUTE1: // don't break; case ResVertexAttribute::USAGE_USERATTRIBUTE2: // don't break; default: break; } return -1; } //--------------------------------------------------------------------------- //! @brief セパレートデータシェイプのIrScale //! //! @param[in] shape //! @param[in] shaderProgramDesc //--------------------------------------------------------------------------- void ResSeparateDataShape_SetupVertexIrScale( ResMesh mesh, ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ) { enum { ATTRIBUTE_SCALES_VECTOR_COUNT = 3 }; u32* command = &mesh.ref().m_IrScaleCommand[0]; mesh.ref().m_Flags &= ~(ResMesh::FLAG_HAS_VERTEX_ALPHA | ResMesh::FLAG_HAS_BONE_WEIGHT_W); std::memset(command, 0, sizeof(mesh.ref().m_IrScaleCommand)); command[0] = VERTEX_SHADER_UNIFORM_IRSCALE_INDEX | 0x80000000; command[1] = internal::MakeCommandHeader(PICA_REG_VS_FLOAT_ADDR, 1, false, 0xF); command[3] = internal::MakeCommandHeader(PICA_REG_VS_FLOAT0, 2 * 4, false, 0xF); internal::ResVertexAttributeIterator iter = internal::ResVertexAttributeIterator::Begin( shape ); ResVertexAttributeArray::iterator end = shape.GetVertexAttributes().end(); for ( ; iter.IsValid(); ++iter) { ResVertexAttribute attribute = *iter; int index = shaderProgramDesc.GetAttributeIndices(attribute.GetUsage()); // シェーダーに存在しない属性の場合は何もせずに終了する。 if (index < 0) { continue; } u8 dimension = 0; ResVertexAttribute::VertexAttributeUsage usage = ResVertexAttribute::USAGE_NONE; if (attribute.GetFlags() & ResVertexAttributeData::FLAG_VERTEX_PARAM) { ResVertexParamAttribute constantVertexAttribute(attribute.ptr()); dimension = constantVertexAttribute.GetDimension(); usage = static_cast(constantVertexAttribute.GetUsage()); s32 commandIndex = QueryScaleCommandIndex( usage ); if ( commandIndex >= 0 ) { command[ commandIndex ] = ut::Float32::Float32ToBits32(1.0f); } } else { ResVertexStream vertexStream(attribute.ptr()); dimension = vertexStream.GetDimension(); usage = static_cast(vertexStream.GetUsage()); f32 scale = vertexStream.GetScale(); s32 commandIndex = QueryScaleCommandIndex( usage ); if ( commandIndex >= 0 ) { command[ commandIndex ] = ut::Float32::Float32ToBits32(scale); } NW_ASSERT( ! ( (commandIndex == BONE_INDEX_SCALE_INDEX) && (scale != 1.0f)) ); } if (dimension == 4) { if (usage == ResVertexAttribute::USAGE_COLOR) { mesh.ref().m_Flags |= ResMesh::FLAG_HAS_VERTEX_ALPHA; } else if (usage == ResVertexAttribute::USAGE_BONEWEIGHT) { mesh.ref().m_Flags |= ResMesh::FLAG_HAS_BONE_WEIGHT_W; } } } } } //---------------------------------------- Result ResMesh::Setup(ResModel owner, os::IAllocator* allocator, ResGraphicsFile graphicsFile) { NW_UNUSED_VARIABLE(graphicsFile); Result result = RESOURCE_RESULT_OK; if (allocator == NULL) { allocator == CommandCacheManager::GetAllocator(); } ResShape shape = owner.GetShapes(this->GetShapeIndex()); ResMaterial material = owner.GetMaterials(this->GetMaterialIndex()); ResBinaryShader shader = material.GetShader().Dereference(); s32 shaderIndex = material.GetShaderProgramDescriptionIndex(); // ResModel::Setup で、シェーダの Setup が完了してから実行するので、 // 参照先のシェーダが見つからない場合は ASSERT。 NW_ASSERT( shader.IsValid() ); ResShaderProgramDescription shaderProgramDesc = shader.GetDescriptions( shaderIndex ); switch ( shape.GetTypeInfo() ) { case ResSeparateDataShape::TYPE_INFO: { ResSeparateDataShape separateShape = ResStaticCast( shape ); s32 activateCommandSize = internal::CalcSetupActivateVertexAttributeCommandSize(separateShape, shaderProgramDesc); s32 deactivateCommandSize = internal::CalcSetupDeactivateVertexAttributeCommandSize(separateShape, shaderProgramDesc); void* buffer = allocator->Alloc( activateCommandSize + deactivateCommandSize, 4 ); internal::CommandBufferInfo bufferInfo(buffer, activateCommandSize + deactivateCommandSize); internal::SetupVertexAttributeCommand(bufferInfo, separateShape, shaderProgramDesc); NW_ASSERT(bufferInfo.GetCurrentSize() == activateCommandSize); internal::SetupDeactivateVertexAttributeCommand(bufferInfo, separateShape, shaderProgramDesc); NW_ASSERT(bufferInfo.GetCurrentSize() == activateCommandSize + deactivateCommandSize); ref().m_ActivateCommandCache = buffer; ref().m_ActivateCommandCacheSize = activateCommandSize; ref().m_DeactivateCommandCache = nw::ut::AddOffsetToPtr( ref().m_ActivateCommandCache, activateCommandSize ); ref().m_DeactivateCommandCacheSize = deactivateCommandSize; ref().m_CommandAllocator = allocator; ResSeparateDataShape_SetupVertexIrScale( *this, separateShape, shaderProgramDesc ); } break; case ResParticleShape::TYPE_INFO: { //ResParticleShape particleShape = ResStaticCast( shape ); //internal::SetupVertexAttributeCommand(particleShape, shaderProgramDesc); } break; } if (result.IsSuccess()) { this->EnableFlags(ResMesh::FLAG_HAS_BEEN_SETUP); } return result; } //------------------------------------------------------------------------------ void ResMesh::Cleanup() { this->DisableFlags(ResMesh::FLAG_HAS_BEEN_SETUP); if ( ref().m_ActivateCommandCache != NULL ) { ref().m_CommandAllocator->Free(ref().m_ActivateCommandCache); ref().m_ActivateCommandCache = NULL; ref().m_ActivateCommandCacheSize = 0; if ( ref().m_DeactivateCommandCache != NULL ) { ref().m_DeactivateCommandCache = NULL; ref().m_DeactivateCommandCacheSize = 0; } } // Activate == NULL かつ Deactivate != NULL という事はありえない。 NW_ASSERT( ref().m_DeactivateCommandCache == NULL ); } } /* namespace res */ } /* namespace gfx */ } /* namespace nw */