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