gecko-dev/dom/media/webaudio/ThreeDPoint.h
Paul Adenot e34a6067fb Bug 1355798 - Fix a division by zero in PannerNode.cpp. r=dminor
This happens when the listener and a PannerNode are at the same position, and
a cone gain has been specified.

The issue is that our implementation of 3d vector normalization does not
special-case vectors that have all components at zero, that dividing by zero
results in infinity, and multiplying by infinity produces NaN.

This end up setting the volume member for the output AudioChunk to NaN, and this
breaks everything downstream, of course. In practice, silence is output, with
some clicks (on linux/pulse at least).

MozReview-Commit-ID: 8u54LixvYMu

--HG--
extra : rebase_source : 3b37970b42e5c60cd6e39d3197b580edc63b5ac9
2017-04-12 15:44:19 +02:00

95 lines
2.0 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ThreeDPoint_h_
#define ThreeDPoint_h_
#include <cmath>
#include <algorithm>
namespace mozilla {
namespace dom {
struct ThreeDPoint final
{
ThreeDPoint()
: x(0.)
, y(0.)
, z(0.)
{
}
ThreeDPoint(double aX, double aY, double aZ)
: x(aX)
, y(aY)
, z(aZ)
{
}
double Magnitude() const
{
return sqrt(x * x + y * y + z * z);
}
void Normalize()
{
// Zero vectors cannot be normalized. For our purpose, normalizing a zero
// vector results in a zero vector.
if (IsZero()) {
return;
}
// Normalize with the maximum norm first to avoid overflow and underflow.
double invMax = 1 / MaxNorm();
x *= invMax;
y *= invMax;
z *= invMax;
double invDistance = 1 / Magnitude();
x *= invDistance;
y *= invDistance;
z *= invDistance;
}
ThreeDPoint CrossProduct(const ThreeDPoint& rhs) const
{
return ThreeDPoint(y * rhs.z - z * rhs.y,
z * rhs.x - x * rhs.z,
x * rhs.y - y * rhs.x);
}
double DotProduct(const ThreeDPoint& rhs)
{
return x * rhs.x + y * rhs.y + z * rhs.z;
}
bool IsZero() const
{
return x == 0 && y == 0 && z == 0;
}
// For comparing two vectors of close to unit magnitude.
bool FuzzyEqual(const ThreeDPoint& other);
double x, y, z;
private:
double MaxNorm() const
{
return std::max(fabs(x), std::max(fabs(y), fabs(z)));
}
};
ThreeDPoint operator-(const ThreeDPoint& lhs, const ThreeDPoint& rhs);
ThreeDPoint operator*(const ThreeDPoint& lhs, const ThreeDPoint& rhs);
ThreeDPoint operator*(const ThreeDPoint& lhs, const double rhs);
bool operator==(const ThreeDPoint& lhs, const ThreeDPoint& rhs);
} // namespace dom
} // namespace mozilla
#endif