Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  SkPerlinNoiseShaderImpl.h   Sprache: 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.
 */

#ifndef SkPerlinNoiseShaderImpl_DEFINED
#define SkPerlinNoiseShaderImpl_DEFINED

#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkColorType.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkOnce.h"
#include "src/shaders/SkShaderBase.h"

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <memory>

class SkReadBuffer;
enum class SkPerlinNoiseShaderType;
struct SkStageRec;
class SkWriteBuffer;

class SkPerlinNoiseShader : public SkShaderBase {
private:
    static constexpr int kBlockSize = 256;
    static constexpr int kBlockMask = kBlockSize - 1;
    static constexpr int kPerlinNoise = 4096;
    static constexpr int kRandMaximum = SK_MaxS32;  // 2**31 - 1

public:
    struct StitchData {
        StitchData() = default;

        StitchData(SkScalar w, SkScalar h)
                : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
                , fWrapX(kPerlinNoise + fWidth)
                , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
                , fWrapY(kPerlinNoise + fHeight) {}

        bool operator==(const StitchData& other) const {
            return fWidth == other.fWidth && fWrapX == other.fWrapX && fHeight == other.fHeight &&
                   fWrapY == other.fWrapY;
        }

        int fWidth = 0;  // How much to subtract to wrap for stitching.
        int fWrapX = 0;  // Minimum value to wrap.
        int fHeight = 0;
        int fWrapY = 0;
    };

    struct PaintingData {
        PaintingData(const SkISize& tileSize,
                     SkScalar seed,
                     SkScalar baseFrequencyX,
                     SkScalar baseFrequencyY) {
            fBaseFrequency.set(baseFrequencyX, baseFrequencyY);
            fTileSize.set(SkScalarRoundToInt(tileSize.fWidth),
                          SkScalarRoundToInt(tileSize.fHeight));
            this->init(seed);
            if (!fTileSize.isEmpty()) {
                this->stitch();
            }
        }

        void generateBitmaps() {
            SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
            fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
            fPermutationsBitmap.setImmutable();

            info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
            fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
            fNoiseBitmap.setImmutable();
        }

        PaintingData(const PaintingData& that)
                : fSeed(that.fSeed)
                , fTileSize(that.fTileSize)
                , fBaseFrequency(that.fBaseFrequency)
                , fStitchDataInit(that.fStitchDataInit)
                , fPermutationsBitmap(that.fPermutationsBitmap)
                , fNoiseBitmap(that.fNoiseBitmap) {
            memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
            memcpy(fNoise, that.fNoise, sizeof(fNoise));
        }

        int fSeed;
        uint8_t fLatticeSelector[kBlockSize];
        uint16_t fNoise[4][kBlockSize][2];
        SkISize fTileSize;
        SkVector fBaseFrequency;
        StitchData fStitchDataInit;

    private:
        SkBitmap fPermutationsBitmap;
        SkBitmap fNoiseBitmap;

        int random() {
            // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
            // m = kRandMaximum, 2**31 - 1 (2147483647)
            static constexpr int kRandAmplitude = 16807;  // 7**5; primitive root of m
            static constexpr int kRandQ = 127773;         // m / a
            static constexpr int kRandR = 2836;           // m % a

            int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
            if (result <= 0) {
                result += kRandMaximum;
            }
            fSeed = result;
            return result;
        }

