/*---------------------------------------------------------------------------* Project: NintendoWare File: lyt_Pane.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: 25594 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include #include using namespace nw::math; namespace nw { namespace lyt { namespace internal { PaneBase::PaneBase() { } PaneBase::~PaneBase() { } } // namespace nw::lyt::internal namespace local { namespace { #ifndef NW_PLATFORM_CTR inline void MultMatrixSRTxST( NW_LYT_WRITEONLY nw::math::MTX34* __restrict pMtx, const nw::math::MTX34* __restrict pMtxParent, const nw::math::VEC2* __restrict pScale, const nw::math::VEC3* __restrict pTransform) { //Ma . Mb // // = [ a00 a01 a02 a03 ] . [ b00 0 0 b03 ] // [ ] [ ] // [ a10 a11 a12 a13 ] [ 0 b11 0 b13 ] // [ ] [ ] // [ a20 a21 a22 a23 ] [ 0 0 1 b23 ] // [ ] [ ] // [ 0 0 0 1 ] [ 0 0 0 1 ] // // = [ a00*b00 a01*b11 a02 a02*b23 + a01*b13 + a00*b03 + a03 ] // [ ] // [ a10*b00 a11*b11 a12 a12*b23 + a11*b13 + a10*b03 + a13 ] // [ ] // [ a20*b00 a21*b11 a22 a22*b23 + a21*b13 + a20*b03 + a23 ] // [ ] // [ 0 0 0 1 ] register const f32 b00 = pScale->x; register const f32 b11 = pScale->y; register const f32 b03 = pTransform->x; register const f32 b13 = pTransform->y; register const f32 b23 = pTransform->z; register const f32 a00 = pMtxParent->m[0][0]; register const f32 a01 = pMtxParent->m[0][1]; register const f32 a02 = pMtxParent->m[0][2]; register const f32 a03 = pMtxParent->m[0][3]; register const f32 a10 = pMtxParent->m[1][0]; register const f32 a11 = pMtxParent->m[1][1]; register const f32 a12 = pMtxParent->m[1][2]; register const f32 a13 = pMtxParent->m[1][3]; register const f32 a20 = pMtxParent->m[2][0]; register const f32 a21 = pMtxParent->m[2][1]; register const f32 a22 = pMtxParent->m[2][2]; register const f32 a23 = pMtxParent->m[2][3]; pMtx->m[0][0] = a00 * b00; pMtx->m[0][1] = a01 * b11; pMtx->m[0][2] = a02; pMtx->m[0][3] = a02 * b23 + a01 * b13 + a00 * b03 + a03; pMtx->m[1][0] = a10 * b00; pMtx->m[1][1] = a11 * b11; pMtx->m[1][2] = a12; pMtx->m[1][3] = a12 * b23 + a11 * b13 + a10 * b03 + a13; pMtx->m[2][0] = a20 * b00; pMtx->m[2][1] = a21 * b11; pMtx->m[2][2] = a22; pMtx->m[2][3] = a22 * b23 + a21 * b13 + a20 * b03 + a23; } #else // NW_PLATFORM_CTR #include asm void MultMatrixSRTxST( NW_LYT_WRITEONLY nw::math::MTX34* __restrict /*pMtx*/, const nw::math::MTX34* __restrict /*pMtxParent*/, const nw::math::VEC2* __restrict /*pScale*/, const nw::math::VEC3* __restrict /*pTransform*/) { //Ma . Mb // // = [ a00 a01 a02 a03 ] . [ b00 0 0 b03 ] // [ ] [ ] // [ a10 a11 a12 a13 ] [ 0 b11 0 b13 ] // [ ] [ ] // [ a20 a21 a22 a23 ] [ 0 0 1 b23 ] // [ ] [ ] // [ 0 0 0 1 ] [ 0 0 0 1 ] // // = [ a00*b00 a01*b11 a02 a02*b23 + a01*b13 + a00*b03 + a03 ] // [ ] // [ a10*b00 a11*b11 a12 a12*b23 + a11*b13 + a10*b03 + a13 ] // [ ] // [ a20*b00 a21*b11 a22 a22*b23 + a21*b13 + a20*b03 + a23 ] // [ ] // [ 0 0 0 1 ] #define a00 s0 #define a01 s1 #define a02 s2 #define a03 s3 #define a10 s4 #define a11 s5 #define a12 s6 #define a13 s7 #define a20 s8 #define a21 s9 #define a22 s10 #define a23 s11 #define b00 s12 #define b11 s13 #define b03 s12 #define b13 s13 #define b23 s14 VLDMIA r1,{a00-a23} VLDMIA r3,{b03,b13,b23} VMLA.F32 a03,a00,b03 VMLA.F32 a13,a10,b03 VMLA.F32 a23,a20,b03 VMLA.F32 a03,a01,b13 VMLA.F32 a13,a11,b13 VMLA.F32 a23,a21,b13 VMLA.F32 a03,a02,b23 VLDMIA r2,{b00,b11} VMLA.F32 a13,a12,b23 VMLA.F32 a23,a22,b23 VMUL.F32 a00,a00,b00 VMUL.F32 a01,a01,b11 VMUL.F32 a10,a10,b00 VMUL.F32 a11,a11,b11 VMUL.F32 a20,a20,b00 VMUL.F32 a21,a21,b11 VSTMIA r0,{a00-a23} // 結果をストア BX lr #undef a00 #undef a01 #undef a02 #undef a03 #undef a10 #undef a11 #undef a12 #undef a13 #undef a20 #undef a21 #undef a22 #undef a23 #undef b00 #undef b11 #undef b03 #undef b13 #undef b23 } #include #endif // NW_PLATFORM_CTR // Scale、Rotate、Transの設定 inline void MakeMatrixSRT(NW_LYT_WRITEONLY nw::math::MTX34& o, const nw::math::VEC2& s, const f32 rotateZ, const nw::math::VEC3& t) { register f32 sin, cos; nn::math::SinCosDeg(&sin, &cos, rotateZ); const f32 tmp0 = s.x * cos; const f32 tmp1 = -s.y * sin; const f32 tmp2 = s.x * sin; const f32 tmp3 = s.y * cos; o.m[0][0] = tmp0; o.m[0][1] = tmp1; o.m[0][2] = 0.f; o.m[0][3] = t.x; o.m[1][0] = tmp2; o.m[1][1] = tmp3; o.m[1][2] = 0.f; o.m[1][3] = t.y; o.m[2][0] = 0.f; o.m[2][1] = 0.f; o.m[2][2] = 1.f; o.m[2][3] = t.z; } inline void MakeMatrixSRT(NW_LYT_WRITEONLY nw::math::MTX34& o, const nw::math::VEC2& s, const nw::math::VEC3& r, const nw::math::VEC3& t) { register f32 sinx, cosx; register f32 siny, cosy; register f32 sinz, cosz; nn::math::SinCosDeg(&sinx, &cosx, r.x); nn::math::SinCosDeg(&siny, &cosy, r.y); nn::math::SinCosDeg(&sinz, &cosz, r.z); const f32 opt1 = cosx * cosz; const f32 opt2 = sinx * siny; const f32 opt3 = cosx * sinz; const f32 tmp00 = s.x * (cosy * cosz); const f32 tmp10 = s.x * (cosy * sinz); const f32 tmp20 = s.x * (-siny); const f32 tmp01 = s.y * ((opt2 * cosz) - (opt3)); const f32 tmp11 = s.y * ((opt2 * sinz) + (opt1)); const f32 tmp21 = s.y * ((sinx * cosy)); const f32 tmp02 = (opt1 * siny) + (sinx * sinz); const f32 tmp12 = (opt3 * siny) - (sinx * cosz); const f32 tmp22 = (cosx * cosy); o.m[0][0] = tmp00; o.m[0][1] = tmp01; o.m[0][2] = tmp02; o.m[0][3] = t.x; o.m[1][0] = tmp10; o.m[1][1] = tmp11; o.m[1][2] = tmp12; o.m[1][3] = t.y; o.m[2][0] = tmp20; o.m[2][1] = tmp21; o.m[2][2] = tmp22; o.m[2][3] = t.z; } } // namespace nw::lyt::local::{anonymous} } // namespace nw::lyt::local NW_UT_RUNTIME_TYPEINFO_ROOT_DEFINITION(Pane); // 実行時型情報の実体を定義 Pane::Pane() { NW_COMPILER_ASSERT( (sizeof(m_Translate) + sizeof(m_Rotate) + sizeof(m_Scale) + sizeof(m_Size)) / sizeof(f32) == ANIMTARGET_PANE_MAX ); using namespace std; Init(); m_BasePosition = HORIZONTALPOSITION_CENTER + VERTICALPOSITION_CENTER * VERTICALPOSITION_MAX; memset(m_Name, 0, sizeof(m_Name)); memset(m_UserData, 0, sizeof(m_UserData)); m_Translate = VEC3(0, 0, 0); m_Rotate = VEC3(0, 0, 0); m_Scale = VEC2(1, 1); m_Size = Size(0.f, 0.f); m_Alpha = ut::Color8::ALPHA_MAX; m_GlbAlpha = m_Alpha; SetVisible(true); } Pane::Pane(const res::Pane* pBlock) { using namespace std; Init(); m_BasePosition = pBlock->basePosition; SetName(pBlock->name); SetUserData(pBlock->userData); m_Translate = pBlock->translate; m_Rotate = pBlock->rotate; m_Scale = pBlock->scale; m_Size = pBlock->size; m_Alpha = pBlock->alpha; m_GlbAlpha = m_Alpha; m_Flag = pBlock->flag; } void Pane::Init() { m_pParent = 0; m_Flag = 0; m_pExtUserDataList = 0; #ifdef NW_LYT_FULLCACHEDRAWMANAGER_ENABLE m_UniversalFlag = 0; #endif MTX34Identity(&m_Mtx); MTX34Identity(&m_GlbMtx); } Pane::~Pane() { // OSReport("Pane::~Pane()\n"); // 子供Paneの後処理 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter();) { PaneList::Iterator currIt = it++; m_ChildList.Erase(currIt); if (! currIt->IsUserAllocated()) { Layout::DeleteObj(&(*currIt)); } } UnbindAnimationSelf(0); } void Pane::SetName(const char* name) { ut::strcpy(m_Name, sizeof(m_Name), name); } void Pane::SetUserData(const char* userData) { ut::strcpy(m_UserData, sizeof(m_UserData), userData); } void Pane::AppendChild(Pane* pChild) { InsertChild(m_ChildList.GetEndIter(), pChild); } void Pane::PrependChild(Pane* pChild) { InsertChild(m_ChildList.GetBeginIter(), pChild); } void Pane::InsertChild( Pane* pNext, Pane* pChild ) { NW_NULL_ASSERT(pNext); NW_ASSERT(pNext->m_pParent == this); InsertChild(m_ChildList.GetIteratorFromPointer(pNext), pChild); } void Pane::InsertChild( PaneList::Iterator next, Pane* pChild ) { NW_NULL_ASSERT(pChild); NW_ASSERT(pChild->m_pParent == 0); m_ChildList.Insert(next, pChild); pChild->m_pParent = this; } void Pane::RemoveChild(Pane* pChild) { NW_NULL_ASSERT(pChild); NW_ASSERT(pChild->m_pParent == this); m_ChildList.Erase(pChild); pChild->m_pParent = NULL; } const ut::Rect Pane::GetPaneRect() const { ut::Rect ret; VEC2 basePt = GetVtxPos(); ret.left = basePt.x; ret.top = basePt.y; ret.right = ret.left + m_Size.width; ret.bottom = ret.top - m_Size.height; return ret; } const ut::Color8 Pane::GetVtxColor(u32 idx) const { NW_UNUSED_VARIABLE(idx) return ut::Color8::WHITE; } void Pane::SetVtxColor( u32 idx, ut::Color8 value ) { NW_UNUSED_VARIABLE(idx) NW_UNUSED_VARIABLE(value) } u8 Pane::GetColorElement(u32 idx) const { NW_ASSERT(idx < ANIMTARGET_PANE_COLOR_MAX); switch (idx) { case ANIMTARGET_PANE_ALPHA: return m_Alpha; default: return GetVtxColorElement(idx); } } void Pane::SetColorElement( u32 idx, u8 value ) { NW_ASSERT(idx < ANIMTARGET_PANE_COLOR_MAX); switch (idx) { case ANIMTARGET_PANE_ALPHA: m_Alpha = value; break; default: SetVtxColorElement(idx, value); } } u8 Pane::GetVtxColorElement(u32 idx) const { NW_UNUSED_VARIABLE(idx) return ut::Color8::ELEMENT_MAX; } void Pane::SetVtxColorElement( u32 idx, u8 value) { NW_UNUSED_VARIABLE(idx) NW_UNUSED_VARIABLE(value) } Pane* Pane::FindPaneByName( const char* findName, bool bRecursive ) { if (internal::EqualsResName(m_Name, findName)) { return this; } if (bRecursive) { // 子供に一致するものが無いか検索 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { if (Pane* pPane = it->FindPaneByName(findName, bRecursive)) { return pPane; } } } return 0; } Material* Pane::FindMaterialByName( const char* findName, bool bRecursive ) { u32 nbMaterial = GetMaterialNum(); for (u32 idx = 0; idx < nbMaterial; ++idx) { Material* pMaterial = GetMaterial(idx); if (pMaterial) { if (internal::EqualsMaterialName(pMaterial->GetName(), findName)) { return pMaterial; } } } if (bRecursive) { // 子供に一致するものが無いか検索 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { if (Material* pMat = it->FindMaterialByName(findName, bRecursive)) { return pMat; } } } return 0; } void Pane::CalculateMtx(const DrawInfo& drawInfo) { if (! IsVisible() && ! drawInfo.IsInvisiblePaneCalculateMtx()) { return; } if (!this->IsUserGlobalMtx()) { // 行列計算 // m_Mtx = T * Rz * Ry * Rx * S const math::MTX34* pParentMtx = NULL; if (m_pParent) { pParentMtx = &m_pParent->m_GlbMtx; } else { pParentMtx = &drawInfo.GetViewMtx(); } // 行列の計算 if (this->IsUserMtx()) { math::MTX34Mult(&m_GlbMtx, pParentMtx, &m_Mtx); } else { MtxCondition mtxCondition = MTXCONDITION_CLEAN; math::VEC2 scale; { // RVCTコンパイラ対策。 // // 構造体のコピーは整数レジスタで行われるため、 // 読み込んだ値を浮動小数点数演算に利用できない。 // メモリに書き込んだものを再度、浮動小数点レジスタで読み直す必要がある。 // // 明示的に浮動小数点として読み込み、計算結果をストアする。 // register f32 sx = this->GetScale().x; register f32 sy = this->GetScale().y; if (drawInfo.IsLocationAdjust() && this->IsLocationAdjust()) { mtxCondition = MTXCONDITION_CLEAN_LOCATION_ADJUST; sx *= drawInfo.GetLocationAdjustScale().x; sy *= drawInfo.GetLocationAdjustScale().y; } scale.Set(sx, sy); } if (m_Rotate.x != 0 || m_Rotate.y != 0) { // XY回転有り if (this->GetMtxCondition() != mtxCondition) { this->SetMtxCondition(mtxCondition); local::MakeMatrixSRT(m_Mtx, scale, m_Rotate, m_Translate); } math::MTX34Mult(&m_GlbMtx, pParentMtx, &m_Mtx); } else if (m_Rotate.z != 0) { // Z回転有り if (this->GetMtxCondition() != mtxCondition) { this->SetMtxCondition(mtxCondition); local::MakeMatrixSRT(m_Mtx, scale, m_Rotate.z, m_Translate); } math::MTX34Mult(&m_GlbMtx, pParentMtx, &m_Mtx); } else { local::MultMatrixSRTxST(&m_GlbMtx, pParentMtx, &scale, &m_Translate); } } } // アルファの計算 if (drawInfo.IsInfluencedAlpha() && m_pParent) { m_GlbAlpha = u8(m_Alpha * drawInfo.GetGlobalAlpha()); } else { m_GlbAlpha = m_Alpha; } /* PANEFLAG_INFLUENCEDALPHAが立っていて、自分の透明度が255でないなら、 drawInfoに累積透明度(0.f - 1.f)をセットして、子供の計算に影響させる。 */ if (IsInfluencedAlpha() && m_Alpha != ut::Color8::ALPHA_MAX) { const f32 crGlobalAlpha = drawInfo.GetGlobalAlpha(); const bool bCrInfluenced = drawInfo.IsInfluencedAlpha(); DrawInfo& mtDrawInfo = const_cast(drawInfo); const f32 invAlpha = 1.0f / ut::Color8::ALPHA_MAX; mtDrawInfo.SetGlobalAlpha(crGlobalAlpha * m_Alpha * invAlpha); mtDrawInfo.SetInfluencedAlpha(true); // 子供の行列計算 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->CalculateMtx(drawInfo); } // 変更した値を元に戻す mtDrawInfo.SetGlobalAlpha(crGlobalAlpha); mtDrawInfo.SetInfluencedAlpha(bCrInfluenced); } else { // 子供の行列計算 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->CalculateMtx(drawInfo); } } } // 子供の行列計算 void Pane::CalculateMtxChild(const DrawInfo& drawInfo) { for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->CalculateMtx(drawInfo); } } #ifdef NW_LYT_DMPGL_ENABLED void Pane::Draw(const DrawInfo& drawInfo) { if (! IsVisible()) { return; } DrawSelf(drawInfo); // 子供の描画 for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->Draw(drawInfo); } } #endif #ifdef NW_LYT_DMPGL_ENABLED void Pane::DrawSelf(const DrawInfo& drawInfo) { #if defined(NW_RELEASE) NW_UNUSED_VARIABLE(drawInfo) #else // #if ! defined(NW_RELEASE) if (m_pParent && drawInfo.IsDebugDrawMode()) // 枠の描画 { // 行列 LoadMtx(drawInfo); internal::DrawLine(drawInfo, GetVtxPos(), m_Size, ut::Color8::GREEN); drawInfo.GetGraphicsResource()->ResetGlState(); } #endif // #if ! defined(NW_RELEASE) } #endif // NW_LYT_DMPGL_ENABLED void Pane::Animate(u32 option) { AnimateSelf(option); if ( IsVisible() || 0 == (option & ANIMATEOPT_NOANIMATEINVISIBLE) ) { // 子供のアニメーション for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->Animate(option); } } } void Pane::AnimateSelf(u32 option) { for (AnimationList::Iterator it = m_AnimList.GetBeginIter(); it != m_AnimList.GetEndIter(); ++it) { if (it->IsEnable()) { AnimTransform* animTrans = it->GetAnimTransform(); animTrans->Animate(it->GetIndex(), this); } } if ( IsVisible() || 0 == (option & ANIMATEOPT_NOANIMATEINVISIBLE) ) { u32 nbMaterial = GetMaterialNum(); for (u32 idx = 0; idx < nbMaterial; ++idx) { Material* pMaterial = GetMaterial(idx); if (pMaterial) { pMaterial->Animate(); } } } } void Pane::BindAnimation( AnimTransform* pAnimTrans, bool bRecursive, bool bDisable ) { NW_NULL_ASSERT(pAnimTrans); pAnimTrans->Bind(this, bRecursive, bDisable); } void Pane::UnbindAnimation( AnimTransform* pAnimTrans, bool bRecursive ) { UnbindAnimationSelf(pAnimTrans); // 再帰的にたどる if (bRecursive) { for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->UnbindAnimation(pAnimTrans, bRecursive); } } } void Pane::UnbindAllAnimation(bool bRecursive) { UnbindAnimation(0, bRecursive); } void Pane::UnbindAnimationSelf(AnimTransform* pAnimTrans) { u32 nbMaterial = GetMaterialNum(); for (u32 idx = 0; idx < nbMaterial; ++idx) { Material* pMaterial = GetMaterial(idx); if (pMaterial) { pMaterial->UnbindAnimation(pAnimTrans); } } internal::UnbindAnimationLink(&m_AnimList, pAnimTrans); } void Pane::AddAnimationLink(AnimationLink* pAnimationLink) { NW_NULL_ASSERT(pAnimationLink); m_AnimList.PushBack(pAnimationLink); } AnimationLink* Pane::FindAnimationLinkSelf(AnimTransform* pAnimTrans) { return internal::FindAnimationLink(&m_AnimList, pAnimTrans); } AnimationLink* Pane::FindAnimationLinkSelf(const AnimResource& animRes) { return internal::FindAnimationLink(&m_AnimList, animRes); } void Pane::SetAnimationEnable( AnimTransform* pAnimTrans, bool bEnable, bool bRecursive ) { if (AnimationLink* pAnimLink = FindAnimationLinkSelf(pAnimTrans)) { pAnimLink->SetEnable(bEnable); } const u32 materialNum = GetMaterialNum(); for (u32 i = 0; i < materialNum; ++i) { GetMaterial(i)->SetAnimationEnable(pAnimTrans, bEnable); } // 再帰的にたどる if (bRecursive) { for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->SetAnimationEnable(pAnimTrans, bEnable, bRecursive); } } } void Pane::SetAnimationEnable( const AnimResource& animRes, bool bEnable, bool bRecursive ) { if (AnimationLink* pAnimLink = FindAnimationLinkSelf(animRes)) { pAnimLink->SetEnable(bEnable); } const u32 materialNum = GetMaterialNum(); for (u32 i = 0; i < materialNum; ++i) { GetMaterial(i)->SetAnimationEnable(animRes, bEnable); } // 再帰的にたどる if (bRecursive) { for (PaneList::Iterator it = m_ChildList.GetBeginIter(); it != m_ChildList.GetEndIter(); ++it) { it->SetAnimationEnable(animRes, bEnable, bRecursive); } } } #ifdef NW_LYT_DMPGL_ENABLED void Pane::LoadMtx(const DrawInfo& drawInfo) { GraphicsResource& graphicsResource = *drawInfo.GetGraphicsResource(); graphicsResource.SetMtxModelView(this->GetGlobalMtx()); } #endif const math::VEC2 Pane::GetVtxPos() const { VEC2 basePt(0, 0); switch (this->GetBasePositionH()) { case HORIZONTALPOSITION_LEFT: default: basePt.x = 0; break; case HORIZONTALPOSITION_CENTER: basePt.x = - m_Size.width / 2; break; case HORIZONTALPOSITION_RIGHT: basePt.x = - m_Size.width; break; } switch (this->GetBasePositionV()) { case VERTICALPOSITION_TOP: default: basePt.y = 0; break; case VERTICALPOSITION_CENTER: basePt.y = m_Size.height / 2; break; case VERTICALPOSITION_BOTTOM: basePt.y = m_Size.height; break; } return basePt; } Material* Pane::GetMaterial() const { if (GetMaterialNum() > 0) { return GetMaterial(0); } else { return 0; } } u8 Pane::GetMaterialNum() const { return 0; } Material* Pane::GetMaterial(u32 idx) const { NW_UNUSED_VARIABLE(idx); NW_WARNING(idx < GetMaterialNum(), "idx >= GetMaterialNum() : %d >= %d", idx, GetMaterialNum()); return 0; } u16 Pane::GetExtUserDataNum() const { if (! m_pExtUserDataList) { return 0; } return m_pExtUserDataList->num; } const ExtUserData* Pane::GetExtUserDataArray() const { if (! m_pExtUserDataList) { return 0; } return internal::ConvertOffsToPtr(m_pExtUserDataList, sizeof(*m_pExtUserDataList)); } const ExtUserData* Pane::FindExtUserDataByName(const char* name) { const ExtUserData* pExtUserData = GetExtUserDataArray(); if (! pExtUserData) { return 0; } for (int i = 0; i < m_pExtUserDataList->num; ++i, ++pExtUserData) { if (0 == std::strcmp(name, pExtUserData->GetName())) { return pExtUserData; } } return 0; } } // namespace nw::lyt } // namespace nw