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