blob: 77cab50820d4baf1f4f5d16aaa0f023a140c5699 [file] [log] [blame]
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00001#import "SkUIView.h"
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00002
3//#define SKWIND_CONFIG SkBitmap::kRGB_565_Config
4#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config
5#define SKGL_CONFIG kEAGLColorFormatRGB565
6//#define SKGL_CONFIG kEAGLColorFormatRGBA8
7
8#define FORCE_REDRAW
9
10//#define USE_GL_1
yangsu@google.com74d25b12011-07-17 14:51:52 +000011#define USE_GL_2
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000012
13#include "SkCanvas.h"
14#include "GrContext.h"
15#include "GrGLInterface.h"
16#include "SkGpuDevice.h"
17#include "SkCGUtils.h"
18
19SkiOSDeviceManager::SkiOSDeviceManager() {
20 fGrContext = NULL;
21 fGrRenderTarget = NULL;
22 usingGL = false;
23}
yangsu@google.com2ba30c02011-07-19 15:17:44 +000024
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000025SkiOSDeviceManager::~SkiOSDeviceManager() {
26 SkSafeUnref(fGrContext);
27 SkSafeUnref(fGrRenderTarget);
28}
29
30void SkiOSDeviceManager::init(SampleWindow* win) {
31 win->attachGL();
32 if (NULL == fGrContext) {
yangsu@google.com74d25b12011-07-17 14:51:52 +000033#ifdef USE_GL_1
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000034 fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
yangsu@google.com2ba30c02011-07-19 15:17:44 +000035#else
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000036 fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
37#endif
38 }
39 fGrRenderTarget = SkGpuDevice::Current3DApiRenderTarget();
40 if (NULL == fGrContext) {
41 SkDebugf("Failed to setup 3D");
42 win->detachGL();
43 }
44}
45bool SkiOSDeviceManager::supportsDeviceType(SampleWindow::DeviceType dType) {
46 switch (dType) {
47 case SampleWindow::kRaster_DeviceType:
48 case SampleWindow::kPicture_DeviceType: // fallthru
49 return true;
50 case SampleWindow::kGPU_DeviceType:
51 return NULL != fGrContext;
52 default:
53 return false;
54 }
55}
56bool SkiOSDeviceManager::prepareCanvas(SampleWindow::DeviceType dType,
57 SkCanvas* canvas,
58 SampleWindow* win) {
59 if (SampleWindow::kGPU_DeviceType == dType) {
60 canvas->setDevice(new SkGpuDevice(fGrContext, fGrRenderTarget))->unref();
61 usingGL = true;
62 }
63 else {
64 //The clip needs to be applied with a device attached to the canvas
yangsu@google.com2ba30c02011-07-19 15:17:44 +000065 canvas->setBitmapDevice(win->getBitmap());
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000066 usingGL = false;
67 }
68 return true;
69}
70
71void SkiOSDeviceManager::publishCanvas(SampleWindow::DeviceType dType,
72 SkCanvas* canvas,
73 SampleWindow* win) {
74 if (SampleWindow::kGPU_DeviceType == dType) {
75 fGrContext->flush();
76 }
77 else {
yangsu@google.com2ba30c02011-07-19 15:17:44 +000078 //CGContextRef cg = UIGraphicsGetCurrentContext();
79 //SkCGDrawBitmap(cg, win->getBitmap(), 0, 0);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000080 }
81 win->presentGL();
82}
yangsu@google.com2ba30c02011-07-19 15:17:44 +000083
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000084////////////////////////////////////////////////////////////////////////////////
85@implementation SkUIView
86
yangsu@google.com2ba30c02011-07-19 15:17:44 +000087@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000088
89#include "SkApplication.h"
90#include "SkEvent.h"
91#include "SkWindow.h"
92
93static float gScreenScale = 1;
94
95#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
96
97static const float SCALE_FOR_ZOOM_LENS = 4.0;
98#define Y_OFFSET_FOR_ZOOM_LENS 200
99#define SIZE_FOR_ZOOM_LENS 250
100
101static const float MAX_ZOOM_SCALE = 4.0;
102static const float MIN_ZOOM_SCALE = 2.0 / MAX_ZOOM_SCALE;
103
104extern bool gDoTraceDraw;
105#define DO_TRACE_DRAW_MAX 100
106
107struct FPSState {
108 static const int FRAME_COUNT = 60;
109
110 CFTimeInterval fNow0, fNow1;
111 CFTimeInterval fTime0, fTime1, fTotalTime;
112 int fFrameCounter;
113 int fDrawCounter;
114 SkString str;
115 FPSState() {
116 fTime0 = fTime1 = fTotalTime = 0;
117 fFrameCounter = 0;
118 }
119
120 void startDraw() {
121 fNow0 = CACurrentMediaTime();
122
123 if (0 == fDrawCounter && false) {
124 gDoTraceDraw = true;
125 SkDebugf("\n");
126 }
127 }
128
129 void endDraw() {
130 fNow1 = CACurrentMediaTime();
131
132 if (0 == fDrawCounter) {
133 gDoTraceDraw = true;
134 }
135 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
136 fDrawCounter = 0;
137 }
138 }
139
140 void flush(SkOSWindow* hwnd) {
141 CFTimeInterval now2 = CACurrentMediaTime();
142
143 fTime0 += fNow1 - fNow0;
144 fTime1 += now2 - fNow1;
145
146 if (++fFrameCounter == FRAME_COUNT) {
147 CFTimeInterval totalNow = CACurrentMediaTime();
148 fTotalTime = totalNow - fTotalTime;
149
150 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
151 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
152 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
153 // FRAME_COUNT / fTotalTime);
154 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
155 hwnd->setTitle(NULL);
156 fTotalTime = totalNow;
157 fTime0 = fTime1 = 0;
158 fFrameCounter = 0;
159 }
160 }
161};
162
163static FPSState gFPS;
164
165#define FPS_StartDraw() gFPS.startDraw()
166#define FPS_EndDraw() gFPS.endDraw()
167#define FPS_Flush(wind) gFPS.flush(wind)
168
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000169///////////////////////////////////////////////////////////////////////////////
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000170
171- (id)initWithMyDefaults {
172 fRedrawRequestPending = false;
173 fFPSState = new FPSState;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000174
175#ifdef USE_GL_1
176 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
177#else
178 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
179#endif
180
181 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
182 {
183 [self release];
184 return nil;
185 }
186
187 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
188 glGenFramebuffers(1, &fGL.fFramebuffer);
189 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
190
191 glGenRenderbuffers(1, &fGL.fRenderbuffer);
192 glGenRenderbuffers(1, &fGL.fStencilbuffer);
193
194 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
195 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
196
197 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
198 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000199
200 fGLLayer = [CAEAGLLayer layer];
201 fGLLayer.bounds = self.bounds;
202 fGLLayer.anchorPoint = CGPointMake(0, 0);
203 fGLLayer.opaque = TRUE;
204 [self.layer addSublayer:fGLLayer];
205 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
206 [NSNumber numberWithBool:NO],
207 kEAGLDrawablePropertyRetainedBacking,
208 SKGL_CONFIG,
209 kEAGLDrawablePropertyColorFormat,
210 nil];
211
212 fRasterLayer = [CALayer layer];
213 fRasterLayer.anchorPoint = CGPointMake(0, 0);
214 fRasterLayer.opaque = TRUE;
215 [self.layer addSublayer:fRasterLayer];
216
217 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
218 [NSNull null], @"onOrderOut",
219 [NSNull null], @"sublayers",
220 [NSNull null], @"contents",
221 [NSNull null], @"bounds",
222 nil];
223 fGLLayer.actions = newActions;
224 fRasterLayer.actions = newActions;
225 [newActions release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000226
227 fDevManager = new SkiOSDeviceManager;
228 fWind = new SampleWindow(self, NULL, NULL, fDevManager);
229 application_init();
230 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
231 fMatrix.reset();
232 fZoomAround = false;
233
234 return self;
235}
236
237- (id)initWithCoder:(NSCoder*)coder {
238 if ((self = [super initWithCoder:coder])) {
239 self = [self initWithMyDefaults];
240 }
241 return self;
242}
243
244- (id)initWithFrame:(CGRect)frame {
245 if (self = [super initWithFrame:frame]) {
246 self = [self initWithMyDefaults];
247 }
248 return self;
249}
250
251- (void)dealloc {
252 delete fWind;
253 delete fDevManager;
254 delete fFPSState;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000255 [fRasterLayer release];
256 [fGLLayer release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000257 application_term();
258 [fTitleItem release];
259 [super dealloc];
260}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000261
262- (void)layoutSubviews {
263 int W, H;
264 gScreenScale = [UIScreen mainScreen].scale;
265
266 if ([self respondsToSelector:@selector(setContentScaleFactor:)]) {
267 self.contentScaleFactor = gScreenScale;
268 }
269
270 // Allocate color buffer backing based on the current layer size
271 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
272 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
273
274 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
275 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
276
277 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
278 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
279
280 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
281 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
282 }
283
284 if (fDevManager->isUsingGL()) {
285 W = fGL.fWidth;
286 H = fGL.fHeight;
287 CGRect rect = CGRectMake(0, 0, W, H);
288 fGLLayer.bounds = rect;
289 }
290 else {
291 CGRect rect = self.bounds;
292 W = (int)CGRectGetWidth(rect);
293 H = (int)CGRectGetHeight(rect);
294 fRasterLayer.bounds = rect;
295 }
296
297 printf("---- layoutSubviews %d %d\n", W, H);
298 fWind->resize(W, H);
299 fWind->inval(NULL);
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000304- (void)drawWithCanvas:(SkCanvas*)canvas {
305 fRedrawRequestPending = false;
306 fFPSState->startDraw();
307 fWind->draw(canvas);
308 fFPSState->endDraw();
309#ifdef FORCE_REDRAW
310 fWind->inval(NULL);
311#endif
312 fFPSState->flush(fWind);
313}
314
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000315- (void)drawInGL {
316 // This application only creates a single context which is already set current at this point.
317 // This call is redundant, but needed if dealing with multiple contexts.
318 [EAGLContext setCurrentContext:fGL.fContext];
319
320 // This application only creates a single default framebuffer which is already bound at this point.
321 // This call is redundant, but needed if dealing with multiple framebuffers.
322 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
323
324 GLint scissorEnable;
325 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
326 glDisable(GL_SCISSOR_TEST);
327 glClearColor(0,0,0,0);
328 glClear(GL_COLOR_BUFFER_BIT);
329 if (scissorEnable) {
330 glEnable(GL_SCISSOR_TEST);
331 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000332 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000333
334
335 GrContext* ctx = fDevManager->getGrContext();
336 SkASSERT(NULL != ctx);
337
338 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000339
340 // if we're not "retained", then we have to always redraw everything.
341 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
342 // If we are "retained", we can skip this call (as the raster case does)
343 fWind->forceInvalAll();
344
345 [self drawWithCanvas:&canvas];
346
347 // This application only creates a single color renderbuffer which is already bound at this point.
348 // This call is redundant, but needed if dealing with multiple renderbuffers.
349 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
350 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
351
352#if GR_COLLECT_STATS
353// static int frame = 0;
354// if (!(frame % 100)) {
355// ctx->printStats();
356// }
357// ctx->resetStats();
358// ++frame;
359#endif
360}
361
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000362- (void)drawInRaster {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000363 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000364 [self drawWithCanvas:&canvas];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000365 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
366 fRasterLayer.contents = (id)cgimage;
367 CGImageRelease(cgimage);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000368}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000369
370- (void)forceRedraw {
371 if (fDevManager->isUsingGL())
372 [self drawInGL];
373 else
374 [self drawInRaster];
375}
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000376
377//Gesture Handlers
378- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
379 for (UITouch *touch in touches) {
380 CGPoint loc = [touch locationInView:self];
381 fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch);
382 }
383}
384
385- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
386 for (UITouch *touch in touches) {
387 CGPoint loc = [touch locationInView:self];
388 fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch);
389 }
390}
391
392- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
393 for (UITouch *touch in touches) {
394 CGPoint loc = [touch locationInView:self];
395 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
396 }
397}
398
399- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
400 for (UITouch *touch in touches) {
401 CGPoint loc = [touch locationInView:self];
402 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
403 }
404}
405
406///////////////////////////////////////////////////////////////////////////////
407
408- (void)setSkTitle:(const char *)title {
409 NSString* text = [NSString stringWithUTF8String:title];
410 if ([text length] > 0)
411 self.fTitle = text;
412
413 if (fTitleItem && fTitle) {
414 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
415 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
416 }
417}
418
419- (BOOL)onHandleEvent:(const SkEvent&)evt {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000420 return false;
421}
422
423- (void)postInvalWithRect:(const SkIRect*)r {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000424 if (!fRedrawRequestPending) {
425 fRedrawRequestPending = true;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000426 bool gl = fDevManager->isUsingGL();
427 [CATransaction begin];
428 [CATransaction setAnimationDuration:0];
429 fRasterLayer.hidden = gl;
430 fGLLayer.hidden = !gl;
431 [CATransaction commit];
432 if (gl) {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000433 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
434 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000435 else {
436 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
437 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000438 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000439}
440
441@end