• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 
9 #include "GrContext.h"
10 #include "SDL.h"
11 #include "SkCanvas.h"
12 #include "SkRandom.h"
13 #include "SkSurface.h"
14 
15 #include "gl/GrGLInterface.h"
16 #include "gl/GrGLUtil.h"
17 
18 #if defined(SK_BUILD_FOR_ANDROID)
19 #include <GLES/gl.h>
20 #elif defined(SK_BUILD_FOR_UNIX)
21 #include <GL/gl.h>
22 #elif defined(SK_BUILD_FOR_MAC)
23 #include <gl.h>
24 #endif
25 
26 /*
27  * This application is a simple example of how to combine SDL and Skia it demonstrates:
28  *   how to setup gpu rendering to the main window
29  *   how to perform cpu-side rendering and draw the result to the gpu-backed screen
30  *   draw simple primitives (rectangles)
31  *   draw more complex primitives (star)
32  */
33 
34 struct ApplicationState {
ApplicationStateApplicationState35     ApplicationState() : fQuit(false) {}
36     // Storage for the user created rectangles. The last one may still be being edited.
37     SkTArray<SkRect> fRects;
38     bool fQuit;
39 };
40 
handle_error()41 static void handle_error() {
42     const char* error = SDL_GetError();
43     SkDebugf("SDL Error: %s\n", error);
44     SDL_ClearError();
45 }
46 
handle_events(ApplicationState * state,SkCanvas * canvas)47 static void handle_events(ApplicationState* state, SkCanvas* canvas) {
48     SDL_Event event;
49     while(SDL_PollEvent(&event)) {
50         switch (event.type) {
51             case SDL_MOUSEMOTION:
52                 if (event.motion.state == SDL_PRESSED) {
53                     SkRect& rect = state->fRects.back();
54                     rect.fRight = event.motion.x;
55                     rect.fBottom = event.motion.y;
56                 }
57                 break;
58             case SDL_MOUSEBUTTONDOWN:
59                 if (event.button.state == SDL_PRESSED) {
60                     state->fRects.push_back() = SkRect::MakeLTRB(SkIntToScalar(event.button.x),
61                                                                  SkIntToScalar(event.button.y),
62                                                                  SkIntToScalar(event.button.x),
63                                                                  SkIntToScalar(event.button.y));
64                 }
65                 break;
66             case SDL_KEYDOWN: {
67                 SDL_Keycode key = event.key.keysym.sym;
68                 if (key == SDLK_ESCAPE) {
69                     state->fQuit = true;
70                 }
71                 break;
72             }
73             case SDL_QUIT:
74                 state->fQuit = true;
75                 break;
76             default:
77                 break;
78         }
79     }
80 }
81 
82 // Creates a star type shape using a SkPath
create_star()83 static SkPath create_star() {
84     static const int kNumPoints = 5;
85     SkPath concavePath;
86     SkPoint points[kNumPoints] = {{0, SkIntToScalar(-50)} };
87     SkMatrix rot;
88     rot.setRotate(SkIntToScalar(360) / kNumPoints);
89     for (int i = 1; i < kNumPoints; ++i) {
90         rot.mapPoints(points + i, points + i - 1, 1);
91     }
92     concavePath.moveTo(points[0]);
93     for (int i = 0; i < kNumPoints; ++i) {
94         concavePath.lineTo(points[(2 * i) % kNumPoints]);
95     }
96     concavePath.setFillType(SkPath::kEvenOdd_FillType);
97     SkASSERT(!concavePath.isConvex());
98     concavePath.close();
99     return concavePath;
100 }
101 
102 #if defined(SK_BUILD_FOR_ANDROID)
SDL_main(int argc,char ** argv)103 int SDL_main(int argc, char** argv) {
104 #else
105 int main(int argc, char** argv) {
106 #endif
107     uint32_t windowFlags = 0;
108 
109     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
110     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
111 
112     SDL_GLContext glContext = nullptr;
113 #if defined(SK_BUILD_FOR_ANDROID)
114     // For Android we need to set up for OpenGL ES and we make the window hi res & full screen
115     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
116     windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE |
117                   SDL_WINDOW_BORDERLESS | SDL_WINDOW_FULLSCREEN_DESKTOP |
118                   SDL_WINDOW_ALLOW_HIGHDPI;
119 #else
120     // For all other clients we use the core profile and operate in a window
121     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
122 
123     windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
124 #endif
125     static const int kStencilBits = 8;  // Skia needs 8 stencil bits
126     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
127     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
128     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
129     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
130     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
131     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, kStencilBits);
132 
133     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
134 
135     // If you want multisampling, uncomment the below lines and set a sample count
136     static const int kMsaaSampleCount = 0; //4;
137     // SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
138     // SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, kMsaaSampleCount);
139 
140     /*
141      * In a real application you might want to initialize more subsystems
142      */
143     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
144         handle_error();
145         return 1;
146     }
147 
148     // Setup window
149     // This code will create a window with the same resolution as the user's desktop.
150     SDL_DisplayMode dm;
151     if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
152         handle_error();
153         return 1;
154     }
155 
156     SDL_Window* window = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED,
157                                           SDL_WINDOWPOS_CENTERED, dm.w, dm.h, windowFlags);
158 
159     if (!window) {
160         handle_error();
161         return 1;
162     }
163 
164     // To go fullscreen
165     // SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
166 
167     // try and setup a GL context
168     glContext = SDL_GL_CreateContext(window);
169     if (!glContext) {
170         handle_error();
171         return 1;
172     }
173 
174     int success =  SDL_GL_MakeCurrent(window, glContext);
175     if (success != 0) {
176         handle_error();
177         return success;
178     }
179 
180     glViewport(0, 0, dm.w, dm.h);
181     glClearColor(1, 1, 1, 1);
182     glClearStencil(0);
183     glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
184 
185     // setup GrContext
186     SkAutoTUnref<const GrGLInterface> interface(GrGLCreateNativeInterface());
187 
188     // To use NVPR, comment this out
189     interface.reset(GrGLInterfaceRemoveNVPR(interface));
190     SkASSERT(interface);
191 
192     // setup contexts
193     SkAutoTUnref<GrContext> grContext(GrContext::Create(kOpenGL_GrBackend,
194                                                         (GrBackendContext)interface.get()));
195     SkASSERT(grContext);
196 
197     // Wrap the frame buffer object attached to the screen in a Skia render target so Skia can
198     // render to it
199     GrBackendRenderTargetDesc desc;
200     desc.fWidth = dm.w;
201     desc.fHeight = dm.h;
202     desc.fConfig = kSkia8888_GrPixelConfig;
203     desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
204     desc.fSampleCnt = kMsaaSampleCount;
205     desc.fStencilBits = kStencilBits;
206     GrGLint buffer;
207     GR_GL_GetIntegerv(interface, GR_GL_FRAMEBUFFER_BINDING, &buffer);
208     desc.fRenderTargetHandle = buffer;
209     SkAutoTUnref<GrRenderTarget>
210             renderTarget(grContext->textureProvider()->wrapBackendRenderTarget(desc));
211 
212     // setup SkSurface
213     // To use distance field text, use commented out SkSurfaceProps instead
214     // SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
215     //                      SkSurfaceProps::kLegacyFontHost_InitType);
216     SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
217     SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(renderTarget, &props));
218 
219     SkCanvas* canvas = surface->getCanvas();
220 
221     ApplicationState state;
222 
223     const char* helpMessage = "Click and drag to create rects.  Press esc to quit.";
224 
225     SkPaint paint;
226 
227     // create a surface for CPU rasterization
228     SkAutoTUnref<SkSurface> cpuSurface(SkSurface::NewRaster(canvas->imageInfo()));
229 
230     SkCanvas* offscreen = cpuSurface->getCanvas();
231     offscreen->save();
232     offscreen->translate(50.0f, 50.0f);
233     offscreen->drawPath(create_star(), paint);
234     offscreen->restore();
235 
236     SkAutoTUnref<SkImage> image(cpuSurface->newImageSnapshot());
237 
238     int rotation = 0;
239     while (!state.fQuit) { // Our application loop
240         SkRandom rand;
241         canvas->clear(SK_ColorWHITE);
242         handle_events(&state, canvas);
243 
244         paint.setColor(SK_ColorBLACK);
245         canvas->drawText(helpMessage, strlen(helpMessage), SkIntToScalar(100),
246                          SkIntToScalar(100), paint);
247         for (int i = 0; i < state.fRects.count(); i++) {
248             paint.setColor(rand.nextU() | 0x44808080);
249             canvas->drawRect(state.fRects[i], paint);
250         }
251 
252         // draw offscreen canvas
253         canvas->save();
254         canvas->translate(dm.w / 2.0, dm.h / 2.0);
255         canvas->rotate(rotation++);
256         canvas->drawImage(image, -50.0f, -50.0f);
257         canvas->restore();
258 
259         canvas->flush();
260         SDL_GL_SwapWindow(window);
261     }
262 
263     if (glContext) {
264         SDL_GL_DeleteContext(glContext);
265     }
266 
267     //Destroy window
268     SDL_DestroyWindow(window);
269 
270     //Quit SDL subsystems
271     SDL_Quit();
272     return 0;
273 }
274