/*---------------------------------------------------------------------------* Project: NintendoWare File: main.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 $ *---------------------------------------------------------------------------*/ //------------------------------------------------------------------ // デモ: tagGroupBind // // 概要 // アニメーション区間タグで設定されているグループごとに、 // アニメーションを独立して制御するデモです。 // // アニメーション区間タグは、選択状態(select)と非選択状態(unselect)の // 2つがあり、それぞれにグループ group_1, group_2 を指定しています。 // 2つのグループそれぞれにアニメーションの状態を管理するため、 // AnimTransform を 4つ作成し、選択状態によって有効/無効を切り替えています。 // // 操作 // 十字ボタンの操作でクロスラインが移動します。 // クロスラインのクロスしている部分をペインに移動させると、 // そのペインのアニメーションが変化します。 // //------------------------------------------------------------------ #include #include namespace { typedef nw::ut::MoveArray File; /*---------------------------------------------------------------------------* @brief 描画の初期設定を行います。 @param width 画面の幅。 @param height 画面の高さ。 *---------------------------------------------------------------------------*/ void InitDraw(int width, int height) { // カラーバッファ情報 // LCDの向きに合わせて、幅と高さを入れ替えています。 const nw::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT }; const u32 commands[] = { // ビューポートの設定 NW_FONT_CMD_SET_VIEWPORT(0, 0, colBufInfo.width, colBufInfo.height), // シザー処理を無効 NW_FONT_CMD_SET_DISABLE_SCISSOR(colBufInfo), // wバッファの無効化 // デプスレンジの設定 // ポリゴンオフセットの無効化 NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET( 0.0f, // wScale : 0.0 でWバッファが無効 0.0f, // depth range near 1.0f, // depth range far 0, // polygon offset units : 0.0 で ポリゴンオフセットが無効 colBufInfo), }; nngxAdd3DCommand(commands, sizeof(commands), true); static const u32 constCommands[] = { // カリングを無効 NW_FONT_CMD_SET_CULL_FACE(NW_FONT_CMD_CULL_FACE_DISABLE), // ステンシルテストを無効 NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(), // デプステストを無効 // カラーバッファの全ての成分を書き込み可 NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK( false, // isDepthTestEnabled 0, // depthFunc true, // depthMask true, // red true, // green true, // blue true), // alpha // アーリーデプステストを無効 NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST(false), // フレームバッファアクセス制御 NW_FONT_CMD_SET_FBACCESS( true, // colorRead true, // colorWrite false, // depthRead false, // depthWrite false, // stencilRead false), // stencilWrite }; nngxAdd3DCommand(constCommands, sizeof(constCommands), true); } /*---------------------------------------------------------------------------* @brief アニメーションのセットアップを行います。 @details アニメーション区間タグで指定されているグループごとに AnimTransform オブジェクトを作成し、バインドします。 無駄な AnimationLink の確保を避けるため、あらかじめバインドに必要な アニメーションの数を調べてからAnimTransform を構築しています。 @param pLayout レイアウトです。 @param animRes アニメーションリソースです。 @param groupRef アニメーション区間タグのグループ情報です。 @param pResAccessor リソースアクセサです。 @return 作成した AnimTransform オブジェクトへのポインタを返します。 *---------------------------------------------------------------------------*/ nw::lyt::AnimTransform* SetupAnimTransform( nw::lyt::Layout* pLayout, const nw::lyt::AnimResource& animRes, const nw::lyt::AnimationGroupRef& groupRef, nw::lyt::ResourceAccessor* pResAccessor ) { // グループにあるペイン全てで必要になるアニメーションの個数を数えます。 nw::lyt::Group *const pGroup = pLayout->GetGroupContainer()->FindGroupByName(groupRef.GetName()); NW_NULL_ASSERT(pGroup); const u16 animNum = animRes.CalcAnimationNum(pGroup, animRes.IsDescendingBind()); // nw::lyt::AnimTransform オブジェクトを作成し、 // バインドするアニメーション数を明示的に指定してリソースをセットします。 nw::lyt::AnimTransform *const pAnimTrans = pLayout->CreateAnimTransform(); NW_NULL_ASSERT(pAnimTrans); pAnimTrans->SetResource(animRes.GetResourceBlock(), pResAccessor, animNum); // アニメーションをバインドします。 BindAnimation(pGroup, pAnimTrans, animRes.IsDescendingBind()); return pAnimTrans; } /*---------------------------------------------------------------------------* @brief モデルビュー行列と射影行列を設定します。 @param drawInfo 描画情報です。 @param layout レイアウトです。 *---------------------------------------------------------------------------*/ void SetupCamera(nw::lyt::DrawInfo& drawInfo, const nw::lyt::Layout& layout) { nw::ut::Rect layoutRect = layout.GetLayoutRect(); f32 znear = 0.f; f32 zfar = 500.f; // 射影行列を正射影に設定 // (Layoutデータは横向きなので向きを変換する) nw::math::MTX44 projMtx; nw::math::MTX44Ortho( &projMtx, layoutRect.bottom, // left layoutRect.top, // right -layoutRect.right, // bottom -layoutRect.left, // top znear, zfar); drawInfo.SetProjectionMtx(projMtx); // モデルビュー行列を設定 // (Layoutデータは横向きなので画面の上方向はレイアウトの-X方向) nw::math::VEC3 pos(0, 0, 1); nw::math::VEC3 up(-1, 0, 0); nw::math::VEC3 target(0, 0, 0); nw::math::MTX34 viewMtx; nw::math::MTX34LookAt(&viewMtx, &pos, &up, &target); drawInfo.SetViewMtx(viewMtx); } /*---------------------------------------------------------------------------* @brief カーソルの位置をレイアウトの座標系で取得します。 @param pLayout レイアウトです。 @return カーソル位置を返します。 *---------------------------------------------------------------------------*/ const nw::math::VEC2 GetCursorPosition(nw::lyt::Layout* pLayout) { const nw::ut::Rect& layoutRect = pLayout->GetLayoutRect(); const nw::math::VEC2 center( (layoutRect.left + layoutRect.right ) / 2, (layoutRect.top + layoutRect.bottom) / 2 ); nw::math::VEC2 curPos; // カーソルの座標系をレイアウトの座標系に変換します。 const nw::ut::Rect cursorRect(-0.5, 0.5, 0.5, -0.5); // LTRB nw::demo::Pad& pad = *nw::demo::PadFactory::GetPad(); const nw::math::VEC2 stick = pad.GetAnalogStick(); curPos.x = center.x + stick.x / (cursorRect.right - cursorRect.left ) * (layoutRect.right - layoutRect.left ); curPos.y = center.y + stick.y / (cursorRect.top - cursorRect.bottom) * (layoutRect.top - layoutRect.bottom); // NW_LOG("curPos %f, %f\n", curPos.x, curPos.y); return curPos; } /*---------------------------------------------------------------------------* @brief カーソルの位置をレイアウトに反映します。 @param pLayout レイアウトです。 @param curPos レイアウトの座標系におけるカーソルの位置です。 *---------------------------------------------------------------------------*/ void ApplyCursorPosition(nw::lyt::Layout* pLayout, const nw::math::VEC2& curPos) { nw::lyt::Pane* pCrossBar = pLayout->GetRootPane()->FindPaneByName("CrossBar", true); if (pCrossBar) { pCrossBar->SetTranslate(curPos); } } /*---------------------------------------------------------------------------* @brief 指定されたペインおよびその子孫となるペインの中で、 Bounding ペインを探します。 @param pPane 探索の起点となるペインです。 @return 見つかった場合は、そのペインのポインタを返します。 見つからなかった場合は、NULLを返します。 *---------------------------------------------------------------------------*/ nw::lyt::Bounding* FindBoundingPane(nw::lyt::Pane* pPane) { // Bound ペインか nw::lyt::Bounding* pBounding = NULL; if ((pBounding = nw::ut::DynamicCast(pPane)) != NULL) { return pBounding; } else { // 子供のチェック for (nw::lyt::PaneList::Iterator it = pPane->GetChildList().GetBeginIter(); it != pPane->GetChildList().GetEndIter(); ++it) { if ((pBounding = FindBoundingPane(&(*it))) != NULL) { return pBounding; } } } return 0; } /*---------------------------------------------------------------------------* @brief 指定されたグループに含まれるペインの子孫の中ある Bounding ペインが 指定された点を含むかどうかをチェックします。 (ペインがXおよびY軸周りで回転している場合は考慮していません。) @param pGroup 探すグループです。 @param pos 探す点です。 @return 含む場合は真を返します。 *---------------------------------------------------------------------------*/ bool TestHit( nw::lyt::Group* pGroup, const nw::math::VEC2& pos ) { nw::lyt::PaneLinkList& paneList = pGroup->GetPaneList(); for (nw::lyt::PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it) { nw::lyt::Bounding *const pBounding = FindBoundingPane(it->target); NW_NULL_ASSERT(pBounding); if (nw::lyt::IsContain(pBounding, pos)) { return true; } } return false; } /*---------------------------------------------------------------------------* @brief アニメーションのフレームを更新します。 @details アニメーションデータがループするアニメーションであること仮定しています。 @param pAnimTrans フレーム値の更新対象です。 *---------------------------------------------------------------------------*/ void UpdateAnimationFrame(nw::lyt::AnimTransform* pAnimTrans) { f32 animFrame = pAnimTrans->GetFrame() + 1.0f; if (animFrame >= pAnimTrans->GetFrameSize()) { animFrame -= pAnimTrans->GetFrameSize(); } pAnimTrans->SetFrame(animFrame); } } // namespace /*---------------------------------------------------------------------------* @brief サンプルのメイン関数です。 *---------------------------------------------------------------------------*/ void nnMain() { nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance(); demoApp.Initialize(); nw::lyt::Initialize(&demoApp.GetAllocator(), &demoApp.GetDeviceAllocator()); nw::lyt::Layout *const pLayout = new nw::lyt::Layout(); // レイアウトのバイナリリソース(アーカイブ)を読み込み。 File fileLayout = nw::demo::Utility::LoadFile( &demoApp.GetDeviceAllocator(), NW_DEMO_FILE_PATH(L"layout.arc"), 128); if (fileLayout.empty()) { NW_FATAL_ERROR("can not open layout archive.\n"); } // バイナリリソースのルートディレクトリを指定してリソースアクセサを生成。 nw::lyt::ArcResourceAccessor* pResAccessor = new nw::lyt::ArcResourceAccessor; if (!pResAccessor->Attach(fileLayout.begin(), ".")) { NW_FATAL_ERROR("can not attach layout archive.\n"); } // レイアウトリソースの読み込み { const void* lytRes = pResAccessor->GetResource(0, "tagGroupBind.bclyt"); NW_NULL_ASSERT(lytRes); pLayout->Build(lytRes, pResAccessor); } enum { ANIMTYPE_UNSELECT, ANIMTYPE_SELECT, ANIMTYPE_MAX }; // アニメーションファイル const char *const brlanFileNames[ANIMTYPE_MAX] = { "tagGroupBind_unselect.bclan", "tagGroupBind_select.bclan", }; nw::lyt::AnimResource animRess[ANIMTYPE_MAX]; // アニメーションリソースの取得します。 // 同時に、brlanファイル内のグループの総数を求めます。 int animTransNum = 0; for (int i = 0; i < ANIMTYPE_MAX; ++i) { const void* lpaRes = pResAccessor->GetResource(0, brlanFileNames[i]); NW_NULL_ASSERT(lpaRes); animRess[i].Set(lpaRes); NW_ASSERT(animRess[i].GetGroupNum() > 0); animTransNum += animRess[i].GetGroupNum(); } // グループ毎に nw::lyt::AnimTransform を構築するため、 // グループの総数分 nw::lyt::AnimTransform ポインタのメモリを確保します。 nw::lyt::AnimTransform* *const animTranss = new nw::lyt::AnimTransform* [animTransNum]; // アニメーションのバインドを行います。 { int animTransIdx = 0; for (int anmIdx = 0; anmIdx < ANIMTYPE_MAX; ++anmIdx) { const nw::lyt::AnimationGroupRef *const groupRefs = animRess[anmIdx].GetGroupArray(); for (int grpIdx = 0; grpIdx < animRess[anmIdx].GetGroupNum(); ++grpIdx) { animTranss[animTransIdx++] = SetupAnimTransform(pLayout, animRess[anmIdx], groupRefs[grpIdx], pResAccessor); } } } nw::lyt::GraphicsResource graphicsResource; // グローバルなリソースファイルを読み込みます。 { graphicsResource.StartSetup(); const wchar_t* resourcePath = 0; for (int i = 0; (resourcePath = graphicsResource.GetResourcePath(i)) != NULL; ++i) { File file = nw::demo::Utility::LoadFile(&demoApp.GetAllocator(), resourcePath); if (file.empty()) { NW_FATAL_ERROR("can not read lyt resource file."); } graphicsResource.SetResource(i, file.begin(), file.size(), false); } graphicsResource.FinishSetup(); } nw::lyt::DrawInfo drawInfo; drawInfo.SetGraphicsResource(&graphicsResource); nw::math::VEC2 curPos(0.f, 0.f); nw::lyt::Drawer drawer; drawer.Initialize(graphicsResource); const nw::ut::FloatColor clearColor(0.3f, 0.3f, 0.3f, 1.0f); const f32 clearDepth = 0.0f; bool loop = true; while (loop) { nw::demo::PadFactory::GetPad()->Update(); demoApp.SetRenderingTarget(demoApp.DISPLAY0); { demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); InitDraw(demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT); SetupCamera(drawInfo, *pLayout); curPos = GetCursorPosition(pLayout); ApplyCursorPosition(pLayout, curPos); pLayout->Animate(); pLayout->CalculateMtx(drawInfo); drawer.DrawBegin(drawInfo); drawer.Draw(pLayout, drawInfo); drawer.DrawEnd(drawInfo); // カーソル位置をレイアウト座標系からビュー座標系に変換します。 { nw::math::VEC3 tmp(curPos.x, curPos.y, 0.0f); nw::math::VEC3Transform(&tmp, &drawInfo.GetViewMtx(), &tmp); curPos = nw::math::VEC2(tmp.x, tmp.y); } // nw::lyt::Layout::CalculateMtx() を呼び出した後の行列を利用してヒットチェックを行います。 // グループ単位でペインのヒットチェックを行い、アニメーションの有効/無効を切り替えます。 int animTransIdx = 0; for (int anmIdx = 0; anmIdx < ANIMTYPE_MAX; ++anmIdx) { const nw::lyt::AnimationGroupRef *const groupRefs = animRess[anmIdx].GetGroupArray(); for (int grpIdx = 0; grpIdx < animRess[anmIdx].GetGroupNum(); ++grpIdx) { nw::lyt::Group *const pGroup = pLayout->GetGroupContainer()->FindGroupByName(groupRefs[grpIdx].GetName()); const bool bSelect = TestHit(pGroup, curPos); const bool bEnable = anmIdx == ANIMTYPE_UNSELECT ? ! bSelect: bSelect; // アニメーションの有効/無効を切り替えます。 nw::lyt::SetAnimationEnable(pGroup, animTranss[animTransIdx], bEnable, animRess[anmIdx].IsDescendingBind()); // アニメーションが有効な場合、フレームを更新しておきます。 if (bEnable) { UpdateAnimationFrame(animTranss[animTransIdx]); } ++animTransIdx; } } } demoApp.SetRenderingTarget(demoApp.DISPLAY1); { demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); } demoApp.SwapBuffer(demoApp.DISPLAY_BOTH); } delete [] animTranss; delete pLayout; delete pResAccessor; }