/*---------------------------------------------------------------------------* Project: NintendoWare File: lyt_Util.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 #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()); } #ifdef NW_PLATFORM_CTR // 割り算を高速に行うため、NN_GX_MEM_FCRAM が 2のべき乗かチェック。 NW_STATIC_ASSERT((NN_GX_MEM_FCRAM & (NN_GX_MEM_FCRAM - 1)) == 0); // NN_GX_MEM_FCRAMで割り切れるかチェック。 NW_STATIC_ASSERT((NN_GX_MEM_VRAMA & (NN_GX_MEM_FCRAM - 1)) == 0); NW_STATIC_ASSERT((NN_GX_MEM_VRAMB & (NN_GX_MEM_FCRAM - 1)) == 0); static const u32 MEM_AREA_FIELD = 0x03; // MEM_AREA_FIELDに収まるかチェック。 NW_STATIC_ASSERT(NN_GX_MEM_VRAMA / NN_GX_MEM_FCRAM <= MEM_AREA_FIELD); NW_STATIC_ASSERT(NN_GX_MEM_VRAMB / NN_GX_MEM_FCRAM <= MEM_AREA_FIELD); #endif const TextureInfo LoadTexture(const void* pImgRes, u32 size, int texLoadFlag) { const TexResource texResource(const_cast(pImgRes), size); if (!texResource.IsValid()) { 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); TexFormat format = texResource.GetFormat(); const void* pixels = texResource.GetImageAddress(); u32 imageSize = texResource.GetImageSize(); #ifndef NW_TARGET_CTR_GL_FINAL if (texSpec[format].final) { NW_WARNING(false, "unsupported texture format (%d).", format); } #endif u16 width = texResource.GetWidth(); u16 realWidth = texSpec[format].minSize; while (realWidth != 0 && realWidth < width) { realWidth <<= 1; } u16 height = texResource.GetHeight(); u16 realHeight = texSpec[format].minSize; while (realHeight != 0 && realHeight < height) { realHeight <<= 1; } #ifdef NW_PLATFORM_CTR if (texLoadFlag == 0) { switch (texResource.GetImageArea()) { case MEMAREA_FCRAM: texLoadFlag = NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP; break; case MEMAREA_VRAMA: texLoadFlag = NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP; break; case MEMAREA_VRAMB: texLoadFlag = NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP; break; default: NW_FATAL_ERROR("unexpected image area."); return TextureInfo(); } } #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[format].compressed) { glCompressedTexImage2D( GL_TEXTURE_2D | texLoadFlag, 0, // mipmap level texSpec[format].format, realWidth, realHeight, 0, imageSize, pixels); NW_GL_ASSERT(); } else { glTexImage2D( GL_TEXTURE_2D | texLoadFlag, 0, // mipmap level texSpec[format].format, realWidth, realHeight, 0, texSpec[format].format, texSpec[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 const u32 MEM_MASK = 0x00030000; GLenum transtype = texLoadFlag & 0xFFFF0000; switch (transtype) { case NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP: nngxUpdateBuffer(pixels, imageSize); physicalAddress = nngxGetPhysicalAddr((uptr)(pixels)); break; case NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP: case NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP: { GLvoid* (*pGlAllocator)(GLenum, GLenum, GLuint, GLsizei) = NULL; nngxGetAllocator(&pGlAllocator, NULL); if (pGlAllocator == NULL) { NW_FATAL_ERROR("can not get DMPGL allocator."); return TextureInfo(); } GLuint area = transtype & MEM_MASK; void* address = pGlAllocator( area, NN_GX_MEM_TEXTURE, texName, imageSize); if (address != NULL) { nngxAddVramDmaCommand(pixels, address, imageSize); physicalAddress = nngxGetPhysicalAddr((uptr)(address)); // VRAMエリアを廃棄するときのために仮想アドレスと // エリア情報を保持しておきます。 // TextureInfo を大きくしたくないので texName で代用します。 // テクスチャは 128バイトアライメントなので下位7ビットは // 空いているはず。 NW_ASSERT(((u32)(address) & MEM_AREA_FIELD) == 0); texName = u32(address) | u32(area / NN_GX_MEM_FCRAM); } } break; default: NW_FATAL_ERROR("unexpected texture transfer type."); } #endif #ifdef NW_LYT_DMPGL_ENABLED } #endif return TextureInfo( texName, physicalAddress, TexSize(width, height), TexSize(realWidth, realHeight), format); } void DeleteTexture(const TextureInfo& texInfo) { #ifdef NW_LYT_DMPGL_ENABLED if (Layout::GetLayoutDrawEnable()) { GLuint texName = texInfo.GetTextureObject(); if (texName != texInfo.INVALID) { glDeleteTextures(1, &texName); } } else #endif { #ifdef NW_PLATFORM_CTR u32 texName = texInfo.GetTextureObject(); if (texName != texInfo.INVALID) { // VRAM に配置された場合。 // 仮想アドレスとメモリ配置情報が texName に格納されています。 GLvoid (*pGlDeallocator)(GLenum, GLenum, GLuint, GLvoid*) = NULL; nngxGetAllocator(NULL, &pGlDeallocator); if (pGlDeallocator == NULL) { NW_FATAL_ERROR("can not get DMPGL deallocator."); } void* address = (void*)(texName & ~MEM_AREA_FIELD); GLuint area = (texName & MEM_AREA_FIELD) * NN_GX_MEM_FCRAM; NW_ASSERT(area == NN_GX_MEM_VRAMA || area == NN_GX_MEM_VRAMB); pGlDeallocator( area, NN_GX_MEM_TEXTURE, TextureInfo::INVALID /* texName */, address); } #endif } } 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