Home | History | Annotate | Download | only in example
      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 {
     35     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 
     41 static void handle_error() {
     42     const char* error = SDL_GetError();
     43     SkDebugf("SDL Error: %s\n", error);
     44     SDL_ClearError();
     45 }
     46 
     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
     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)
    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