aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2015-07-13 13:16:44 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-13 13:16:44 -0700
commit3d32d768cd8b66c49c070495c08f7933b9dd2423 (patch)
tree6676e917988dcecc00b5f33f5e33a4e7c2849344
parent52e7657cd850f95e66eb23c6d138ee45149a1039 (diff)
Add new SkPoint3 class
The existing Light filter and the upcoming Lighting Shader both need a Point3 class Review URL: https://codereview.chromium.org/1229693009
-rw-r--r--bench/LightingBench.cpp107
-rw-r--r--gm/imagefiltersscaled.cpp9
-rw-r--r--gm/lighting.cpp17
-rw-r--r--gyp/effects.gypi8
-rw-r--r--gyp/skia_for_chromium_defines.gypi1
-rw-r--r--include/effects/SkLightingImageFilter.h35
-rw-r--r--include/effects/SkPoint3.h113
-rw-r--r--samplecode/SampleFilterFuzz.cpp7
-rwxr-xr-xsamplecode/SampleLighting.cpp13
-rw-r--r--src/effects/SkLightingImageFilter.cpp91
-rw-r--r--src/effects/SkPoint3.cpp80
-rw-r--r--tests/ImageFilterTest.cpp11
-rw-r--r--tests/Point3Test.cpp130
13 files changed, 467 insertions, 155 deletions
diff --git a/bench/LightingBench.cpp b/bench/LightingBench.cpp
index a56ed226e2..ce6c11989d 100644
--- a/bench/LightingBench.cpp
+++ b/bench/LightingBench.cpp
@@ -9,6 +9,7 @@
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkLightingImageFilter.h"
+#include "SkPoint3.h"
#define FILTER_WIDTH_SMALL SkIntToScalar(32)
#define FILTER_HEIGHT_SMALL SkIntToScalar(32)
@@ -30,63 +31,65 @@ protected:
}
}
- static SkPoint3 getPointLocation() {
- static SkPoint3 pointLocation(0, 0, SkIntToScalar(10));
+ static SkPoint3 GetPointLocation() {
+ static SkPoint3 pointLocation = SkPoint3::Make(0, 0, SkIntToScalar(10));
return pointLocation;
}
- static SkPoint3 getDistantDirection() {
+ static SkPoint3 GetDistantDirection() {
static SkScalar azimuthRad = SkDegreesToRadians(SkIntToScalar(225));
static SkScalar elevationRad = SkDegreesToRadians(SkIntToScalar(5));
- static SkPoint3 distantDirection(SkScalarMul(SkScalarCos(azimuthRad),
- SkScalarCos(elevationRad)),
- SkScalarMul(SkScalarSin(azimuthRad),
- SkScalarCos(elevationRad)),
- SkScalarSin(elevationRad));
+ static SkPoint3 distantDirection = SkPoint3::Make(SkScalarMul(SkScalarCos(azimuthRad),
+ SkScalarCos(elevationRad)),
+ SkScalarMul(SkScalarSin(azimuthRad),
+ SkScalarCos(elevationRad)),
+ SkScalarSin(elevationRad));
return distantDirection;
}
- static SkPoint3 getSpotLocation() {
- static SkPoint3 spotLocation(SkIntToScalar(-10), SkIntToScalar(-10), SkIntToScalar(20));
+ static SkPoint3 GetSpotLocation() {
+ static SkPoint3 spotLocation = SkPoint3::Make(SkIntToScalar(-10),
+ SkIntToScalar(-10),
+ SkIntToScalar(20));
return spotLocation;
}
- static SkPoint3 getSpotTarget() {
- static SkPoint3 spotTarget(SkIntToScalar(40), SkIntToScalar(40), 0);
+ static SkPoint3 GetSpotTarget() {
+ static SkPoint3 spotTarget = SkPoint3::Make(SkIntToScalar(40), SkIntToScalar(40), 0);
return spotTarget;
}
- static SkScalar getSpotExponent() {
+ static SkScalar GetSpotExponent() {
static SkScalar spotExponent = SK_Scalar1;
return spotExponent;
}
- static SkScalar getCutoffAngle() {
+ static SkScalar GetCutoffAngle() {
static SkScalar cutoffAngle = SkIntToScalar(15);
return cutoffAngle;
}
- static SkScalar getKd() {
+ static SkScalar GetKd() {
static SkScalar kd = SkIntToScalar(2);
return kd;
}
- static SkScalar getKs() {
+ static SkScalar GetKs() {
static SkScalar ks = SkIntToScalar(1);
return ks;
}
- static SkScalar getShininess() {
+ static SkScalar GetShininess() {
static SkScalar shininess = SkIntToScalar(8);
return shininess;
}
- static SkScalar getSurfaceScale() {
+ static SkScalar GetSurfaceScale() {
static SkScalar surfaceScale = SkIntToScalar(1);
return surfaceScale;
}
- static SkColor getWhite() {
+ static SkColor GetWhite() {
static SkColor white(0xFFFFFFFF);
return white;
}
@@ -106,10 +109,10 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreatePointLitDiffuse(getPointLocation(),
- getWhite(),
- getSurfaceScale(),
- getKd()));
+ draw(loops, canvas, SkLightingImageFilter::CreatePointLitDiffuse(GetPointLocation(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKd()));
}
private:
@@ -127,10 +130,10 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreateDistantLitDiffuse(getDistantDirection(),
- getWhite(),
- getSurfaceScale(),
- getKd()));
+ draw(loops, canvas, SkLightingImageFilter::CreateDistantLitDiffuse(GetDistantDirection(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKd()));
}
private:
@@ -148,13 +151,13 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreateSpotLitDiffuse(getSpotLocation(),
- getSpotTarget(),
- getSpotExponent(),
- getCutoffAngle(),
- getWhite(),
- getSurfaceScale(),
- getKd()));
+ draw(loops, canvas, SkLightingImageFilter::CreateSpotLitDiffuse(GetSpotLocation(),
+ GetSpotTarget(),
+ GetSpotExponent(),
+ GetCutoffAngle(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKd()));
}
private:
@@ -172,11 +175,11 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreatePointLitSpecular(getPointLocation(),
- getWhite(),
- getSurfaceScale(),
- getKs(),
- getShininess()));
+ draw(loops, canvas, SkLightingImageFilter::CreatePointLitSpecular(GetPointLocation(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKs(),
+ GetShininess()));
}
private:
@@ -194,11 +197,11 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreateDistantLitSpecular(getDistantDirection(),
- getWhite(),
- getSurfaceScale(),
- getKs(),
- getShininess()));
+ draw(loops, canvas, SkLightingImageFilter::CreateDistantLitSpecular(GetDistantDirection(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKs(),
+ GetShininess()));
}
private:
@@ -216,14 +219,14 @@ protected:
}
void onDraw(const int loops, SkCanvas* canvas) override {
- draw(loops, canvas, SkLightingImageFilter::CreateSpotLitSpecular(getSpotLocation(),
- getSpotTarget(),
- getSpotExponent(),
- getCutoffAngle(),
- getWhite(),
- getSurfaceScale(),
- getKs(),
- getShininess()));
+ draw(loops, canvas, SkLightingImageFilter::CreateSpotLitSpecular(GetSpotLocation(),
+ GetSpotTarget(),
+ GetSpotExponent(),
+ GetCutoffAngle(),
+ GetWhite(),
+ GetSurfaceScale(),
+ GetKs(),
+ GetShininess()));
}
private:
diff --git a/gm/imagefiltersscaled.cpp b/gm/imagefiltersscaled.cpp
index 9a80964a0e..e7a68d747d 100644
--- a/gm/imagefiltersscaled.cpp
+++ b/gm/imagefiltersscaled.cpp
@@ -16,6 +16,7 @@
#include "SkMorphologyImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkPerlinNoiseShader.h"
+#include "SkPoint3.h"
#include "SkRectShaderImageFilter.h"
#include "SkScalar.h"
#include "gm.h"
@@ -75,9 +76,11 @@ protected:
SkAutoTUnref<SkShader> noise(SkPerlinNoiseShader::CreateFractalNoise(
SkDoubleToScalar(0.1), SkDoubleToScalar(0.05), 1, 0));
- SkPoint3 pointLocation(0, 0, SkIntToScalar(10));
- SkPoint3 spotLocation(SkIntToScalar(-10), SkIntToScalar(-10), SkIntToScalar(20));
- SkPoint3 spotTarget(SkIntToScalar(40), SkIntToScalar(40), 0);
+ SkPoint3 pointLocation = SkPoint3::Make(0, 0, SkIntToScalar(10));
+ SkPoint3 spotLocation = SkPoint3::Make(SkIntToScalar(-10),
+ SkIntToScalar(-10),
+ SkIntToScalar(20));
+ SkPoint3 spotTarget = SkPoint3::Make(SkIntToScalar(40), SkIntToScalar(40), 0);
SkScalar spotExponent = SK_Scalar1;
SkScalar cutoffAngle = SkIntToScalar(15);
SkScalar kd = SkIntToScalar(2);
diff --git a/gm/lighting.cpp b/gm/lighting.cpp
index 0bfbb47a95..6df58516b2 100644
--- a/gm/lighting.cpp
+++ b/gm/lighting.cpp
@@ -8,6 +8,7 @@
#include "gm.h"
#include "SkLightingImageFilter.h"
#include "SkOffsetImageFilter.h"
+#include "SkPoint3.h"
#define WIDTH 330
#define HEIGHT 660
@@ -69,14 +70,18 @@ protected:
canvas->restore();
}
}
- SkPoint3 pointLocation(0, 0, SkIntToScalar(10));
+ SkPoint3 pointLocation = SkPoint3::Make(0, 0, SkIntToScalar(10));
SkScalar azimuthRad = SkDegreesToRadians(SkIntToScalar(225));
SkScalar elevationRad = SkDegreesToRadians(SkIntToScalar(5));
- SkPoint3 distantDirection(SkScalarMul(SkScalarCos(azimuthRad), SkScalarCos(elevationRad)),
- SkScalarMul(SkScalarSin(azimuthRad), SkScalarCos(elevationRad)),
- SkScalarSin(elevationRad));
- SkPoint3 spotLocation(SkIntToScalar(-10), SkIntToScalar(-10), SkIntToScalar(20));
- SkPoint3 spotTarget(SkIntToScalar(40), SkIntToScalar(40), 0);
+ SkPoint3 distantDirection = SkPoint3::Make(SkScalarMul(SkScalarCos(azimuthRad),
+ SkScalarCos(elevationRad)),
+ SkScalarMul(SkScalarSin(azimuthRad),
+ SkScalarCos(elevationRad)),
+ SkScalarSin(elevationRad));
+ SkPoint3 spotLocation = SkPoint3::Make(SkIntToScalar(-10),
+ SkIntToScalar(-10),
+ SkIntToScalar(20));
+ SkPoint3 spotTarget = SkPoint3::Make(SkIntToScalar(40), SkIntToScalar(40), 0);
SkScalar spotExponent = SK_Scalar1;
SkScalar cutoffAngle = SkIntToScalar(15);
SkScalar kd = SkIntToScalar(2);
diff --git a/gyp/effects.gypi b/gyp/effects.gypi
index edba3c726c..e0ed2c43da 100644
--- a/gyp/effects.gypi
+++ b/gyp/effects.gypi
@@ -55,6 +55,7 @@
'<(skia_src_path)/effects/SkPerlinNoiseShader.cpp',
'<(skia_src_path)/effects/SkPictureImageFilter.cpp',
'<(skia_src_path)/effects/SkPixelXorXfermode.cpp',
+ '<(skia_src_path)/effects/SkPoint3.cpp',
'<(skia_src_path)/effects/SkRectShaderImageFilter.cpp',
'<(skia_src_path)/effects/SkTableColorFilter.cpp',
'<(skia_src_path)/effects/SkTableMaskFilter.cpp',
@@ -82,7 +83,6 @@
'<(skia_include_path)/effects/Sk1DPathEffect.h',
'<(skia_include_path)/effects/Sk2DPathEffect.h',
- '<(skia_include_path)/effects/SkXfermodeImageFilter.h',
'<(skia_include_path)/effects/SkAlphaThresholdFilter.h',
'<(skia_include_path)/effects/SkArithmeticMode.h',
'<(skia_include_path)/effects/SkBitmapSource.h',
@@ -106,15 +106,17 @@
'<(skia_include_path)/effects/SkLerpXfermode.h',
'<(skia_include_path)/effects/SkLightingImageFilter.h',
'<(skia_include_path)/effects/SkLumaColorFilter.h',
- '<(skia_include_path)/effects/SkOffsetImageFilter.h',
+ '<(skia_include_path)/effects/SkMagnifierImageFilter.h',
'<(skia_include_path)/effects/SkMorphologyImageFilter.h',
+ '<(skia_include_path)/effects/SkOffsetImageFilter.h',
'<(skia_include_path)/effects/SkPaintFlagsDrawFilter.h',
'<(skia_include_path)/effects/SkPerlinNoiseShader.h',
'<(skia_include_path)/effects/SkPixelXorXfermode.h',
+ '<(skia_include_path)/effects/SkPoint3.h',
'<(skia_include_path)/effects/SkRectShaderImageFilter.h',
'<(skia_include_path)/effects/SkTableColorFilter.h',
'<(skia_include_path)/effects/SkTableMaskFilter.h',
'<(skia_include_path)/effects/SkTileImageFilter.h',
- '<(skia_include_path)/effects/SkMagnifierImageFilter.h',
+ '<(skia_include_path)/effects/SkXfermodeImageFilter.h',
],
}
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index a148a83a01..a1f323c88e 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -14,6 +14,7 @@
#
'skia_for_chromium_defines': [
'SK_IGNORE_LINEONLY_AA_CONVEX_PATH_OPTS',
+ 'SK_LEGACY_SKPOINT3_CTORS',
],
},
}
diff --git a/include/effects/SkLightingImageFilter.h b/include/effects/SkLightingImageFilter.h
index e5048eeac7..326e7b8967 100644
--- a/include/effects/SkLightingImageFilter.h
+++ b/include/effects/SkLightingImageFilter.h
@@ -11,35 +11,12 @@
#include "SkImageFilter.h"
#include "SkColor.h"
-class SK_API SkPoint3 {
-public:
- SkPoint3() {}
- SkPoint3(SkScalar x, SkScalar y, SkScalar z)
- : fX(x), fY(y), fZ(z) {}
- SkScalar dot(const SkPoint3& other) const {
- return fX * other.fX + fY * other.fY + fZ * other.fZ;
- }
- SkScalar maxComponent() const {
- return fX > fY ? (fX > fZ ? fX : fZ) : (fY > fZ ? fY : fZ);
- }
- void normalize() {
- // Small epsilon is added to prevent division by 0.
- SkScalar scale = SkScalarInvert(SkScalarSqrt(dot(*this)) + SK_ScalarNearlyZero);
- fX = fX * scale;
- fY = fY * scale;
- fZ = fZ * scale;
- }
- SkPoint3 operator*(SkScalar scalar) const {
- return SkPoint3(fX * scalar, fY * scalar, fZ * scalar);
- }
- SkPoint3 operator-(const SkPoint3& other) const {
- return SkPoint3(fX - other.fX, fY - other.fY, fZ - other.fZ);
- }
- bool operator==(const SkPoint3& other) const {
- return fX == other.fX && fY == other.fY && fZ == other.fZ;
- }
- SkScalar fX, fY, fZ;
-};
+#ifdef SK_LEGACY_SKPOINT3_CTORS
+// TODO: remove this. Chromium relies on having this included here
+#include "SkPoint3.h"
+#else
+struct SkPoint3;
+#endif
class SkLight;
diff --git a/include/effects/SkPoint3.h b/include/effects/SkPoint3.h
new file mode 100644
index 0000000000..f9b727b998
--- /dev/null
+++ b/include/effects/SkPoint3.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPoint3_DEFINED
+#define SkPoint3_DEFINED
+
+#include "SkScalar.h"
+
+struct SK_API SkPoint3 {
+ SkScalar fX, fY, fZ;
+
+#ifdef SK_LEGACY_SKPOINT3_CTORS
+ // TODO: remove these - they are needed for Chromium staging
+ SkPoint3() {}
+ SkPoint3(SkScalar x, SkScalar y, SkScalar z) : fX(x), fY(y), fZ(z) {}
+#endif
+
+ static SkPoint3 Make(SkScalar x, SkScalar y, SkScalar z) {
+ SkPoint3 pt;
+ pt.set(x, y, z);
+ return pt;
+ }
+
+ SkScalar x() const { return fX; }
+ SkScalar y() const { return fY; }
+ SkScalar z() const { return fZ; }
+
+ void set(SkScalar x, SkScalar y, SkScalar z) { fX = x; fY = y; fZ = z; }
+
+ friend bool operator==(const SkPoint3& a, const SkPoint3& b) {
+ return a.fX == b.fX && a.fY == b.fY && a.fZ == b.fZ;
+ }
+
+ friend bool operator!=(const SkPoint3& a, const SkPoint3& b) {
+ return !(a == b);
+ }
+
+ /** Returns the Euclidian distance from (0,0,0) to (x,y,z)
+ */
+ static SkScalar Length(SkScalar x, SkScalar y, SkScalar z);
+
+ /** Return the Euclidian distance from (0,0,0) to the point
+ */
+ SkScalar length() const { return SkPoint3::Length(fX, fY, fZ); }
+
+ /** Set the point (vector) to be unit-length in the same direction as it
+ already points. If the point has a degenerate length (i.e., nearly 0)
+ then set it to (0,0,0) and return false; otherwise return true.
+ */
+ bool normalize();
+
+ /** Return a new point whose X, Y and Z coordinates are scaled.
+ */
+ SkPoint3 makeScale(SkScalar scale) const {
+ SkPoint3 p;
+ p.set(scale * fX, scale * fY, scale * fZ);
+ return p;
+ }
+
+ /** Scale the point's coordinates by scale.
+ */
+ void scale(SkScalar value) {
+ fX *= value;
+ fY *= value;
+ fZ *= value;
+ }
+
+ /** Return a new point whose X, Y and Z coordinates are the negative of the
+ original point's
+ */
+ SkPoint3 operator-() const {
+ SkPoint3 neg;
+ neg.fX = -fX;
+ neg.fY = -fY;
+ neg.fZ = -fZ;
+ return neg;
+ }
+
+ /** Returns a new point whose coordinates are the difference between
+ a and b (i.e., a - b)
+ */
+ friend SkPoint3 operator-(const SkPoint3& a, const SkPoint3& b) {
+ SkPoint3 v;
+ v.set(a.fX - b.fX, a.fY - b.fY, a.fZ - b.fZ);
+ return v;
+ }
+
+ /** Returns a new point whose coordinates are the sum of a and b (a + b)
+ */
+ friend SkPoint3 operator+(const SkPoint3& a, const SkPoint3& b) {
+ SkPoint3 v;
+ v.set(a.fX + b.fX, a.fY + b.fY, a.fZ + b.fZ);
+ return v;
+ }
+
+ /** Returns the dot product of a and b, treating them as 3D vectors
+ */
+ static SkScalar DotProduct(const SkPoint3& a, const SkPoint3& b) {
+ return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ;
+ }
+
+ SkScalar dot(const SkPoint3& vec) const {
+ return DotProduct(*this, vec);
+ }
+};
+
+typedef SkPoint3 SkVector3;
+
+#endif
diff --git a/samplecode/SampleFilterFuzz.cpp b/samplecode/SampleFilterFuzz.cpp
index 30389b600d..bae7c21a5f 100644
--- a/samplecode/SampleFilterFuzz.cpp
+++ b/samplecode/SampleFilterFuzz.cpp
@@ -26,6 +26,7 @@
#include "SkPerlinNoiseShader.h"
#include "SkPictureImageFilter.h"
#include "SkPictureRecorder.h"
+#include "SkPoint3.h"
#include "SkRandom.h"
#include "SkRectShaderImageFilter.h"
#include "SkTestImageFilters.h"
@@ -128,7 +129,7 @@ static SkDropShadowImageFilter::ShadowMode make_shadow_mode() {
}
static SkPoint3 make_point() {
- return SkPoint3(make_scalar(), make_scalar(), make_scalar(true));
+ return SkPoint3::Make(make_scalar(), make_scalar(), make_scalar(true));
}
static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() {
@@ -357,10 +358,10 @@ static SkImageFilter* make_image_filter(bool canBeNull = true) {
break;
case SPOT_LIGHT:
filter = (R(2) == 1) ?
- SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
+ SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3::Make(0, 0, 0),
make_point(), make_scalar(), make_scalar(), make_color(),
make_scalar(), make_scalar(), make_image_filter()) :
- SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
+ SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3::Make(0, 0, 0),
make_point(), make_scalar(), make_scalar(), make_color(),
make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
break;
diff --git a/samplecode/SampleLighting.cpp b/samplecode/SampleLighting.cpp
index 40e6fbb073..a002a9320f 100755
--- a/samplecode/SampleLighting.cpp
+++ b/samplecode/SampleLighting.cpp
@@ -11,6 +11,7 @@
#include "SkCanvas.h"
#include "SkErrorInternals.h"
#include "SkGr.h"
+#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkShader.h"
#include "SkWriteBuffer.h"
@@ -21,18 +22,6 @@
///////////////////////////////////////////////////////////////////////////////
-struct SkVector3 {
- SkScalar fX, fY, fZ;
-
- bool operator==(const SkVector3& other) const {
- return fX == other.fX && fY == other.fY && fZ == other.fZ;
- }
-
- bool operator!=(const SkVector3& other) const {
- return !(*this == other);
- }
-};
-
class LightingShader : public SkShader {
public:
struct Light {
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 0df6f7a76f..ae49462b5e 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -8,11 +8,10 @@
#include "SkLightingImageFilter.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"
+#include "SkPoint3.h"
#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
#include "SkTypes.h"
+#include "SkWriteBuffer.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
@@ -47,7 +46,7 @@ void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
const SkPoint3& point) {
- setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
+ setUniformPoint3(pdman, uni, point);
}
#endif
@@ -69,7 +68,7 @@ public:
const SkPoint3& lightColor) const {
SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
- SkPoint3 color(lightColor * colorScale);
+ SkPoint3 color = lightColor.makeScale(colorScale);
return SkPackARGB32(255,
SkClampMax(SkScalarRoundToInt(color.fX), 255),
SkClampMax(SkScalarRoundToInt(color.fY), 255),
@@ -79,6 +78,10 @@ private:
SkScalar fKD;
};
+static SkScalar max_component(const SkPoint3& p) {
+ return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z());
+}
+
class SpecularLightingType {
public:
SpecularLightingType(SkScalar ks, SkScalar shininess)
@@ -91,8 +94,8 @@ public:
SkScalar colorScale = SkScalarMul(fKS,
SkScalarPow(normal.dot(halfDir), fShininess));
colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
- SkPoint3 color(lightColor * colorScale);
- return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
+ SkPoint3 color = lightColor.makeScale(colorScale);
+ return SkPackARGB32(SkClampMax(SkScalarRoundToInt(max_component(color)), 255),
SkClampMax(SkScalarRoundToInt(color.fX), 255),
SkClampMax(SkScalarRoundToInt(color.fY), 255),
SkClampMax(SkScalarRoundToInt(color.fZ), 255));
@@ -107,9 +110,9 @@ inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale)
}
inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
- SkPoint3 vector(SkScalarMul(-x, surfaceScale),
- SkScalarMul(-y, surfaceScale),
- SK_Scalar1);
+ SkPoint3 vector = SkPoint3::Make(SkScalarMul(-x, surfaceScale),
+ SkScalarMul(-y, surfaceScale),
+ SK_Scalar1);
vector.normalize();
return vector;
}
@@ -712,10 +715,11 @@ public:
static SkLight* UnflattenLight(SkReadBuffer& buffer);
protected:
- SkLight(SkColor color)
- : fColor(SkIntToScalar(SkColorGetR(color)),
- SkIntToScalar(SkColorGetG(color)),
- SkIntToScalar(SkColorGetB(color))) {}
+ SkLight(SkColor color) {
+ fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)),
+ SkIntToScalar(SkColorGetG(color)),
+ SkIntToScalar(SkColorGetB(color)));
+ }
SkLight(const SkPoint3& color)
: fColor(color) {}
SkLight(SkReadBuffer& buffer) {
@@ -741,7 +745,7 @@ public:
SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
return fDirection;
};
- SkPoint3 lightColor(const SkPoint3&) const { return color(); }
+ const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
LightType type() const override { return kDistant_LightType; }
const SkPoint3& direction() const { return fDirection; }
GrGLLight* createGLLight() const override {
@@ -792,13 +796,14 @@ public:
: INHERITED(color), fLocation(location) {}
SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
- SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
- fLocation.fY - SkIntToScalar(y),
- fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
+ SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
+ fLocation.fY - SkIntToScalar(y),
+ fLocation.fZ - SkScalarMul(SkIntToScalar(z),
+ surfaceScale));
direction.normalize();
return direction;
};
- SkPoint3 lightColor(const SkPoint3&) const { return color(); }
+ const SkPoint3& lightColor(const SkPoint3&) const { return this->color(); }
LightType type() const override { return kPoint_LightType; }
const SkPoint3& location() const { return fLocation; }
GrGLLight* createGLLight() const override {
@@ -824,7 +829,9 @@ public:
// Use X scale and Y scale on Z and average the result
SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
matrix.mapVectors(&locationZ, 1);
- SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
+ SkPoint3 location = SkPoint3::Make(location2.fX,
+ location2.fY,
+ SkScalarAve(locationZ.fX, locationZ.fY));
return new SkPointLight(location, color());
}
@@ -872,12 +879,14 @@ public:
// Use X scale and Y scale on Z and average the result
SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
matrix.mapVectors(&locationZ, 1);
- SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
+ SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY,
+ SkScalarAve(locationZ.fX, locationZ.fY));
SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
matrix.mapPoints(&target2, 1);
SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
matrix.mapVectors(&targetZ, 1);
- SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
+ SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY,
+ SkScalarAve(targetZ.fX, targetZ.fY));
SkPoint3 s = target - location;
s.normalize();
return new SkSpotLight(location,
@@ -891,23 +900,24 @@ public:
}
SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
- SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
- fLocation.fY - SkIntToScalar(y),
- fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
+ SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x),
+ fLocation.fY - SkIntToScalar(y),
+ fLocation.fZ - SkScalarMul(SkIntToScalar(z),
+ surfaceScale));
direction.normalize();
return direction;
};
SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
SkScalar cosAngle = -surfaceToLight.dot(fS);
- if (cosAngle < fCosOuterConeAngle) {
- return SkPoint3(0, 0, 0);
- }
- SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
- if (cosAngle < fCosInnerConeAngle) {
- scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
- return color() * SkScalarMul(scale, fConeScale);
+ SkScalar scale = 0;
+ if (cosAngle >= fCosOuterConeAngle) {
+ scale = SkScalarPow(cosAngle, fSpecularExponent);
+ if (cosAngle < fCosInnerConeAngle) {
+ scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
+ scale *= fConeScale;
+ }
}
- return color() * scale;
+ return this->color().makeScale(scale);
}
GrGLLight* createGLLight() const override {
#if SK_SUPPORT_GPU
@@ -1386,9 +1396,9 @@ GrFragmentProcessor* SkSpecularLightingImageFilter::getFragmentProcessor(
namespace {
SkPoint3 random_point3(SkRandom* random) {
- return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
- SkScalarToFloat(random->nextSScalar1()),
- SkScalarToFloat(random->nextSScalar1()));
+ return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
+ SkScalarToFloat(random->nextSScalar1()),
+ SkScalarToFloat(random->nextSScalar1()));
}
SkLight* create_random_light(SkRandom* random) {
@@ -1883,14 +1893,13 @@ void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
"LightColor");
}
-void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
- const char *surfaceToLight) {
+void GrGLLight::emitLightColor(GrGLFPBuilder* builder, const char *surfaceToLight) {
builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
}
-void GrGLLight::setData(const GrGLProgramDataManager& pdman,
- const SkLight* light) const {
- setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
+void GrGLLight::setData(const GrGLProgramDataManager& pdman, const SkLight* light) const {
+ setUniformPoint3(pdman, fColorUni,
+ light->color().makeScale(SkScalarInvert(SkIntToScalar(255))));
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkPoint3.cpp b/src/effects/SkPoint3.cpp
new file mode 100644
index 0000000000..3b5586b067
--- /dev/null
+++ b/src/effects/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;
+}
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index dc35332593..a5ffb1b226 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -26,6 +26,7 @@
#include "SkPicture.h"
#include "SkPictureImageFilter.h"
#include "SkPictureRecorder.h"
+#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkRect.h"
#include "SkRectShaderImageFilter.h"
@@ -244,9 +245,9 @@ DEF_TEST(ImageFilter, reporter) {
{
// This tests for :
// 1 ) location at (0,0,1)
- SkPoint3 location(0, 0, SK_Scalar1);
+ SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
// 2 ) location and target at same value
- SkPoint3 target(location.fX, location.fY, location.fZ);
+ SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
// 3 ) large negative specular exponent value
SkScalar specularExponent = -1000;
@@ -277,8 +278,7 @@ static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* rep
SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
- SkPoint3 location(0, 0, SK_Scalar1);
- SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
SkScalar kernel[9] = {
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
@@ -411,8 +411,7 @@ DEF_TEST(ImageFilterDrawTiled, reporter) {
// Tests pass by not asserting.
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
- SkPoint3 location(0, 0, SK_Scalar1);
- SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
SkScalar kernel[9] = {
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
diff --git a/tests/Point3Test.cpp b/tests/Point3Test.cpp
new file mode 100644
index 0000000000..bf3b90270c
--- /dev/null
+++ b/tests/Point3Test.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Unit tests for src/core/SkPoint3.cpp and its header
+
+#include "SkPoint3.h"
+#include "Test.h"
+
+static void test_eq_ops(skiatest::Reporter* reporter) {
+ const SkPoint3 p0 = SkPoint3::Make(0, 0, 0);
+ const SkPoint3 p1 = SkPoint3::Make(1, 1, 1);
+ const SkPoint3 p2 = SkPoint3::Make(1, 1, 1);
+
+ REPORTER_ASSERT(reporter, p0 != p1);
+ REPORTER_ASSERT(reporter, p1 == p2);
+}
+
+static void test_ops(skiatest::Reporter* reporter) {
+ SkPoint3 v = SkPoint3::Make(1, 1, 1);
+ v.normalize();
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(v.length(), SK_Scalar1));
+
+ // scale
+ SkPoint3 p = v.makeScale(3.0f);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.length(), 3.0f));
+
+ p.scale(1.0f/3.0f);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.length(), SK_Scalar1));
+
+ SkPoint3 p1 = SkPoint3::Make(20.0f, 2.0f, 10.0f);
+ SkPoint3 p2 = -p1;
+
+ // -
+ p = p1 - p1;
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.x(), 0.0f));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.y(), 0.0f));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.z(), 0.0f));
+
+ // +
+ p = p1 + p2;
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.x(), 0.0f));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.y(), 0.0f));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.z(), 0.0f));
+}
+
+static void test_dot(skiatest::Reporter* reporter) {
+ const SkPoint3 xAxis = SkPoint3::Make(1.0f, 0.0f, 0.0f);
+ const SkPoint3 yAxis = SkPoint3::Make(0.0f, 1.0f, 0.0f);
+ const SkPoint3 zAxis = SkPoint3::Make(0.0f, 0.0f, 1.0f);
+
+ SkScalar dot = xAxis.dot(yAxis);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));
+
+ dot = yAxis.dot(zAxis);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));
+
+ dot = zAxis.dot(xAxis);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 0.0f));
+
+ SkPoint3 v = SkPoint3::Make(13.0f, 2.0f, 7.0f);
+ v.normalize();
+
+ dot = v.dot(v);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, 1.0f));
+
+ v = SkPoint3::Make(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2, 0.0f);
+
+ dot = xAxis.dot(v);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, SK_ScalarRoot2Over2));
+
+ dot = yAxis.dot(v);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dot, SK_ScalarRoot2Over2));
+}
+
+static void test_length(skiatest::Reporter* reporter,
+ SkScalar x, SkScalar y, SkScalar z, SkScalar expectedLen) {
+ SkPoint3 point = SkPoint3::Make(x, y, z);
+
+ SkScalar s1 = point.length();
+ SkScalar s2 = SkPoint3::Length(x, y, z);
+
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, s2));
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLen));
+}
+
+static void test_normalize(skiatest::Reporter* reporter,
+ SkScalar x, SkScalar y, SkScalar z, SkScalar expectedLen) {
+ SkPoint3 point = SkPoint3::Make(x, y, z);
+
+ bool result = point.normalize();
+ SkScalar newLength = point.length();
+
+ if (0 == expectedLen) {
+ const SkPoint3 empty = SkPoint3::Make(0.0f, 0.0f, 0.0f);
+
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, 0));
+ REPORTER_ASSERT(reporter, !result);
+ REPORTER_ASSERT(reporter, point == empty);
+ } else {
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
+ REPORTER_ASSERT(reporter, result);
+ }
+}
+
+DEF_TEST(Point3, reporter) {
+ test_eq_ops(reporter);
+ test_ops(reporter);
+ test_dot(reporter);
+
+ static const struct {
+ SkScalar fX;
+ SkScalar fY;
+ SkScalar fZ;
+ SkScalar fLength;
+ } gRec[] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.3f, 0.4f, 0.5f, SK_ScalarRoot2Over2 },
+ { 1.0e-37f, 1.0e-37f, 1.0e-37f, 0.0f }, // underflows
+ { 3.4e38f, 0.0f, 0.0f, 3.4e38f } // overflows
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ test_length(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fZ, gRec[i].fLength);
+ test_normalize(reporter, gRec[i].fX, gRec[i].fY, gRec[i].fZ, gRec[i].fLength);
+ }
+}