diff options
author | robertphillips <robertphillips@google.com> | 2015-07-13 13:16:44 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-13 13:16:44 -0700 |
commit | 3d32d768cd8b66c49c070495c08f7933b9dd2423 (patch) | |
tree | 6676e917988dcecc00b5f33f5e33a4e7c2849344 | |
parent | 52e7657cd850f95e66eb23c6d138ee45149a1039 (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.cpp | 107 | ||||
-rw-r--r-- | gm/imagefiltersscaled.cpp | 9 | ||||
-rw-r--r-- | gm/lighting.cpp | 17 | ||||
-rw-r--r-- | gyp/effects.gypi | 8 | ||||
-rw-r--r-- | gyp/skia_for_chromium_defines.gypi | 1 | ||||
-rw-r--r-- | include/effects/SkLightingImageFilter.h | 35 | ||||
-rw-r--r-- | include/effects/SkPoint3.h | 113 | ||||
-rw-r--r-- | samplecode/SampleFilterFuzz.cpp | 7 | ||||
-rwxr-xr-x | samplecode/SampleLighting.cpp | 13 | ||||
-rw-r--r-- | src/effects/SkLightingImageFilter.cpp | 91 | ||||
-rw-r--r-- | src/effects/SkPoint3.cpp | 80 | ||||
-rw-r--r-- | tests/ImageFilterTest.cpp | 11 | ||||
-rw-r--r-- | tests/Point3Test.cpp | 130 |
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); + } +} |