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
25 class RectanizerView : public SampleView {
26 public:
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 
54 protected:
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 
132 private:
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 //////////////////////////////////////////////////////////////////////////////
190 static SkView* MyFactory() { return new RectanizerView; }
191 static SkViewRegister reg(MyFactory);
192 
193 #endif
194