blob: 9a9b07f6ae212926a9d6295f1a9e1dd49c5e477b [file] [log] [blame]
#import "SkUIView.h"
//#define SKWIND_CONFIG SkBitmap::kRGB_565_Config
#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config
#define SKGL_CONFIG kEAGLColorFormatRGB565
//#define SKGL_CONFIG kEAGLColorFormatRGBA8
#define FORCE_REDRAW
//#define USE_GL_1
#define USE_GL_2
#include "SkCanvas.h"
#include "GrContext.h"
#include "GrGLInterface.h"
#include "SkGpuDevice.h"
#include "SkCGUtils.h"
class SkiOSDeviceManager : public SampleWindow::DeviceManager {
public:
SkiOSDeviceManager() {
fGrContext = NULL;
fGrRenderTarget = NULL;
usingGL = false;
}
virtual ~SkiOSDeviceManager() {
SkSafeUnref(fGrContext);
SkSafeUnref(fGrRenderTarget);
}
virtual void init(SampleWindow* win) {
win->attachGL();
if (NULL == fGrContext) {
#ifdef USE_GL_1
fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
#else
fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
#endif
}
if (NULL == fGrContext) {
SkDebugf("Failed to setup 3D");
win->detachGL();
}
}
virtual bool supportsDeviceType(SampleWindow::DeviceType dType) {
switch (dType) {
case SampleWindow::kRaster_DeviceType:
case SampleWindow::kPicture_DeviceType: // fallthru
return true;
case SampleWindow::kGPU_DeviceType:
return NULL != fGrContext;
default:
return false;
}
}
virtual bool prepareCanvas(SampleWindow::DeviceType dType,
SkCanvas* canvas,
SampleWindow* win) {
if (SampleWindow::kGPU_DeviceType == dType) {
canvas->setDevice(new SkGpuDevice(fGrContext, fGrRenderTarget))->unref();
usingGL = true;
}
else {
//The clip needs to be applied with a device attached to the canvas
canvas->setBitmapDevice(win->getBitmap());
usingGL = false;
}
return true;
}
virtual void publishCanvas(SampleWindow::DeviceType dType,
SkCanvas* canvas,
SampleWindow* win) {
if (SampleWindow::kGPU_DeviceType == dType) {
fGrContext->flush();
}
else {
//CGContextRef cg = UIGraphicsGetCurrentContext();
//SkCGDrawBitmap(cg, win->getBitmap(), 0, 0);
}
win->presentGL();
}
virtual void windowSizeChanged(SampleWindow* win) {
if (fGrContext) {
win->attachGL();
GrPlatformSurfaceDesc desc;
desc.reset();
desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
desc.fWidth = SkScalarRound(win->width());
desc.fHeight = SkScalarRound(win->height());
desc.fConfig = kRGBA_8888_GrPixelConfig;
const GrGLInterface* gl = GrGLGetDefaultGLInterface();
GrAssert(NULL != gl);
GR_GL_GetIntegerv(gl, GR_GL_STENCIL_BITS, &desc.fStencilBits);
GR_GL_GetIntegerv(gl, GR_GL_SAMPLES, &desc.fSampleCnt);
GrGLint buffer;
GR_GL_GetIntegerv(gl, GR_GL_FRAMEBUFFER_BINDING, &buffer);
desc.fPlatformRenderTarget = buffer;
SkSafeUnref(fGrRenderTarget);
fGrRenderTarget = static_cast<GrRenderTarget*>(
fGrContext->createPlatformSurface(desc));
}
}
bool isUsingGL() { return usingGL; }
virtual GrContext* getGrContext() { return fGrContext; }
private:
bool usingGL;
GrContext* fGrContext;
GrRenderTarget* fGrRenderTarget;
};
////////////////////////////////////////////////////////////////////////////////
@implementation SkUIView
@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer, fOptionsDelegate;
#include "SkApplication.h"
#include "SkEvent.h"
#include "SkWindow.h"
#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
extern bool gDoTraceDraw;
#define DO_TRACE_DRAW_MAX 100
struct FPSState {
static const int FRAME_COUNT = 60;
CFTimeInterval fNow0, fNow1;
CFTimeInterval fTime0, fTime1, fTotalTime;
int fFrameCounter;
int fDrawCounter;
SkString str;
FPSState() {
fTime0 = fTime1 = fTotalTime = 0;
fFrameCounter = 0;
}
void startDraw() {
fNow0 = CACurrentMediaTime();
if (0 == fDrawCounter && false) {
gDoTraceDraw = true;
SkDebugf("\n");
}
}
void endDraw() {
fNow1 = CACurrentMediaTime();
if (0 == fDrawCounter) {
gDoTraceDraw = true;
}
if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
fDrawCounter = 0;
}
}
void flush(SkOSWindow* hwnd) {
CFTimeInterval now2 = CACurrentMediaTime();
fTime0 += fNow1 - fNow0;
fTime1 += now2 - fNow1;
if (++fFrameCounter == FRAME_COUNT) {
CFTimeInterval totalNow = CACurrentMediaTime();
fTotalTime = totalNow - fTotalTime;
//SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
//SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
//str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
// FRAME_COUNT / fTotalTime);
str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
hwnd->setTitle(NULL);
fTotalTime = totalNow;
fTime0 = fTime1 = 0;
fFrameCounter = 0;
}
}
};
static FPSState gFPS;
#define FPS_StartDraw() gFPS.startDraw()
#define FPS_EndDraw() gFPS.endDraw()
#define FPS_Flush(wind) gFPS.flush(wind)
///////////////////////////////////////////////////////////////////////////////
- (id)initWithMyDefaults {
fRedrawRequestPending = false;
fFPSState = new FPSState;
//Add gesture recognizer for single taps. Taps on the right half of the view
//will cause SampleApp to go to the next sample, taps on the left will go to
//the previous sample
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleTap:)];
[self addGestureRecognizer:tap];
[tap release];
#ifdef USE_GL_1
fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
#else
fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
#endif
if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
{
[self release];
return nil;
}
// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
glGenFramebuffers(1, &fGL.fFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
glGenRenderbuffers(1, &fGL.fRenderbuffer);
glGenRenderbuffers(1, &fGL.fStencilbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
self.fGLLayer = [CAEAGLLayer layer];
fGLLayer.bounds = self.bounds;
fGLLayer.anchorPoint = CGPointMake(0, 0);
fGLLayer.opaque = TRUE;
[self.layer addSublayer:fGLLayer];
fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO],
kEAGLDrawablePropertyRetainedBacking,
SKGL_CONFIG,
kEAGLDrawablePropertyColorFormat,
nil];
self.fRasterLayer = [CALayer layer];
fRasterLayer.anchorPoint = CGPointMake(0, 0);
fRasterLayer.opaque = TRUE;
[self.layer addSublayer:fRasterLayer];
NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
[NSNull null], @"onOrderOut",
[NSNull null], @"sublayers",
[NSNull null], @"contents",
[NSNull null], @"bounds",
nil];
fGLLayer.actions = newActions;
fRasterLayer.actions = newActions;
[newActions release];
fDevManager = new SkiOSDeviceManager;
fWind = new SampleWindow(self, NULL, NULL, fDevManager);
application_init();
fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
return self;
}
- (id)initWithCoder:(NSCoder*)coder {
if ((self = [super initWithCoder:coder])) {
self = [self initWithMyDefaults];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self = [self initWithMyDefaults];
}
return self;
}
- (void)dealloc {
delete fWind;
delete fDevManager;
delete fFPSState;
self.fRasterLayer = nil;
self.fGLLayer = nil;
[fGL.fContext release];
application_term();
[fTitleItem release];
[super dealloc];
}
- (void)layoutSubviews {
int W, H;
// Allocate color buffer backing based on the current layer size
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
[fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
if (fDevManager->isUsingGL()) {
W = fGL.fWidth;
H = fGL.fHeight;
CGRect rect = CGRectMake(0, 0, W, H);
fGLLayer.bounds = rect;
}
else {
CGRect rect = self.bounds;
W = (int)CGRectGetWidth(rect);
H = (int)CGRectGetHeight(rect);
fRasterLayer.bounds = rect;
}
printf("---- layoutSubviews %d %d\n", W, H);
fWind->resize(W, H);
fWind->inval(NULL);
}
///////////////////////////////////////////////////////////////////////////////
- (void)drawWithCanvas:(SkCanvas*)canvas {
fRedrawRequestPending = false;
fFPSState->startDraw();
fWind->draw(canvas);
fFPSState->endDraw();
#ifdef FORCE_REDRAW
fWind->inval(NULL);
#endif
fFPSState->flush(fWind);
}
- (void)drawInGL {
// This application only creates a single context which is already set current at this point.
// This call is redundant, but needed if dealing with multiple contexts.
[EAGLContext setCurrentContext:fGL.fContext];
// This application only creates a single default framebuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple framebuffers.
glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
GLint scissorEnable;
glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
if (scissorEnable) {
glEnable(GL_SCISSOR_TEST);
}
glViewport(0, 0, fGL.fWidth, fGL.fHeight);
GrContext* ctx = fDevManager->getGrContext();
SkASSERT(NULL != ctx);
SkCanvas canvas;
// if we're not "retained", then we have to always redraw everything.
// This call forces us to ignore the fDirtyRgn, and draw everywhere.
// If we are "retained", we can skip this call (as the raster case does)
fWind->forceInvalAll();
[self drawWithCanvas:&canvas];
// This application only creates a single color renderbuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple renderbuffers.
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
[fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
#if GR_COLLECT_STATS
// static int frame = 0;
// if (!(frame % 100)) {
// ctx->printStats();
// }
// ctx->resetStats();
// ++frame;
#endif
}
- (void)drawInRaster {
SkCanvas canvas;
[self drawWithCanvas:&canvas];
CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
fRasterLayer.contents = (id)cgimage;
CGImageRelease(cgimage);
}
- (void)forceRedraw {
if (fDevManager->isUsingGL())
[self drawInGL];
else
[self drawInRaster];
}
//Gesture Handlers
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint loc = [touch locationInView:self];
fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch);
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint loc = [touch locationInView:self];
fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch);
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint loc = [touch locationInView:self];
fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint loc = [touch locationInView:self];
fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
}
}
- (void)handleTap:(UISwipeGestureRecognizer *)sender {
// CGPoint loc = [sender locationInView:self];
// if (loc.x > self.bounds.size.width/2)
// ((SampleWindow*)fWind)->nextSample();
// else
// ((SampleWindow*)fWind)->previousSample();
}
///////////////////////////////////////////////////////////////////////////////
- (void)setSkTitle:(const char *)title {
NSString* text = [NSString stringWithUTF8String:title];
if ([text length] > 0)
self.fTitle = text;
if (fTitleItem && fTitle) {
fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
[NSString stringWithUTF8String:fFPSState->str.c_str()]];
}
}
- (BOOL)onHandleEvent:(const SkEvent&)evt {
return false;
}
#include "SkOSMenu.h"
- (void)onAddMenu:(const SkOSMenu*)menu {
[self.fOptionsDelegate view:self didAddMenu:menu];
}
- (void)onUpdateMenu:(const SkOSMenu*)menu {
[self.fOptionsDelegate view:self didUpdateMenu:menu];
}
- (void)postInvalWithRect:(const SkIRect*)r {
if (!fRedrawRequestPending) {
fRedrawRequestPending = true;
bool gl = fDevManager->isUsingGL();
[CATransaction begin];
[CATransaction setAnimationDuration:0];
fRasterLayer.hidden = gl;
fGLLayer.hidden = !gl;
[CATransaction commit];
if (gl) {
[self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
}
else {
[self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
[self setNeedsDisplay];
}
}
}
@end