aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkPoint3.cpp
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2015-08-20 05:15:06 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-20 05:15:07 -0700
commit2f0dbc761a626473c19db7de561c7072b12953c5 (patch)
tree5549b8e7359d6a55e171dd1b76634d93b343b491 /src/core/SkPoint3.cpp
parentd1c6b7c5007b5c609b44a9cdfe95ef64a5a8f29f (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.cpp80
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;
+}