1/*---------------------------------------------------------------------------*
2  Project:  NintendoWare
3  File:     math_Matrix34.ipp
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#include <cmath>
18#include <nw/math/math_Vector3.h>
19
20namespace nw {
21namespace math {
22using namespace nn::math;
23
24/*!--------------------------------------------------------------------------*
25  @brief        カメラ行列を設定します。
26
27  @param[out]   pOut     計算結果を受け取るバッファへのポインタ。
28  @param[in]    pCamPos  カメラの位置を指定するベクトルへのポインタ。
29  @param[in]    twist    カメラの視線方向に対する1 円周を 256.0 とする単位での回転角度。
30  @param[in]    pTarget  カメラの注視点を指定するベクトルへのポインタ。
31
32  @return       pOut を返します。
33 *---------------------------------------------------------------------------*/
34NW_MATH_INLINE MTX34*
35MTX34LookAtFIdx(
36    nw::math::MTX34* pOut, const nw::math::VEC3* pCamPos, f32 twist, const nw::math::VEC3* pTarget)
37{
38    using namespace nw::math;
39
40    NW_NULL_ASSERT(pOut);
41    NW_NULL_ASSERT(pCamPos);
42    NW_NULL_ASSERT(pTarget);
43
44    f32 (*const m)[4] = pOut->m;
45
46    // カメラ座標系のZ方向
47    VEC3 lookReverse(pCamPos->x - pTarget->x, pCamPos->y - pTarget->y, pCamPos->z - pTarget->z);
48
49    if ((lookReverse.x == 0.0f) && (lookReverse.z == 0.0f))
50    {
51        // カメラとターゲットのXZ座標が同じ場合ツイストは定義されない
52        m[0][0] = 1.0f;
53        m[0][1] = 0.0f;
54        m[0][2] = 0.0f;
55        m[0][3] = -pCamPos->x;
56
57        m[1][0] = 0.0f;
58        m[1][1] = 0.0f;
59
60        m[2][0] = 0.0f;
61        m[2][2] = 0.0f;
62
63        if (lookReverse.y <= 0.0f)
64        {
65            // 真上を見るとき
66            m[1][2] = 1.0f;
67            m[1][3] = -pCamPos->z;
68
69            m[2][1] = -1.0f;
70            m[2][3] = pCamPos->y;
71        }
72        else
73        {
74            // 真下を見るとき
75            m[1][2] = -1.0f;
76            m[1][3] = pCamPos->z;
77
78            m[2][1] = 1.0f;
79            m[2][3] = -pCamPos->y;
80        }
81    }
82    else
83    {
84        // カメラ座標系のX方向
85        VEC3 r(lookReverse.z, 0.0f, -lookReverse.x);
86
87        VEC3Normalize(&lookReverse, &lookReverse);
88        VEC3Normalize(&r, &r);
89
90        // カメラ座標系のY方向
91        VEC3 u;
92        VEC3Cross(&u, &lookReverse, &r);
93
94        f32 st, ct;
95        SinCosFIdx(&st, &ct, twist);
96        VEC3 right, up;
97
98        // r軸, u軸をru平面上でcameraTwistだけ半時計回りに回転させてrightを求める
99        // r.y == 0であることに注意
100        right.x = st * u.x + ct * r.x;
101        right.y = st * u.y;
102        right.z = st * u.z + ct * r.z;
103
104        up.x    = ct * u.x - st * r.x;
105        up.y    = ct * u.y;
106        up.z    = ct * u.z - st * r.z;
107
108        // right
109        m[0][0] = right.x;
110        m[0][1] = right.y;
111        m[0][2] = right.z;
112        m[0][3] = -VEC3Dot(pCamPos, &right);
113
114        // up
115        m[1][0] = up.x;
116        m[1][1] = up.y;
117        m[1][2] = up.z;
118        m[1][3] = -VEC3Dot(pCamPos, &up);
119
120        // look
121        m[2][0] = lookReverse.x;
122        m[2][1] = lookReverse.y;
123        m[2][2] = lookReverse.z;
124        m[2][3] = -VEC3Dot(pCamPos, &lookReverse);
125    }
126
127    return pOut;
128}
129
130/*!--------------------------------------------------------------------------*
131  @brief        カメラ行列を設定します。
132
133  @param[out]   pOut        計算結果を受け取るバッファへのポインタ。
134  @param[in]    pCamPos     カメラの位置を指定するベクトルへのポインタ。
135  @param[in]    pCamRotate  1 円周を 256.0 とする単位でのカメラの回転量を指定するベクトルへのポインタ。
136
137  @return       pOut を返します。
138 *---------------------------------------------------------------------------*/
139NW_MATH_INLINE MTX34*
140MTX34CameraRotateFIdx(
141    nw::math::MTX34* pOut, const nw::math::VEC3* pCamPos, const nw::math::VEC3* pCamRotate)
142{
143    using namespace nw::math;
144
145    NW_NULL_ASSERT(pOut);
146    NW_NULL_ASSERT(pCamPos);
147    NW_NULL_ASSERT(pCamRotate);
148
149    f32 (*const m)[4] = pOut->m;
150
151    f32 sx, sy, sz, cx, cy, cz;
152    SinCosFIdx(&sx, &cx, pCamRotate->x);
153    SinCosFIdx(&sy, &cy, pCamRotate->y);
154    SinCosFIdx(&sz, &cz, pCamRotate->z);
155
156    // Z軸, X軸, Y軸の順番で回転させている
157    VEC3 right, up, back;
158
159    right.x = sx * sy * sz + cy * cz;
160    right.y = cx * sz;
161    right.z = sx * cy * sz - sy * cz;
162
163    up.x    = sx * sy * cz - cy * sz;
164    up.y    = cx * cz;
165    up.z    = sx * cy * cz + sy * sz;
166
167    back.x  = cx * sy;
168    back.y  = - sx;
169    back.z  = cx * cy;
170
171    m[0][0] = right.x;
172    m[0][1] = right.y;
173    m[0][2] = right.z;
174    m[0][3] = -VEC3Dot(pCamPos, &right);
175
176    m[1][0] = up.x;
177    m[1][1] = up.y;
178    m[1][2] = up.z;
179    m[1][3] = -VEC3Dot(pCamPos, &up);
180
181    m[2][0] = back.x;
182    m[2][1] = back.y;
183    m[2][2] = back.z;
184    m[2][3] = -VEC3Dot(pCamPos, &back);
185
186    return pOut;
187}
188
189/*!--------------------------------------------------------------------------*
190  @brief        カメラ行列を設定します。
191
192  @param[out]   pOut        計算結果を受け取るバッファへのポインタ。
193  @param[in]    pCamPos     カメラの位置を指定するベクトルへのポインタ。
194  @param[in]    pCamRotate  ラジアン単位でのカメラの回転量を指定するベクトルへのポインタ。
195
196  @return       pOut を返します。
197 *---------------------------------------------------------------------------*/
198NW_MATH_INLINE MTX34*
199MTX34CameraRotateRad(MTX34* pOut, const VEC3* pCamPos, const VEC3* pCamRotate)
200{
201    VEC3 rotateFIdx;
202    rotateFIdx.x = NW_MATH_RAD_TO_FIDX(pCamRotate->x);
203    rotateFIdx.y = NW_MATH_RAD_TO_FIDX(pCamRotate->y);
204    rotateFIdx.z = NW_MATH_RAD_TO_FIDX(pCamRotate->z);
205
206    return MTX34CameraRotateFIdx(pOut, pCamPos, &rotateFIdx);
207}
208
209/*!--------------------------------------------------------------------------*
210  @brief        カメラ行列を設定します。
211
212  @param[out]   pOut     計算結果を受け取るバッファへのポインタ。
213  @param[in]    pCamPos  カメラの位置を指定するベクトルへのポインタ。
214  @param[in]    twist    カメラの視線方向に対するラジアン単位での回転角度。
215  @param[in]    pTarget  カメラの注視点を指定するベクトルへのポインタ。
216
217  @return       pOut を返します。
218 *---------------------------------------------------------------------------*/
219NW_MATH_INLINE MTX34*
220MTX34LookAtRad(MTX34* pOut, const VEC3* pCamPos, f32 twist, const VEC3* pTarget)
221{
222    f32 twistFIdx = NW_MATH_RAD_TO_FIDX(twist);
223    return MTX34LookAtFIdx(pOut, pCamPos, twistFIdx, pTarget);
224}
225
226/*!--------------------------------------------------------------------------*
227  @brief        行列からスケール値を取得します。
228                右からかけたスケールを取り出します。
229
230  @param[out]   pOut     計算結果を受け取るバッファへのポインタ。
231  @param[in]    pM       スケールを取り出す行列へのポインタ。
232
233  @return       pOut を返します。
234 *---------------------------------------------------------------------------*/
235NW_MATH_INLINE VEC3*
236MTX34DecomposeToColumnScale(VEC3* pOut, const MTX34* pM)
237{
238    pOut->x = FSqrt((pM->f._00 * pM->f._00) + (pM->f._10 * pM->f._10) + (pM->f._20 * pM->f._20));
239    pOut->y = FSqrt((pM->f._01 * pM->f._01) + (pM->f._11 * pM->f._11) + (pM->f._21 * pM->f._21));
240    pOut->z = FSqrt((pM->f._02 * pM->f._02) + (pM->f._12 * pM->f._12) + (pM->f._22 * pM->f._22));
241
242    return pOut;
243}
244
245/*!--------------------------------------------------------------------------*
246  @brief        行列からスケール値を取得します。
247                左からかけたスケールを取り出します。
248
249  @param[out]   pOut     計算結果を受け取るバッファへのポインタ。
250  @param[in]    pM       スケールを取り出す行列へのポインタ。
251
252  @return       pOut を返します。
253 *---------------------------------------------------------------------------*/
254NW_MATH_INLINE VEC3*
255MTX34DecomposeToRowScale(VEC3* pOut, const MTX34* pM)
256{
257    pOut->x = FSqrt((pM->f._00 * pM->f._00) + (pM->f._01 * pM->f._01) + (pM->f._02 * pM->f._02));
258    pOut->y = FSqrt((pM->f._10 * pM->f._10) + (pM->f._11 * pM->f._11) + (pM->f._12 * pM->f._12));
259    pOut->z = FSqrt((pM->f._20 * pM->f._20) + (pM->f._21 * pM->f._21) + (pM->f._22 * pM->f._22));
260
261    return pOut;
262}
263
264}  // namespace math
265}  // namespace nw
266