ce6a354e12
It turns out that the perlin implementation we inherited from WebKit does not actually generate tileable noise (see Chromium bug http://crbug.com/383495). The main problem is that when generating coordinates for gradient interpolation, it was attempting to wrap both x and (x + 1) simultaneously at the tile boundary (that is, either both or neither are wrapped). This obviously won't work, since along the tile seams, (x + 1) should be wrapped, but x should not. The same is true in y. This patch fixes both the CPU and GPU paths, renames some variables to more closely match the spec, and modifies the perlin noise GM to actually test tiling. (Note that the clipping the GM was doing was removed, since it's superfluous: it used to be necessary for image filters, but isn't anymore, and this isn't an image filter GM anyway.) R=sugoi@google.com, sugoi TBR=senorblanco Author: senorblanco@chromium.org Review URL: https://codereview.chromium.org/332523006
181 lines
5.9 KiB
C++
181 lines
5.9 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "gm.h"
|
|
#include "SkPerlinNoiseShader.h"
|
|
|
|
class PerlinNoiseGM : public skiagm::GM {
|
|
public:
|
|
PerlinNoiseGM() {
|
|
this->setBGColor(0xFF000000);
|
|
fSize = SkISize::Make(80, 80);
|
|
}
|
|
|
|
protected:
|
|
virtual SkString onShortName() {
|
|
return SkString("perlinnoise");
|
|
}
|
|
|
|
virtual SkISize onISize() {
|
|
return SkISize::Make(200, 500);
|
|
}
|
|
|
|
void drawRect(SkCanvas* canvas, int x, int y, const SkPaint& paint, const SkISize& size) {
|
|
canvas->save();
|
|
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
|
|
SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
|
|
SkIntToScalar(size.height()));
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
}
|
|
|
|
void test(SkCanvas* canvas, int x, int y, SkPerlinNoiseShader::Type type,
|
|
float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed,
|
|
bool stitchTiles) {
|
|
SkISize tileSize = SkISize::Make(fSize.width() / 2, fSize.height() / 2);
|
|
SkShader* shader = (type == SkPerlinNoiseShader::kFractalNoise_Type) ?
|
|
SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves,
|
|
seed, stitchTiles ? &tileSize : NULL) :
|
|
SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves,
|
|
seed, stitchTiles ? &tileSize : NULL);
|
|
SkPaint paint;
|
|
paint.setShader(shader)->unref();
|
|
if (stitchTiles) {
|
|
drawRect(canvas, x, y, paint, tileSize);
|
|
x += tileSize.width();
|
|
drawRect(canvas, x, y, paint, tileSize);
|
|
y += tileSize.width();
|
|
drawRect(canvas, x, y, paint, tileSize);
|
|
x -= tileSize.width();
|
|
drawRect(canvas, x, y, paint, tileSize);
|
|
} else {
|
|
drawRect(canvas, x, y, paint, fSize);
|
|
}
|
|
}
|
|
|
|
virtual void onDraw(SkCanvas* canvas) {
|
|
canvas->clear(0x00000000);
|
|
test(canvas, 0, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.1f, 0, 0, false);
|
|
test(canvas, 100, 0, SkPerlinNoiseShader::kTurbulence_Type,
|
|
0.1f, 0.1f, 0, 0, false);
|
|
|
|
test(canvas, 0, 100, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.1f, 2, 0, false);
|
|
test(canvas, 100, 100, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.05f, 0.1f, 1, 0, true);
|
|
|
|
test(canvas, 0, 200, SkPerlinNoiseShader::kTurbulence_Type,
|
|
0.1f, 0.1f, 1, 0, true);
|
|
test(canvas, 100, 200, SkPerlinNoiseShader::kTurbulence_Type,
|
|
0.2f, 0.4f, 5, 0, false);
|
|
|
|
test(canvas, 0, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.1f, 3, 1, false);
|
|
test(canvas, 100, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.1f, 3, 4, false);
|
|
|
|
canvas->scale(0.75f, 1.0f);
|
|
|
|
test(canvas, 0, 400, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.1f, 2, 0, false);
|
|
test(canvas, 100, 400, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
0.1f, 0.05f, 1, 0, true);
|
|
}
|
|
|
|
private:
|
|
typedef GM INHERITED;
|
|
SkISize fSize;
|
|
};
|
|
|
|
class PerlinNoiseGM2 : public skiagm::GM {
|
|
public:
|
|
PerlinNoiseGM2() {
|
|
fSize = SkISize::Make(80, 80);
|
|
}
|
|
|
|
protected:
|
|
virtual SkString onShortName() {
|
|
return SkString("perlinnoise_localmatrix");
|
|
}
|
|
|
|
virtual SkISize onISize() {
|
|
return SkISize::Make(640, 480);
|
|
}
|
|
|
|
void install(SkPaint* paint, SkPerlinNoiseShader::Type type,
|
|
float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed,
|
|
bool stitchTiles) {
|
|
SkShader* shader = (type == SkPerlinNoiseShader::kFractalNoise_Type) ?
|
|
SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves,
|
|
seed, stitchTiles ? &fSize : NULL) :
|
|
SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves,
|
|
seed, stitchTiles ? &fSize : NULL);
|
|
paint->setShader(shader)->unref();
|
|
}
|
|
|
|
virtual void onDraw(SkCanvas* canvas) {
|
|
canvas->translate(10, 10);
|
|
|
|
SkPaint paint;
|
|
install(&paint, SkPerlinNoiseShader::kFractalNoise_Type, 0.1f, 0.1f, 2, 0, false);
|
|
|
|
const SkScalar w = SkIntToScalar(fSize.width());
|
|
const SkScalar h = SkIntToScalar(fSize.height());
|
|
|
|
SkRect r = SkRect::MakeWH(w, h);
|
|
canvas->drawRect(r, paint);
|
|
|
|
canvas->save();
|
|
canvas->translate(w * 5/4, 0);
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
|
|
canvas->save();
|
|
canvas->translate(0, h + 10);
|
|
canvas->scale(2, 2);
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
|
|
canvas->save();
|
|
canvas->translate(w + 100, h + 10);
|
|
canvas->scale(2, 2);
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
|
|
// The next row should draw the same as the previous, even though we are using a local
|
|
// matrix instead of the canvas.
|
|
|
|
canvas->translate(0, h * 2 + 10);
|
|
|
|
SkMatrix lm;
|
|
lm.setScale(2, 2);
|
|
paint.setShader(SkShader::CreateLocalMatrixShader(paint.getShader(), lm))->unref();
|
|
r.fRight += r.width();
|
|
r.fBottom += r.height();
|
|
|
|
canvas->save();
|
|
canvas->translate(0, h + 10);
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
|
|
canvas->save();
|
|
canvas->translate(w + 100, h + 10);
|
|
canvas->drawRect(r, paint);
|
|
canvas->restore();
|
|
}
|
|
|
|
private:
|
|
typedef GM INHERITED;
|
|
SkISize fSize;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_GM( return new PerlinNoiseGM; )
|
|
DEF_GM( return new PerlinNoiseGM2; )
|