1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_Util.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 25594 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/lyt/lyt_Util.h>
19 #include <nw/lyt/lyt_Bounding.h>
20 #include <nw/lyt/lyt_Layout.h>
21 #include <nw/lyt/lyt_Group.h>
22 #include <nw/lyt/lyt_Animation.h>
23 
24 #define ARRAY_LENGTH(a)   (sizeof(a) / sizeof((a)[0]))
25 
26 namespace nw
27 {
28 namespace lyt
29 {
30 namespace
31 {
32 
33 struct TexSpec
34 {
35     int lytFormat;
36     GLenum format;
37     GLenum type;
38     int minSize;
39     bool compressed;
40     bool final;
41 };
42 
43 bool
Contains(const nw::ut::Rect & rect,const nw::math::VEC2 & point)44 Contains(
45     const nw::ut::Rect&   rect,
46     const nw::math::VEC2& point
47 )
48 {
49     return rect.left <= point.x && point.x <= rect.right && rect.bottom <= point.y && point.y <= rect.top;
50 }
51 
52 } // namespace nw::lyt::{no-name}
53 
54 void
BindAnimation(Group * pGroup,AnimTransform * pAnimTrans,bool bRecursive,bool bDisable)55 BindAnimation(
56     Group*          pGroup,
57     AnimTransform*  pAnimTrans,
58     bool            bRecursive,
59     bool            bDisable
60 )
61 {
62     PaneLinkList& paneList = pGroup->GetPaneList();
63     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
64     {
65         it->target->BindAnimation(pAnimTrans, bRecursive, bDisable);
66     }
67 }
68 
69 void
UnbindAnimation(Group * pGroup,AnimTransform * pAnimTrans,bool bRecursive)70 UnbindAnimation(
71     Group*          pGroup,
72     AnimTransform*  pAnimTrans,
73     bool            bRecursive
74 )
75 {
76     PaneLinkList& paneList = pGroup->GetPaneList();
77     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
78     {
79         it->target->UnbindAnimation(pAnimTrans, bRecursive);
80     }
81 }
82 
83 void
SetAnimationEnable(Group * pGroup,AnimTransform * pAnimTrans,bool bEnable,bool bRecursive)84 SetAnimationEnable(
85     Group*          pGroup,
86     AnimTransform*  pAnimTrans,
87     bool            bEnable,
88     bool            bRecursive
89 )
90 {
91     PaneLinkList& paneList = pGroup->GetPaneList();
92     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
93     {
94         it->target->SetAnimationEnable(pAnimTrans, bEnable, bRecursive);
95     }
96 }
97 
98 bool
IsContain(Pane * pPane,const math::VEC2 & pos)99 IsContain(
100     Pane*               pPane,
101     const math::VEC2&   pos
102 )
103 {
104     math::MTX34 invGlbMtx;
105     math::MTX34Inverse(&invGlbMtx, &pPane->GetGlobalMtx());       // ペインのグローバル行列の逆行列を求める
106 
107     math::VEC3 pos3(pos.x, pos.y, 0.f);
108     math::VEC3 lclPos;
109     math::VEC3Transform(&lclPos, &invGlbMtx, &pos3);
110 
111     return Contains(pPane->GetPaneRect(), math::VEC2(lclPos.x, lclPos.y));
112 }
113 
114 Pane*
FindHitPane(Pane * pPane,const math::VEC2 & pos)115 FindHitPane(
116     Pane*               pPane,
117     const math::VEC2&   pos
118 )
119 {
120     // 非表示のペインはヒットチェックの対象としない。
121     if (! pPane->IsVisible())
122     {
123         return 0;
124     }
125 
126     // 子供のヒットチェック
127     for (PaneList::ReverseIterator it = pPane->GetChildList().GetBeginReverseIter(); it != pPane->GetChildList().GetEndReverseIter(); ++it)
128     {
129         if (Pane *const ret = FindHitPane(&(*it), pos))
130         {
131             return ret;
132         }
133     }
134 
135     // Bounding ペインか
136     if (nw::lyt::Bounding *const pBounding = nw::ut::DynamicCast<nw::lyt::Bounding*>(pPane))
137     {
138         if (IsContain(pBounding, pos))
139         {
140             return pBounding;  // 含まれている。
141         }
142     }
143 
144     return 0;
145 }
146 
147 Pane*
FindHitPane(Layout * pLayout,const math::VEC2 & pos)148 FindHitPane(
149     Layout*             pLayout,
150     const math::VEC2&   pos
151 )
152 {
153     return FindHitPane(pLayout->GetRootPane(), pos);
154 }
155 
156 /*
157     次のペインを返す。
158 */
159 Pane*
GetNextPane(Pane * pPane)160 GetNextPane(Pane* pPane)
161 {
162     if (! pPane->GetChildList().IsEmpty())  // 子供がいれば、最初の子供を返す。
163     {
164         PaneList::Iterator paneIt = pPane->GetChildList().GetBeginIter();
165         return &(*paneIt);
166     }
167 
168     // 弟を探す。
169     // 弟が無ければ、親の弟へとたどる。
170     while (true)
171     {
172         if (pPane->GetParent() == 0)    // 親が NULL の場合はルートペイン
173         {
174             return 0;
175         }
176 
177         PaneList::Iterator nextIt = PaneList::GetIteratorFromPointer(pPane->m_Link.GetNext());
178         PaneList::Iterator endIt = pPane->GetParent()->GetChildList().GetEndIter();
179         if (nextIt != endIt)
180         {
181             break;
182         }
183 
184         pPane = pPane->GetParent();
185     }
186 
187     return PaneList::GetPointerFromNode(pPane->m_Link.GetNext());
188 }
189 
190 const TextureInfo
LoadTexture(const void * pImgRes,u32 size,int texLoadFlag)191 LoadTexture(const void* pImgRes, u32 size, int texLoadFlag)
192 {
193     const int FILEHEADER_ALIGNMENT = 4;
194 
195     NW_NULL_ASSERT(pImgRes);
196     NW_ASSERT((u32)(pImgRes) % 128 == 0);
197 
198     // アライメントのためテクスチャイメージはリソースファイルの先頭に配置。
199     const void* pixels = pImgRes;
200 
201     // ファイルの末尾 4 バイトがイメージサイズ。
202     const res::ImageSize* pImageSize
203         = internal::ConvertOffsToPtr<res::ImageSize>(pImgRes, size - sizeof(u32));
204     u32 imageSize = pImageSize->imageSize;
205     NW_ASSERT(imageSize < size);
206 
207     const ut::BinaryFileHeader* pFileHead
208         = internal::ConvertOffsToPtr<ut::BinaryFileHeader>(
209             pImgRes,
210             ut::RoundUp(imageSize, FILEHEADER_ALIGNMENT));
211 
212     if (!ut::IsValidBinaryFile(pFileHead, res::FILESIGNATURE_CLIM, res::BinaryFileFormatVersion))
213     {
214         NW_WARNING(false, "not valid layout image file.");
215         return TextureInfo();
216     }
217 
218     const res::Image* pImage = 0;
219 
220     const ut::BinaryBlockHeader* pBlockHead = NULL;
221     for (int i = 0; i < pFileHead->dataBlocks; ++i)
222     {
223         pBlockHead = ut::GetNextBinaryBlockHeader(pFileHead, pBlockHead);
224         NW_NULL_ASSERT(pBlockHead);
225 
226         ut::SigWord kind = pBlockHead->kind;
227         switch (kind)
228         {
229         case res::DATABLOCKKIND_IMAGE:
230             pImage = reinterpret_cast<const res::Image *>(pBlockHead);
231             break;
232         }
233     }
234 
235     if (pImage == NULL)
236     {
237         NW_WARNING(false, "file does not contain texture image.");
238         return TextureInfo();
239     }
240 
241 #ifndef NW_TARGET_CTR_GL_FINAL
242 #  undef GL_UNSIGNED_BYTE_4_4_DMP
243 #  define GL_UNSIGNED_BYTE_4_4_DMP GL_UNSIGNED_BYTE
244 #  undef GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP
245 #  define GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP GL_ETC1_RGB8_NATIVE_DMP
246 #  undef GL_UNSIGNED_4BITS_DMP
247 #  define GL_UNSIGNED_4BITS_DMP GL_UNSIGNED_BYTE
248 #endif
249 
250     static const TexSpec texSpec[] =
251     {
252         { TEXFORMAT_L8, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
253         { TEXFORMAT_A8, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
254         { TEXFORMAT_LA4, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE_4_4_DMP, 8, false, true },
255         { TEXFORMAT_LA8, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
256         { TEXFORMAT_HILO8, GL_HILO8_DMP_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
257         { TEXFORMAT_RGB565, GL_RGB_NATIVE_DMP, GL_UNSIGNED_SHORT_5_6_5, 8, false, false },
258         { TEXFORMAT_RGB8, GL_RGB_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
259         { TEXFORMAT_RGB5A1, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_5_5_5_1, 8, false, false },
260         { TEXFORMAT_RGBA4, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_4_4_4_4, 8, false, false },
261         { TEXFORMAT_RGBA8, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
262         { TEXFORMAT_ETC1, GL_ETC1_RGB8_NATIVE_DMP, 0 /* N/A */, 16, true, false },
263         { TEXFORMAT_ETC1A4, GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP, 0 /* N/A */, 8, true, true },
264         { TEXFORMAT_L4, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true },
265         { TEXFORMAT_A4, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true },
266     };
267     NW_COMPILER_ASSERT(ARRAY_LENGTH(texSpec) == TEXFORMAT_MAX);
268 
269 #ifndef NW_TARGET_CTR_GL_FINAL
270     if (texSpec[pImage->format].final)
271     {
272         NW_WARNING(false, "unsupported texture format (%d).", pImage->format);
273     }
274 #endif
275 
276     u16 width = pImage->width;
277     u16 realWidth = texSpec[pImage->format].minSize;
278     while (realWidth != 0 && realWidth < width)
279     {
280         realWidth <<= 1;
281     }
282 
283     u16 height = pImage->height;
284     u16 realHeight = texSpec[pImage->format].minSize;
285     while (realHeight != 0 && realHeight < height)
286     {
287         realHeight <<= 1;
288     }
289 
290 #ifdef NW_PLATFORM_CTR
291     if (texLoadFlag == 0)
292     {
293         texLoadFlag = NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
294     }
295 #endif
296 
297     GLuint texName = TextureInfo::INVALID;
298     uptr physicalAddress = 0;
299 
300 #ifdef NW_LYT_DMPGL_ENABLED
301     if (Layout::GetLayoutDrawEnable())
302     {
303         // テクスチャ名を取得。
304         glGenTextures(1, &texName);
305         // テクスチャオブジェクトを生成。
306         glBindTexture(GL_TEXTURE_2D, texName);
307         NW_GL_ASSERT();
308 
309         if (texSpec[pImage->format].compressed)
310         {
311             glCompressedTexImage2D(
312                 GL_TEXTURE_2D | texLoadFlag,
313                 0, // mipmap level
314                 texSpec[pImage->format].format,
315                 realWidth,
316                 realHeight,
317                 0,
318                 imageSize,
319                 pixels);
320                 NW_GL_ASSERT();
321         }
322         else
323         {
324             glTexImage2D(
325                 GL_TEXTURE_2D | texLoadFlag,
326                 0, // mipmap level
327                 texSpec[pImage->format].format,
328                 realWidth,
329                 realHeight,
330                 0,
331                 texSpec[pImage->format].format,
332                 texSpec[pImage->format].type,
333                 pixels);
334                 NW_GL_ASSERT();
335         }
336 
337         // 固定設定
338         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f);
339         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, -1000);
340 
341 #ifdef NW_PLATFORM_CTR
342         {
343             GLint dataAddr = 0;
344             glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_DATA_ADDR_DMP, &dataAddr);
345             physicalAddress = nngxGetPhysicalAddr((uptr)(dataAddr));
346         }
347 #endif
348     }
349     else
350     {
351 #endif // NW_LYT_DMPGL_ENABLED
352 
353 #ifdef NW_PLATFORM_CTR
354         NW_ASSERT((texLoadFlag & ~(GL_COPY_FCRAM_DMP | GL_NO_COPY_FCRAM_DMP)) == NN_GX_MEM_FCRAM);
355 
356         nngxUpdateBuffer(pixels, imageSize);
357         physicalAddress = nngxGetPhysicalAddr((uptr)(pixels));
358 #endif
359 
360 #ifdef NW_LYT_DMPGL_ENABLED
361     }
362 #endif
363 
364     return TextureInfo(
365         texName,
366         physicalAddress,
367         TexSize(width, height),
368         TexSize(realWidth, realHeight),
369         TexFormat(pImage->format));
370 }
371 
372 void
CalcTextureMtx(math::MTX23 * pTexMtx,const TexSRT & texSRT,const TexMap & texMap)373 CalcTextureMtx(math::MTX23* pTexMtx, const TexSRT& texSRT, const TexMap& texMap)
374 {
375     NW_NULL_ASSERT(pTexMtx);
376 
377     math::MTX23& texMtx = *pTexMtx;
378 
379     math::VEC2 center(0.5f, 0.5f);
380 
381     f32 sinR, cosR;
382     math::SinCosDeg(&sinR, &cosR, texSRT.rotate);
383 
384     f32 a0, a1;
385 
386     a0 = cosR * texSRT.scale.x;
387     a1 =
388 #ifdef ORDER_TSR
389          texSRT.scale.x * (-sinR);
390 #else   // TRS
391          -sinR * texSRT.scale.y;
392 #endif
393 
394     texMtx.m[0][0] = a0;
395     texMtx.m[0][1] = a1;
396     texMtx.m[0][2] = texSRT.translate.x + center.x + a0 * (-center.x) + a1 * (-center.y);
397 
398     a0 =
399 #ifdef ORDER_TSR
400          texSRT.scale.y * sinR;
401 #else   // TRS
402          sinR * texSRT.scale.x;
403 #endif
404     a1 = cosR * texSRT.scale.y;
405     texMtx.m[1][0] = a0;
406     texMtx.m[1][1] = a1;
407     texMtx.m[1][2] = texSRT.translate.y + center.y + a0 * (-center.x) + a1 * (-center.y);
408 
409     f32 su = static_cast<f32>(texMap.GetWidth()) / texMap.GetRealWidth();
410     f32 sv = static_cast<f32>(texMap.GetHeight()) / texMap.GetRealHeight();
411 
412     // math::MTX23 m(
413     //     su,   0,  0,
414     //      0, -sv,  1);
415     // math::MTX23Mult(&texMtx, &m, &texMtx);
416     texMtx.f._00 *= su;
417     texMtx.f._01 *= su;
418     texMtx.f._02 *= su;
419     sv = -sv;
420     texMtx.f._10 *= sv;
421     texMtx.f._11 *= sv;
422     texMtx.f._12 = texMtx.f._12 * sv + 1.0f;
423 }
424 
425 } // namespace nw::lyt
426 } // namespace nw
427