diff options
author | robertphillips <robertphillips@google.com> | 2015-08-20 05:15:06 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-20 05:15:07 -0700 |
commit | 2f0dbc761a626473c19db7de561c7072b12953c5 (patch) | |
tree | 5549b8e7359d6a55e171dd1b76634d93b343b491 /src/core/SkPoint3.cpp | |
parent | d1c6b7c5007b5c609b44a9cdfe95ef64a5a8f29f (diff) |
Update SkLightingShader to support rotation
This also:
makes the SkLightingShader handle normal maps where the rects aren't aligned between the diffuse and normal maps.
adds a light aggregating class (Lights) to SkLightingShader (along with a Builder nested class).
Split out of https://codereview.chromium.org/1261433009/ (Add SkCanvas::drawLitAtlas call)
Committed: https://skia.googlesource.com/skia/+/45b59ed6e4e231814dbdb9f707b3d2a7ee50de84
Review URL: https://codereview.chromium.org/1291783003
Diffstat (limited to 'src/core/SkPoint3.cpp')
-rw-r--r-- | src/core/SkPoint3.cpp | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/core/SkPoint3.cpp b/src/core/SkPoint3.cpp new file mode 100644 index 0000000000..3b5586b067 --- /dev/null +++ b/src/core/SkPoint3.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkPoint3.h" + +// Returns the square of the Euclidian distance to (x,y,z). +static inline float get_length_squared(float x, float y, float z) { + return x * x + y * y + z * z; +} + +// Calculates the square of the Euclidian distance to (x,y,z) and stores it in +// *lengthSquared. Returns true if the distance is judged to be "nearly zero". +// +// This logic is encapsulated in a helper method to make it explicit that we +// always perform this check in the same manner, to avoid inconsistencies +// (see http://code.google.com/p/skia/issues/detail?id=560 ). +static inline bool is_length_nearly_zero(float x, float y, float z, float *lengthSquared) { + *lengthSquared = get_length_squared(x, y, z); + return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); +} + +SkScalar SkPoint3::Length(SkScalar x, SkScalar y, SkScalar z) { + float magSq = get_length_squared(x, y, z); + if (SkScalarIsFinite(magSq)) { + return sk_float_sqrt(magSq); + } else { + double xx = x; + double yy = y; + double zz = z; + return (float)sqrt(xx * xx + yy * yy + zz * zz); + } +} + +/* + * We have to worry about 2 tricky conditions: + * 1. underflow of magSq (compared against nearlyzero^2) + * 2. overflow of magSq (compared w/ isfinite) + * + * If we underflow, we return false. If we overflow, we compute again using + * doubles, which is much slower (3x in a desktop test) but will not overflow. + */ +bool SkPoint3::normalize() { + float magSq; + if (is_length_nearly_zero(fX, fY, fZ, &magSq)) { + this->set(0, 0, 0); + return false; + } + + float scale; + if (SkScalarIsFinite(magSq)) { + scale = 1.0f / sk_float_sqrt(magSq); + } else { + // our magSq step overflowed to infinity, so use doubles instead. + // much slower, but needed when x, y or z is very large, otherwise we + // divide by inf. and return (0,0,0) vector. + double xx = fX; + double yy = fY; + double zz = fZ; +#ifdef SK_CPU_FLUSH_TO_ZERO + // The iOS ARM processor discards small denormalized numbers to go faster. + // Casting this to a float would cause the scale to go to zero. Keeping it + // as a double for the multiply keeps the scale non-zero. + double dscale = 1.0f / sqrt(xx * xx + yy * yy + zz * zz); + fX = x * dscale; + fY = y * dscale; + fZ = z * dscale; + return true; +#else + scale = (float)(1.0f / sqrt(xx * xx + yy * yy + zz * zz)); +#endif + } + fX *= scale; + fY *= scale; + fZ *= scale; + return true; +} |