1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/core/SkCanvas.h"
9#include "include/core/SkFont.h"
10#include "include/core/SkPaint.h"
11#include "include/utils/SkRandom.h"
12#include "samplecode/Sample.h"
13#include "src/utils/SkUTF.h"
14#if SK_SUPPORT_GPU
15#include "src/gpu/GrRectanizerPow2.h"
16#include "src/gpu/GrRectanizerSkyline.h"
17
18// This slide visualizes the various GrRectanizer-derived classes behavior
19// for various input sets
20//  'j' will cycle through the various rectanizers
21//          Pow2 -> GrRectanizerPow2
22//          Skyline -> GrRectanizerSkyline
23//  'h' will cycle through the various rect sets
24//          Rand -> random rects from 2-256
25//          Pow2Rand -> random power of 2 sized rects from 2-256
26//          SmallPow2 -> 128x128 rects
27class RectanizerView : public Sample {
28public:
29    RectanizerView()
30        : fCurRandRect(0)
31        , fCurRectanizer(0) {
32        for (int i = 0; i < 3; ++i) {
33           fRects[i].setReserve(kNumRandRects);
34        }
35        fRectLocations.setReserve(kNumRandRects);
36
37        SkRandom random;
38        for (int i = 0; i < kNumRandRects; ++i) {
39            *fRects[0].append() = SkISize::Make(random.nextRangeU(kMinRectSize, kMaxRectSize),
40                                                random.nextRangeU(kMinRectSize, kMaxRectSize));
41            *fRects[1].append() = SkISize::Make(
42                        GrNextPow2(random.nextRangeU(kMinRectSize, kMaxRectSize)),
43                        GrNextPow2(random.nextRangeU(kMinRectSize, kMaxRectSize)));
44            *fRects[2].append() = SkISize::Make(128, 128);
45            *fRectLocations.append() = SkIPoint16::Make(0, 0);
46        }
47
48        fCurRects = &fRects[0];
49
50        fRectanizers.push_back(
51            std::unique_ptr<GrRectanizer>(new GrRectanizerPow2(kWidth, kHeight)));
52        fRectanizers.push_back(
53            std::unique_ptr<GrRectanizer>(new GrRectanizerSkyline(kWidth, kHeight)));
54    }
55
56protected:
57    SkString name() override { return SkString("Rectanizer"); }
58
59    bool onChar(SkUnichar uni) override {
60            char utf8[SkUTF::kMaxBytesInUTF8Sequence];
61            size_t size = SkUTF::ToUTF8(uni, utf8);
62            // Only consider events for single char keys
63            if (1 == size) {
64                switch (utf8[0]) {
65                case kCycleRectanizerKey:
66                    this->cycleRectanizer();
67                    return true;
68                case kCycleRectsKey:
69                    this->cycleRects();
70                    return true;
71                default:
72                    break;
73                }
74            }
75            return false;
76    }
77
78    void onDrawContent(SkCanvas* canvas) override {
79        if (fCurRandRect < kNumRandRects) {
80            if (fRectanizers[fCurRectanizer]->addRect((*fCurRects)[fCurRandRect].fWidth,
81                                                      (*fCurRects)[fCurRandRect].fHeight,
82                                                      &fRectLocations[fCurRandRect])) {
83                ++fCurRandRect;
84            }
85        }
86
87        SkFont blackBigFont;
88        blackBigFont.setSize(20);
89        SkPaint blackStroke;
90        blackStroke.setStyle(SkPaint::kStroke_Style);
91        SkPaint redFill;
92        redFill.setColor(SK_ColorRED);
93
94        SkRect r = SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight));
95
96        canvas->clear(SK_ColorWHITE);
97        canvas->drawRect(r, blackStroke);
98
99        long totArea = 0;
100        for (int i = 0; i < fCurRandRect; ++i) {
101            r = SkRect::MakeXYWH(SkIntToScalar(fRectLocations[i].fX),
102                                 SkIntToScalar(fRectLocations[i].fY),
103                                 SkIntToScalar((*fCurRects)[i].fWidth),
104                                 SkIntToScalar((*fCurRects)[i].fHeight));
105            canvas->drawRect(r, redFill);
106            canvas->drawRect(r, blackStroke);
107            totArea += (*fCurRects)[i].fWidth * (*fCurRects)[i].fHeight;
108        }
109
110        SkString str;
111
112        str.printf("%s-%s: tot Area: %ld %%full: %.2f (%.2f) numTextures: %d/%d",
113                   this->getRectanizerName(),
114                   this->getRectsName(),
115                   totArea,
116                   100.0f * fRectanizers[fCurRectanizer]->percentFull(),
117                   100.0f * totArea / ((float)kWidth*kHeight),
118                   fCurRandRect,
119                   kNumRandRects);
120        canvas->drawString(str, 50, kHeight + 50, blackBigFont, SkPaint());
121
122        str.printf("Press \'j\' to toggle rectanizer");
123        canvas->drawString(str, 50, kHeight + 100, blackBigFont, SkPaint());
124
125        str.printf("Press \'h\' to toggle rects");
126        canvas->drawString(str, 50, kHeight + 150, blackBigFont, SkPaint());
127    }
128
129private:
130    static const int kWidth = 1024;
131    static const int kHeight = 1024;
132    static const int kNumRandRects = 200;
133    static const char kCycleRectanizerKey = 'j';
134    static const char kCycleRectsKey = 'h';
135    static const int kMinRectSize = 2;
136    static const int kMaxRectSize = 256;
137
138    int                                     fCurRandRect;
139    SkTDArray<SkISize>                      fRects[3];
140    SkTDArray<SkISize>*                     fCurRects;
141    SkTDArray<SkIPoint16>                   fRectLocations;
142    SkTArray<std::unique_ptr<GrRectanizer>> fRectanizers;
143    int                                     fCurRectanizer;
144
145    const char* getRectanizerName() const {
146        if (!fCurRectanizer) {
147            return "Pow2";
148        } else {
149            return "Skyline";
150        }
151    }
152
153    void cycleRectanizer() {
154        fCurRectanizer = (fCurRectanizer + 1) % fRectanizers.count();
155
156        fRectanizers[fCurRectanizer]->reset();
157        fCurRandRect = 0;
158    }
159
160    const char* getRectsName() const {
161        if (fCurRects == &fRects[0]) {
162            return "Rand";
163        } else if (fCurRects == &fRects[1]) {
164            return "Pow2Rand";
165        } else {
166            return "SmallPow2";
167        }
168    }
169
170    void cycleRects() {
171        if (fCurRects == &fRects[0]) {
172            fCurRects = &fRects[1];
173        } else if (fCurRects == &fRects[1]) {
174            fCurRects = &fRects[2];
175        } else {
176            fCurRects = &fRects[0];
177        }
178
179        fRectanizers[fCurRectanizer]->reset();
180        fCurRandRect = 0;
181    }
182
183    using INHERITED = Sample;
184};
185
186//////////////////////////////////////////////////////////////////////////////
187
188DEF_SAMPLE( return new RectanizerView(); )
189
190#endif
191