1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_Util.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/lyt/lyt_Util.h>
21 #include <nw/lyt/lyt_Bounding.h>
22 #include <nw/lyt/lyt_Layout.h>
23 #include <nw/lyt/lyt_Group.h>
24 #include <nw/lyt/lyt_Animation.h>
25 #include <nw/lyt/lyt_TexResource.h>
26 
27 #define ARRAY_LENGTH(a)   (sizeof(a) / sizeof((a)[0]))
28 
29 namespace nw
30 {
31 namespace lyt
32 {
33 namespace
34 {
35 
36 struct TexSpec
37 {
38     int lytFormat;
39     GLenum format;
40     GLenum type;
41     int minSize;
42     bool compressed;
43     bool final;
44 };
45 
46 bool
Contains(const nw::ut::Rect & rect,const nw::math::VEC2 & point)47 Contains(
48     const nw::ut::Rect&   rect,
49     const nw::math::VEC2& point
50 )
51 {
52     return rect.left <= point.x && point.x <= rect.right && rect.bottom <= point.y && point.y <= rect.top;
53 }
54 
55 } // namespace nw::lyt::{no-name}
56 
57 void
BindAnimation(Group * pGroup,AnimTransform * pAnimTrans,bool bRecursive,bool bDisable)58 BindAnimation(
59     Group*          pGroup,
60     AnimTransform*  pAnimTrans,
61     bool            bRecursive,
62     bool            bDisable
63 )
64 {
65     PaneLinkList& paneList = pGroup->GetPaneList();
66     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
67     {
68         it->target->BindAnimation(pAnimTrans, bRecursive, bDisable);
69     }
70 }
71 
72 void
UnbindAnimation(Group * pGroup,AnimTransform * pAnimTrans,bool bRecursive)73 UnbindAnimation(
74     Group*          pGroup,
75     AnimTransform*  pAnimTrans,
76     bool            bRecursive
77 )
78 {
79     PaneLinkList& paneList = pGroup->GetPaneList();
80     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
81     {
82         it->target->UnbindAnimation(pAnimTrans, bRecursive);
83     }
84 }
85 
86 void
SetAnimationEnable(Group * pGroup,AnimTransform * pAnimTrans,bool bEnable,bool bRecursive)87 SetAnimationEnable(
88     Group*          pGroup,
89     AnimTransform*  pAnimTrans,
90     bool            bEnable,
91     bool            bRecursive
92 )
93 {
94     PaneLinkList& paneList = pGroup->GetPaneList();
95     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
96     {
97         it->target->SetAnimationEnable(pAnimTrans, bEnable, bRecursive);
98     }
99 }
100 
101 bool
IsContain(Pane * pPane,const math::VEC2 & pos)102 IsContain(
103     Pane*               pPane,
104     const math::VEC2&   pos
105 )
106 {
107     math::MTX34 invGlbMtx;
108     math::MTX34Inverse(&invGlbMtx, &pPane->GetGlobalMtx());       // ペインのグローバル行列の逆行列を求める
109 
110     math::VEC3 pos3(pos.x, pos.y, 0.f);
111     math::VEC3 lclPos;
112     math::VEC3Transform(&lclPos, &invGlbMtx, &pos3);
113 
114     return Contains(pPane->GetPaneRect(), math::VEC2(lclPos.x, lclPos.y));
115 }
116 
117 Pane*
FindHitPane(Pane * pPane,const math::VEC2 & pos)118 FindHitPane(
119     Pane*               pPane,
120     const math::VEC2&   pos
121 )
122 {
123     // 非表示のペインはヒットチェックの対象としない。
124     if (! pPane->IsVisible())
125     {
126         return 0;
127     }
128 
129     // 子供のヒットチェック
130     for (PaneList::ReverseIterator it = pPane->GetChildList().GetBeginReverseIter(); it != pPane->GetChildList().GetEndReverseIter(); ++it)
131     {
132         if (Pane *const ret = FindHitPane(&(*it), pos))
133         {
134             return ret;
135         }
136     }
137 
138     // Bounding ペインか
139     if (nw::lyt::Bounding *const pBounding = nw::ut::DynamicCast<nw::lyt::Bounding*>(pPane))
140     {
141         if (IsContain(pBounding, pos))
142         {
143             return pBounding;  // 含まれている。
144         }
145     }
146 
147     return 0;
148 }
149 
150 Pane*
FindHitPane(Layout * pLayout,const math::VEC2 & pos)151 FindHitPane(
152     Layout*             pLayout,
153     const math::VEC2&   pos
154 )
155 {
156     return FindHitPane(pLayout->GetRootPane(), pos);
157 }
158 
159 /*
160     次のペインを返す。
161 */
162 Pane*
GetNextPane(Pane * pPane)163 GetNextPane(Pane* pPane)
164 {
165     if (! pPane->GetChildList().IsEmpty())  // 子供がいれば、最初の子供を返す。
166     {
167         PaneList::Iterator paneIt = pPane->GetChildList().GetBeginIter();
168         return &(*paneIt);
169     }
170 
171     // 弟を探す。
172     // 弟が無ければ、親の弟へとたどる。
173     while (true)
174     {
175         if (pPane->GetParent() == 0)    // 親が NULL の場合はルートペイン
176         {
177             return 0;
178         }
179 
180         PaneList::Iterator nextIt = PaneList::GetIteratorFromPointer(pPane->m_Link.GetNext());
181         PaneList::Iterator endIt = pPane->GetParent()->GetChildList().GetEndIter();
182         if (nextIt != endIt)
183         {
184             break;
185         }
186 
187         pPane = pPane->GetParent();
188     }
189 
190     return PaneList::GetPointerFromNode(pPane->m_Link.GetNext());
191 }
192 
193 #ifdef NW_PLATFORM_CTR
194 // 割り算を高速に行うため、NN_GX_MEM_FCRAM が 2のべき乗かチェック。
195 NW_STATIC_ASSERT((NN_GX_MEM_FCRAM & (NN_GX_MEM_FCRAM - 1)) == 0);
196 
197 // NN_GX_MEM_FCRAMで割り切れるかチェック。
198 NW_STATIC_ASSERT((NN_GX_MEM_VRAMA & (NN_GX_MEM_FCRAM - 1)) == 0);
199 NW_STATIC_ASSERT((NN_GX_MEM_VRAMB & (NN_GX_MEM_FCRAM - 1)) == 0);
200 
201 static const u32 MEM_AREA_FIELD = 0x03;
202 // MEM_AREA_FIELDに収まるかチェック。
203 NW_STATIC_ASSERT(NN_GX_MEM_VRAMA / NN_GX_MEM_FCRAM <= MEM_AREA_FIELD);
204 NW_STATIC_ASSERT(NN_GX_MEM_VRAMB / NN_GX_MEM_FCRAM <= MEM_AREA_FIELD);
205 #endif
206 
207 const TextureInfo
LoadTexture(const void * pImgRes,u32 size,int texLoadFlag)208 LoadTexture(const void* pImgRes, u32 size, int texLoadFlag)
209 {
210     const TexResource texResource(const_cast<void*>(pImgRes), size);
211     if (!texResource.IsValid())
212     {
213         return TextureInfo();
214     }
215 
216 #ifndef NW_TARGET_CTR_GL_FINAL
217 #  undef GL_UNSIGNED_BYTE_4_4_DMP
218 #  define GL_UNSIGNED_BYTE_4_4_DMP GL_UNSIGNED_BYTE
219 #  undef GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP
220 #  define GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP GL_ETC1_RGB8_NATIVE_DMP
221 #  undef GL_UNSIGNED_4BITS_DMP
222 #  define GL_UNSIGNED_4BITS_DMP GL_UNSIGNED_BYTE
223 #endif
224 
225     static const TexSpec texSpec[] =
226     {
227         { TEXFORMAT_L8, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
228         { TEXFORMAT_A8, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
229         { TEXFORMAT_LA4, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE_4_4_DMP, 8, false, true },
230         { TEXFORMAT_LA8, GL_LUMINANCE_ALPHA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
231         { TEXFORMAT_HILO8, GL_HILO8_DMP_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
232         { TEXFORMAT_RGB565, GL_RGB_NATIVE_DMP, GL_UNSIGNED_SHORT_5_6_5, 8, false, false },
233         { TEXFORMAT_RGB8, GL_RGB_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
234         { TEXFORMAT_RGB5A1, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_5_5_5_1, 8, false, false },
235         { TEXFORMAT_RGBA4, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_SHORT_4_4_4_4, 8, false, false },
236         { TEXFORMAT_RGBA8, GL_RGBA_NATIVE_DMP, GL_UNSIGNED_BYTE, 8, false, false },
237         { TEXFORMAT_ETC1, GL_ETC1_RGB8_NATIVE_DMP, 0 /* N/A */, 16, true, false },
238         { TEXFORMAT_ETC1A4, GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP, 0 /* N/A */, 8, true, true },
239         { TEXFORMAT_L4, GL_LUMINANCE_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true },
240         { TEXFORMAT_A4, GL_ALPHA_NATIVE_DMP, GL_UNSIGNED_4BITS_DMP, 8, false, true },
241     };
242     NW_COMPILER_ASSERT(ARRAY_LENGTH(texSpec) == TEXFORMAT_MAX);
243 
244     TexFormat format = texResource.GetFormat();
245     const void* pixels = texResource.GetImageAddress();
246     u32 imageSize = texResource.GetImageSize();
247 
248 #ifndef NW_TARGET_CTR_GL_FINAL
249     if (texSpec[format].final)
250     {
251         NW_WARNING(false, "unsupported texture format (%d).", format);
252     }
253 #endif
254 
255     u16 width = texResource.GetWidth();
256     u16 realWidth = texSpec[format].minSize;
257     while (realWidth != 0 && realWidth < width)
258     {
259         realWidth <<= 1;
260     }
261 
262     u16 height = texResource.GetHeight();
263     u16 realHeight = texSpec[format].minSize;
264     while (realHeight != 0 && realHeight < height)
265     {
266         realHeight <<= 1;
267     }
268 
269 #ifdef NW_PLATFORM_CTR
270     if (texLoadFlag == 0)
271     {
272         switch (texResource.GetImageArea())
273         {
274         case MEMAREA_FCRAM:
275             texLoadFlag = NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP;
276             break;
277 
278         case MEMAREA_VRAMA:
279             texLoadFlag = NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP;
280             break;
281 
282         case MEMAREA_VRAMB:
283             texLoadFlag = NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP;
284             break;
285 
286         default:
287             NW_FATAL_ERROR("unexpected image area.");
288             return TextureInfo();
289         }
290     }
291 #endif
292 
293     GLuint texName = TextureInfo::INVALID;
294     uptr physicalAddress = 0;
295 
296 #ifdef NW_LYT_DMPGL_ENABLED
297     if (Layout::GetLayoutDrawEnable())
298     {
299         // テクスチャ名を取得。
300         glGenTextures(1, &texName);
301         // テクスチャオブジェクトを生成。
302         glBindTexture(GL_TEXTURE_2D, texName);
303         NW_GL_ASSERT();
304 
305         if (texSpec[format].compressed)
306         {
307             glCompressedTexImage2D(
308                 GL_TEXTURE_2D | texLoadFlag,
309                 0, // mipmap level
310                 texSpec[format].format,
311                 realWidth,
312                 realHeight,
313                 0,
314                 imageSize,
315                 pixels);
316                 NW_GL_ASSERT();
317         }
318         else
319         {
320             glTexImage2D(
321                 GL_TEXTURE_2D | texLoadFlag,
322                 0, // mipmap level
323                 texSpec[format].format,
324                 realWidth,
325                 realHeight,
326                 0,
327                 texSpec[format].format,
328                 texSpec[format].type,
329                 pixels);
330                 NW_GL_ASSERT();
331         }
332 
333         // 固定設定
334         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f);
335         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, -1000);
336 
337 #ifdef NW_PLATFORM_CTR
338         {
339             GLint dataAddr = 0;
340             glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_DATA_ADDR_DMP, &dataAddr);
341             physicalAddress = nngxGetPhysicalAddr((uptr)(dataAddr));
342         }
343 #endif
344     }
345     else
346     {
347 #endif // NW_LYT_DMPGL_ENABLED
348 
349 #ifdef NW_PLATFORM_CTR
350         const u32 MEM_MASK = 0x00030000;
351         GLenum transtype = texLoadFlag & 0xFFFF0000;
352         switch (transtype)
353         {
354         case NN_GX_MEM_FCRAM | GL_NO_COPY_FCRAM_DMP:
355             nngxUpdateBuffer(pixels, imageSize);
356             physicalAddress = nngxGetPhysicalAddr((uptr)(pixels));
357             break;
358 
359         case NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP:
360         case NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP:
361             {
362                 GLvoid* (*pGlAllocator)(GLenum, GLenum, GLuint, GLsizei) = NULL;
363                 nngxGetAllocator(&pGlAllocator, NULL);
364                 if (pGlAllocator == NULL)
365                 {
366                     NW_FATAL_ERROR("can not get DMPGL allocator.");
367                     return TextureInfo();
368                 }
369 
370                 GLuint area = transtype & MEM_MASK;
371 
372                 void* address = pGlAllocator(
373                     area, NN_GX_MEM_TEXTURE, texName, imageSize);
374 
375                 if (address != NULL)
376                 {
377                     nngxAddVramDmaCommand(pixels, address, imageSize);
378 
379                     physicalAddress = nngxGetPhysicalAddr((uptr)(address));
380 
381                     // VRAMエリアを廃棄するときのために仮想アドレスと
382                     // エリア情報を保持しておきます。
383                     // TextureInfo を大きくしたくないので texName で代用します。
384                     // テクスチャは 128バイトアライメントなので下位7ビットは
385                     // 空いているはず。
386 
387                     NW_ASSERT(((u32)(address) & MEM_AREA_FIELD) == 0);
388                     texName = u32(address) | u32(area / NN_GX_MEM_FCRAM);
389                 }
390             }
391             break;
392 
393         default:
394             NW_FATAL_ERROR("unexpected texture transfer type.");
395         }
396 #endif
397 
398 #ifdef NW_LYT_DMPGL_ENABLED
399     }
400 #endif
401 
402     return TextureInfo(
403         texName,
404         physicalAddress,
405         TexSize(width, height),
406         TexSize(realWidth, realHeight),
407         format);
408 }
409 
410 void
DeleteTexture(const TextureInfo & texInfo)411 DeleteTexture(const TextureInfo& texInfo)
412 {
413 #ifdef NW_LYT_DMPGL_ENABLED
414     if (Layout::GetLayoutDrawEnable())
415     {
416         GLuint texName = texInfo.GetTextureObject();
417         if (texName != texInfo.INVALID)
418         {
419             glDeleteTextures(1, &texName);
420         }
421     }
422     else
423 #endif
424     {
425 #ifdef NW_PLATFORM_CTR
426         u32 texName = texInfo.GetTextureObject();
427         if (texName != texInfo.INVALID)
428         {
429             // VRAM に配置された場合。
430             // 仮想アドレスとメモリ配置情報が texName に格納されています。
431 
432             GLvoid (*pGlDeallocator)(GLenum, GLenum, GLuint, GLvoid*) = NULL;
433             nngxGetAllocator(NULL, &pGlDeallocator);
434             if (pGlDeallocator == NULL)
435             {
436                 NW_FATAL_ERROR("can not get DMPGL deallocator.");
437             }
438 
439             void* address = (void*)(texName & ~MEM_AREA_FIELD);
440 
441             GLuint area = (texName & MEM_AREA_FIELD) * NN_GX_MEM_FCRAM;
442             NW_ASSERT(area == NN_GX_MEM_VRAMA || area == NN_GX_MEM_VRAMB);
443 
444             pGlDeallocator(
445                 area,
446                 NN_GX_MEM_TEXTURE,
447                 TextureInfo::INVALID /* texName */,
448                 address);
449         }
450 #endif
451     }
452 }
453 
454 void
CalcTextureMtx(math::MTX23 * pTexMtx,const TexSRT & texSRT,const TexMap & texMap)455 CalcTextureMtx(math::MTX23* pTexMtx, const TexSRT& texSRT, const TexMap& texMap)
456 {
457     NW_NULL_ASSERT(pTexMtx);
458 
459     math::MTX23& texMtx = *pTexMtx;
460 
461     math::VEC2 center(0.5f, 0.5f);
462 
463     f32 sinR, cosR;
464     math::SinCosDeg(&sinR, &cosR, texSRT.rotate);
465 
466     f32 a0, a1;
467 
468     a0 = cosR * texSRT.scale.x;
469     a1 =
470 #ifdef ORDER_TSR
471          texSRT.scale.x * (-sinR);
472 #else   // TRS
473          -sinR * texSRT.scale.y;
474 #endif
475 
476     texMtx.m[0][0] = a0;
477     texMtx.m[0][1] = a1;
478     texMtx.m[0][2] = texSRT.translate.x + center.x + a0 * (-center.x) + a1 * (-center.y);
479 
480     a0 =
481 #ifdef ORDER_TSR
482          texSRT.scale.y * sinR;
483 #else   // TRS
484          sinR * texSRT.scale.x;
485 #endif
486     a1 = cosR * texSRT.scale.y;
487     texMtx.m[1][0] = a0;
488     texMtx.m[1][1] = a1;
489     texMtx.m[1][2] = texSRT.translate.y + center.y + a0 * (-center.x) + a1 * (-center.y);
490 
491     f32 su = static_cast<f32>(texMap.GetWidth()) / texMap.GetRealWidth();
492     f32 sv = static_cast<f32>(texMap.GetHeight()) / texMap.GetRealHeight();
493 
494     // math::MTX23 m(
495     //     su,   0,  0,
496     //      0, -sv,  1);
497     // math::MTX23Mult(&texMtx, &m, &texMtx);
498     texMtx.f._00 *= su;
499     texMtx.f._01 *= su;
500     texMtx.f._02 *= su;
501     sv = -sv;
502     texMtx.f._10 *= sv;
503     texMtx.f._11 *= sv;
504     texMtx.f._12 = texMtx.f._12 * sv + 1.0f;
505 }
506 
507 } // namespace nw::lyt
508 } // namespace nw
509