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