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