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