Matrix Matrix::operator*(Matrix oper)
{
	float *B = oper.GetMatrix();
	int RB = oper.GetRows();
	int CB = oper.GetColumns();
	Matrix C(oper.GetColumns(), GetColumns());
	int CSize = C.GetColumns()*C.GetRows();
	int Columns = C.GetColumns();
	float *Result = C.GetMatrix();

	Result[0] = A[0]*B[0] + A[1]*B[3] + A[2]*B[6]; 
	Result[1] = A[0]*B[1] + A[1]*B[4] + A[2]*B[7]; 
	Result[2] = A[0]*B[2] + A[1]*B[5] + A[2]*B[8]; 

	Result[3] = A[3]*B[0] + A[4]*B[3] + A[5]*B[6]; 
	Result[4] = A[3]*B[1] + A[4]*B[4] + A[5]*B[7]; 
	Result[5] = A[3]*B[2] + A[4]*B[5] + A[5]*B[8]; 

	Result[6] = A[6]*B[0] + A[7]*B[3] + A[8]*B[6]; 
	Result[7] = A[6]*B[1] + A[7]*B[4] + A[8]*B[7]; 
	Result[8] = A[6]*B[2] + A[7]*B[5] + A[8]*B[8]; 
	

	return C;
}
void Manipulator::RenderSphere(LPD3DXEFFECT effect,
    const Matrix& projection, const Matrix& view,
    const D3DXVECTOR3& color, const Transform& world)
{
    D3DXMATRIX wvp = world.GetMatrix() * view.GetMatrix() * projection.GetMatrix();
    effect->SetMatrix(DxConstant::WordViewProjection, &wvp);
    effect->SetFloatArray(DxConstant::VertexColor, &color.x, 3);

    UINT nPasses = 0;
    effect->Begin(&nPasses, 0);
    for(UINT iPass = 0; iPass < nPasses; iPass++)
    {
        effect->BeginPass(iPass);
        m_sphere->DrawSubset(0);
        effect->EndPass();
    }
    effect->End();
}
void CollisionMesh::DrawMesh(const Matrix& projection, const Matrix& view, const D3DXVECTOR3& color)
{
    if(m_draw && m_geometry)
    {
        LPD3DXEFFECT shader = m_geometry->GetShader();
        D3DXMATRIX wvp = m_world.GetMatrix() * view.GetMatrix() * projection.GetMatrix();
        shader->SetMatrix(DxConstant::WordViewProjection, &wvp);
        shader->SetTechnique(DxConstant::DefaultTechnique);
        shader->SetFloatArray(DxConstant::VertexColor, &(color.x), 3);

        UINT nPasses = 0;
        shader->Begin(&nPasses, 0);
        for(UINT pass = 0; pass < nPasses; ++pass)
        {
            shader->BeginPass(pass);
            m_geometry->GetMesh()->DrawSubset(0);
            shader->EndPass();
        }
        shader->End();
    }
}
void Manipulator::UpdateState(Manipulator::MeshPtr mesh, const D3DXVECTOR2& direction, 
    const Matrix& world, const Matrix& invProjection, bool pressed, float deltatime)
{
    if(m_selectedTool == NONE)
    {
        return;
    }

    // Ensure the tool axis are aligned with the mesh axis
    std::for_each(m_tools[m_selectedTool]->axis.begin(), 
        m_tools[m_selectedTool]->axis.end(), [&mesh](const MeshPtr& axis)
    {
        axis->SetRotationMatrix(mesh->GetRotationMatrix());
    });

    if(pressed)
    {
        if(m_selectedAxis != NO_AXIS && D3DXVec2Length(&direction) > 0.0f)
        {
            D3DXVECTOR3 axis;
            switch(m_selectedAxis)
            {
            case X_AXIS:
                axis = mesh->Right();
                break;
            case Y_AXIS:
                axis = mesh->Up();
                break;
            case Z_AXIS:
                axis = mesh->Forward();
                break;
            }

            D3DXVECTOR3 mouseDirection(direction.x, direction.y, CAMERA_NEAR);
            mouseDirection.x *= -1.0f;

            // Transform the screen space mouse direction into global 3D coordinates
            // Camera world matrix is the inverse view matrix
            D3DXVec3TransformNormal(&mouseDirection, &mouseDirection, &invProjection.GetMatrix());
            D3DXVec3TransformNormal(&mouseDirection, &mouseDirection, &world.GetMatrix());

            D3DXVec3Normalize(&mouseDirection, &mouseDirection);
            D3DXVec3Normalize(&axis, &axis);

            const float dot = D3DXVec3Dot(&axis, &mouseDirection);
            const float angle = RadToDeg(std::acos(dot));
            const float speed = fabs(dot) * (angle > 90.0f ? -1.0f : 1.0f) * deltatime;

            if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::MESH))
            {
                m_engine->diagnostic()->UpdateLine(Diagnostic::MESH,
                    "MouseDirection3D", Diagnostic::WHITE, mesh->Position(),
                    mesh->Position() + mouseDirection * 20.0f);

                m_engine->diagnostic()->UpdateText(Diagnostic::MESH,
                    "MovementDot", Diagnostic::WHITE, StringCast(dot));

                m_engine->diagnostic()->UpdateText(Diagnostic::MESH,
                    "MovementAngle", Diagnostic::WHITE, StringCast(angle));
            }

            switch(m_selectedTool)
            {
            case ROTATE:
                RotateMesh(mesh, speed * ROTATION_SPEED);
                break;
            case MOVE:
                mesh->ResetAnimation();
                TranslateMesh(mesh, speed * TRANSLATION_SPEED);
                break;
            case SCALE:
                ScaleMesh(mesh, speed * SCALE_SPEED);
                break;
            case ANIMATE:
                AnimateMesh(mesh, speed * TRANSLATION_SPEED);
                break;
            }
        }
    }

    if(m_selectedTool == ANIMATE)
    {
        if(mesh->GetAnimationPoints().empty() || (!pressed && m_saveAnimation))
        {
            m_saveAnimation = false;
            mesh->SavePosition();
        }
    }
}