        // Only called once. Could be part of the constructor.
        void init(SkScalar seed) {
            // According to the SVG spec, we must truncate (not round) the seed value.
            fSeed = SkScalarTruncToInt(seed);
            // The seed value clamp to the range [1, kRandMaximum - 1].
            if (fSeed <= 0) {
                fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
            }
            if (fSeed > kRandMaximum - 1) {
                fSeed = kRandMaximum - 1;
            }
            for (int channel = 0; channel < 4; ++channel) {
                for (int i = 0; i < kBlockSize; ++i) {
                    fLatticeSelector[i] = i;
                    fNoise[channel][i][0] = (random() % (2 * kBlockSize));
                    fNoise[channel][i][1] = (random() % (2 * kBlockSize));
                }
            }
            for (int i = kBlockSize - 1; i > 0; --i) {
                int k = fLatticeSelector[i];
                int j = random() % kBlockSize;
                SkASSERT(j >= 0);
                SkASSERT(j < kBlockSize);
                fLatticeSelector[i] = fLatticeSelector[j];
                fLatticeSelector[j] = k;
            }

            // Perform the permutations now
            {
                // Copy noise data
                uint16_t noise[4][kBlockSize][2];
                for (int i = 0; i < kBlockSize; ++i) {
                    for (int channel = 0; channel < 4; ++channel) {
                        for (int j = 0; j < 2; ++j) {
                            noise[channel][i][j] = fNoise[channel][i][j];
                        }
                    }
                }
                // Do permutations on noise data
                for (int i = 0; i < kBlockSize; ++i) {
                    for (int channel = 0; channel < 4; ++channel) {
                        for (int j = 0; j < 2; ++j) {
                            fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
                        }
                    }
                }
            }

            // Half of the largest possible value for 16 bit unsigned int
            static constexpr SkScalar kHalfMax16bits = 32767.5f;

            // Compute gradients from permuted noise data
            static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
            for (int channel = 0; channel < 4; ++channel) {
                for (int i = 0; i < kBlockSize; ++i) {
                    SkPoint gradient =
                            SkPoint::Make((fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
                                          (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
                    gradient.normalize();
                    // Put the normalized gradient back into the noise data
                    fNoise[channel][i][0] = SkScalarRoundToInt((gradient.fX + 1) * kHalfMax16bits);
                    fNoise[channel][i][1] = SkScalarRoundToInt((gradient.fY + 1) * kHalfMax16bits);
                }
            }
        }

        // Only called once. Could be part of the constructor.
        void stitch() {
            SkScalar tileWidth = SkIntToScalar(fTileSize.width());
            SkScalar tileHeight = SkIntToScalar(fTileSize.height());
            SkASSERT(tileWidth > 0 && tileHeight > 0);
            // When stitching tiled turbulence, the frequencies must be adjusted
            // so that the tile borders will be continuous.
            if (fBaseFrequency.fX) {
                SkScalar lowFrequencx =
                        SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
                SkScalar highFrequencx =
                        SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
                // BaseFrequency should be non-negative according to the standard.
                // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
                if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) <
                    highFrequencx / fBaseFrequency.fX) {
                    fBaseFrequency.fX = lowFrequencx;
                } else {
                    fBaseFrequency.fX = highFrequencx;
                }
            }
            if (fBaseFrequency.fY) {
                SkScalar lowFrequency =
                        SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
                SkScalar highFrequency =
                        SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
                // lowFrequency can be 0 if fBaseFrequency.fY is very small.
                if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) <
                    highFrequency / fBaseFrequency.fY) {
                    fBaseFrequency.fY = lowFrequency;
                } else {
                    fBaseFrequency.fY = highFrequency;
                }
            }
            fStitchDataInit =
                    StitchData(tileWidth * fBaseFrequency.fX, tileHeight * fBaseFrequency.fY);
        }

    public:
        const SkBitmap& getPermutationsBitmap() const {
            SkASSERT(!fPermutationsBitmap.drawsNothing());
            return fPermutationsBitmap;
        }
        const SkBitmap& getNoiseBitmap() const {
            SkASSERT(!fNoiseBitmap.drawsNothing());
            return fNoiseBitmap;
        }
    };  // struct PaintingData

    static const int kMaxOctaves = 255;  // numOctaves must be <= 0 and <= kMaxOctaves

    SkPerlinNoiseShader(SkPerlinNoiseShaderType type,
                        SkScalar baseFrequencyX,
                        SkScalar baseFrequencyY,
                        int numOctaves,
                        SkScalar seed,
                        const SkISize* tileSize);

    ShaderType type() const override { return ShaderType::kPerlinNoise; }

    SkPerlinNoiseShaderType noiseType() const { return fType; }
    int numOctaves() const { return fNumOctaves; }
    bool stitchTiles() const { return fStitchTiles; }
    SkISize tileSize() const { return fTileSize; }

    std::unique_ptr<PaintingData> getPaintingData() const {
        return std::make_unique<PaintingData>(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY);
    }

    bool appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const override;

protected:
    void flatten(SkWriteBuffer&) const override;

private:
    SK_FLATTENABLE_HOOKS(SkPerlinNoiseShader)

    const SkPerlinNoiseShaderType fType;
    const SkScalar fBaseFrequencyX;
    const SkScalar fBaseFrequencyY;
    const int fNumOctaves;
    const SkScalar fSeed;
    const SkISize fTileSize;
    const bool fStitchTiles;

    mutable SkOnce fInitPaintingDataOnce;
    std::unique_ptr<PaintingData> fPaintingData;

    friend void SkRegisterPerlinNoiseShaderFlattenable();
};

#endif

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.0 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge