/*---------------------------------------------------------------------------* Project: NintendoWare File: lyt_Util.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 #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) namespace nw { namespace lyt { namespace { struct TexSpec { int lytFormat; GLenum format; GLenum type; int minSize; bool compressed; bool final; }; bool Contains( const nw::ut::Rect& rect, const nw::math::VEC2& point ) { return rect.left <= point.x && point.x <= rect.right && rect.bottom <= point.y && point.y <= rect.top; } } // namespace nw::lyt::{no-name} void BindAnimation( Group* pGroup, AnimTransform* pAnimTrans, bool bRecursive, bool bDisable ) { PaneLinkList& paneList = pGroup->GetPaneList(); for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it) { it->target->BindAnimation(pAnimTrans, bRecursive, bDisable); } } void UnbindAnimation( Group* pGroup, AnimTransform* pAnimTrans, bool bRecursive ) { PaneLinkList& paneList = pGroup->GetPaneList(); for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it) { it->target->UnbindAnimation(pAnimTrans, bRecursive); } } void SetAnimationEnable( Group* pGroup, AnimTransform* pAnimTrans, bool bEnable, bool bRecursive ) { PaneLinkList& paneList = pGroup->GetPaneList(); for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it) { it->target->SetAnimationEnable(pAnimTrans, bEnable, bRecursive); } } bool IsContain( Pane* pPane, const math::VEC2& pos ) { math::MTX34 invGlbMtx; math::MTX34Inverse(&invGlbMtx, &pPane->GetGlobalMtx()); // ペインのグローバル行列の逆行列を求める math::VEC3 pos3(pos.x, pos.y, 0.f); math::VEC3 lclPos; math::VEC3Transform(&lclPos, &invGlbMtx, &pos3); return Contains(pPane->GetPaneRect(), math::VEC2(lclPos.x, lclPos.y)); } Pane* FindHitPane( Pane* pPane, const math::VEC2& pos ) { // 非表示のペインはヒットチェックの対象としない。 if (! pPane->IsVisible()) { return 0; } // 子供のヒットチェック for (PaneList::ReverseIterator it = pPane->GetChildList().GetBeginReverseIter(); it != pPane->GetChildList().GetEndReverseIter(); ++it) { if (Pane *const ret = FindHitPane(&(*it), pos)) { return ret; } } // Bounding ペインか if (nw::lyt::Bounding *const pBounding = nw::ut::DynamicCast(pPane)) { if (IsContain(pBounding, pos)) { return pBounding; // 含まれている。 } } return 0; } Pane* FindHitPane( Layout* pLayout, const math::VEC2& pos ) { return FindHitPane(pLayout->GetRootPane(), pos); } /* 次のペインを返す。 */ Pane* GetNextPane(Pane* pPane) { if (! pPane->GetChildList().IsEmpty()) // 子供がいれば、最初の子供を返す。 { PaneList::Iterator paneIt = pPane->GetChildList().GetBeginIter(); return &(*paneIt); } // 弟を探す。 // 弟が無ければ、親の弟へとたどる。 while (true) { if (pPane->GetParent() == 0) // 親が NULL の場合はルートペイン { return 0; } PaneList::Iterator nextIt = PaneList::GetIteratorFromPointer(pPane->m_Link.GetNext()); PaneList::Iterator endIt = pPane->GetParent()->GetChildList().GetEndIter(); if (nextIt != endIt) { break; } pPane = pPane->GetParent(); } return PaneList::GetPointerFromNode(pPane->m_Link.GetNext()); } const TextureInfo LoadTexture(const void* pImgRes, u32 size, int texLoadFlag) { const int FILEHEADER_ALIGNMENT = 4; NW_NULL_ASSERT(pImgRes); NW_ASSERT((u32)(pImgRes) % 128 == 0); // アライメントのためテクスチャイメージはリソースファイルの先頭に配置。 const void* pixels = pImgRes; // ファイルの末尾 4 バイトがイメージサイズ。 const res::ImageSize* pImageSize = internal::ConvertOffsToPtr(pImgRes, size - sizeof(u32)); u32 imageSize = pImageSize->imageSize; NW_ASSERT(imageSize < size); const ut::BinaryFileHeader* pFileHead = internal::ConvertOffsToPtr( pImgRes, ut::RoundUp(imageSize, FILEHEADER_ALIGNMENT)); if (!ut::IsValidBinaryFile(pFileHead, res::FILESIGNATURE_CLIM, res::BinaryFileFormatVersion)) { NW_WARNING(false, "not valid layout image file."); return TextureInfo(); } const res::Image* pImage = 0; const ut::BinaryBlockHeader* pBlockHead = NULL; for (int i = 0; i < pFileHead->dataBlocks; ++i) { pBlockHead = ut::GetNextBinaryBlockHeader(pFileHead, pBlockHead); NW_NULL_ASSERT(pBlockHead); ut::SigWord kind = pBlockHead->kind; switch (kind) { case res::DATABLOCKKIND_IMAGE: pImage = reinterpret_cast(pBlockHead); break; } } if (pImage == NULL) { NW_WARNING(false, "file does not contain texture image."); return TextureInfo(); } #ifndef NW_TARGET_CTR_GL_FINAL # undef GL_UNSIGNED_BYTE_4_4_DMP # define GL_UNSIGNED_BYTE_4_4_DMP GL_UNSIGNED_BYTE # undef GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP # define GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP GL_ETC1_RGB8_NATIVE_DMP # undef GL_UNSIGNED_4BITS_DMP # define GL_UNSIGNED_4BITS_DMP GL_UNSIGNED_BYTE #endif static const TexSpec texSpec[] = { { TEXFORMAT_L8, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_A8, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_LA4, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE_4_4_DMP, 8, false, true }, { TEXFORMAT_LA8, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_HILO8, GL_HILO8_DMP_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_RGB565, GL_RGB_NATIVE_DMP, GL_UNSIGNED_SHORT_5_6_5, 8, false, false }, { TEXFORMAT_RGB8, GL_RGB_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_RGB5A1, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_5_5_5_1, 8, false, false }, { TEXFORMAT_RGBA4, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_4_4_4_4, 8, false, false }, { TEXFORMAT_RGBA8, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false }, { TEXFORMAT_ETC1, GL_ETC1_RGB8_NATIVE_DMP, 0 /* N/A */, 16, true, false }, { TEXFORMAT_ETC1A4, GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP, 0 /* N/A */, 8, true, true }, { TEXFORMAT_L4, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true }, { TEXFORMAT_A4, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true }, }; NW_COMPILER_ASSERT(ARRAY_LENGTH(texSpec) == TEXFORMAT_MAX); #ifndef NW_TARGET_CTR_GL_FINAL if (texSpec[pImage->format].final) { NW_WARNING(false, "unsupported texture format (%d).", pImage->format); } #endif u16 width = pImage->width; u16 realWidth = texSpec[pImage->format].minSize; while (realWidth != 0 && realWidth < width) { realWidth <<= 1; } u16 height = pImage->height; u16 realHeight = texSpec[pImage->format].minSize; while (realHeight != 0 && realHeight < height) { realHeight <<= 1; } #ifdef NW_PLATFORM_CTR if (texLoadFlag == 0) { texLoadFlag = NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP; } #endif GLuint texName = TextureInfo::INVALID; uptr physicalAddress = 0; #ifdef NW_LYT_DMPGL_ENABLED if (Layout::GetLayoutDrawEnable()) { // テクスチャ名を取得。 glGenTextures(1, &texName); // テクスチャオブジェクトを生成。 glBindTexture(GL_TEXTURE_2D, texName); NW_GL_ASSERT(); if (texSpec[pImage->format].compressed) { glCompressedTexImage2D( GL_TEXTURE_2D | texLoadFlag, 0, // mipmap level texSpec[pImage->format].format, realWidth, realHeight, 0, imageSize, pixels); NW_GL_ASSERT(); } else { glTexImage2D( GL_TEXTURE_2D | texLoadFlag, 0, // mipmap level texSpec[pImage->format].format, realWidth, realHeight, 0, texSpec[pImage->format].format, texSpec[pImage->format].type, pixels); NW_GL_ASSERT(); } // 固定設定 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, -1000); #ifdef NW_PLATFORM_CTR { GLint dataAddr = 0; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_DATA_ADDR_DMP, &dataAddr); physicalAddress = nngxGetPhysicalAddr((uptr)(dataAddr)); } #endif } else { #endif // NW_LYT_DMPGL_ENABLED #ifdef NW_PLATFORM_CTR NW_ASSERT((texLoadFlag & ~(GL_COPY_FCRAM_DMP | GL_NO_COPY_FCRAM_DMP)) == NN_GX_MEM_FCRAM); nngxUpdateBuffer(pixels, imageSize); physicalAddress = nngxGetPhysicalAddr((uptr)(pixels)); #endif #ifdef NW_LYT_DMPGL_ENABLED } #endif return TextureInfo( texName, physicalAddress, TexSize(width, height), TexSize(realWidth, realHeight), TexFormat(pImage->format)); } void CalcTextureMtx(math::MTX23* pTexMtx, const TexSRT& texSRT, const TexMap& texMap) { NW_NULL_ASSERT(pTexMtx); math::MTX23& texMtx = *pTexMtx; math::VEC2 center(0.5f, 0.5f); f32 sinR, cosR; math::SinCosDeg(&sinR, &cosR, texSRT.rotate); f32 a0, a1; a0 = cosR * texSRT.scale.x; a1 = #ifdef ORDER_TSR texSRT.scale.x * (-sinR); #else // TRS -sinR * texSRT.scale.y; #endif texMtx.m[0][0] = a0; texMtx.m[0][1] = a1; texMtx.m[0][2] = texSRT.translate.x + center.x + a0 * (-center.x) + a1 * (-center.y); a0 = #ifdef ORDER_TSR texSRT.scale.y * sinR; #else // TRS sinR * texSRT.scale.x; #endif a1 = cosR * texSRT.scale.y; texMtx.m[1][0] = a0; texMtx.m[1][1] = a1; texMtx.m[1][2] = texSRT.translate.y + center.y + a0 * (-center.x) + a1 * (-center.y); f32 su = static_cast(texMap.GetWidth()) / texMap.GetRealWidth(); f32 sv = static_cast(texMap.GetHeight()) / texMap.GetRealHeight(); // math::MTX23 m( // su, 0, 0, // 0, -sv, 1); // math::MTX23Mult(&texMtx, &m, &texMtx); texMtx.f._00 *= su; texMtx.f._01 *= su; texMtx.f._02 *= su; sv = -sv; texMtx.f._10 *= sv; texMtx.f._11 *= sv; texMtx.f._12 = texMtx.f._12 * sv + 1.0f; } } // namespace nw::lyt } // namespace nw