hostile-takeover/game/iphone/cgview.mm
2014-07-06 17:47:28 -07:00

229 lines
6.0 KiB
Plaintext

#import <QuartzCore/QuartzCore.h>
#import "game/iphone/cgview.h"
#import "game/iphone/iphone.h"
#include "base/log.h"
@implementation CgView
- (id)initWithFrame:(struct CGRect)rect
{
self = [super initWithFrame: rect];
if (self != nil) {
[self initGraphics];
image_ = NULL;
arcInvalid_ = NULL;
crcInvalid_ = 0;
crcInvalidMax_ = 0;
}
return self;
}
- (void)dealloc
{
CGContextRelease(bmCtx_);
if (image_ != NULL) {
CGImageRelease(image_);
}
delete arcInvalid_;
[super dealloc];
}
- (void)setFormMgrs:(wi::FormMgr *)pfrmmSimUI input:(wi::FormMgr *)pfrmmInput
{
// Now allocate the max # of invalid rects that may result
wi::Size sizMap0;
pfrmmSimUI->GetUpdateMap()->GetMapSize(&sizMap0);
wi::Size sizMap1;
pfrmmInput->GetUpdateMap()->GetMapSize(&sizMap1);
int crcMax = (sizMap0.cx * sizMap0.cy + sizMap1.cx * sizMap1.cy) / 2;
delete arcInvalid_;
arcInvalid_ = new CGRect[crcMax];
crcInvalid_ = 0;
crcInvalidMax_ = crcMax;
}
- (void)initGraphics
{
// The OS erases invalid areas black whether clearsContext is YES or NO.
[[self layer] setOpaque: YES];
self.clearsContextBeforeDrawing = NO;
int w = rect_.size.width;
int h = rect_.size.height;
int allocSize = 4 * w * h;
pb_ = (unsigned char *)malloc(allocSize);
memset(pb_, 0, allocSize);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
bmCtx_ = CGBitmapContextCreate(pb_, w, h, 8, w * 4, colorSpace,
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrderDefault);
CGColorSpaceRelease(colorSpace);
tmFlip_ = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, h);
}
- (void)drawRect:(CGRect)frame
{
// OS 4.0 introduces contentScaleFactor. If this is set to anything other
// than 1.0, the OS performs a very slow blt. OS 4.0 defaults it to 2.0
// on iPhone 4. Set it back to 1.0 if the selector is present.
if ([self respondsToSelector:@selector(setContentScaleFactor:)]) {
[self setContentScaleFactor: 1.0];
}
base::CritScope cs(pcrit_);
if (image_ == NULL) {
return;
}
CGRect rc = [self bounds];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextConcatCTM(ctx, tmFlip_);
CGContextDrawImage(ctx, rc, image_);
[self drawSprites: ctx];
CGContextRestoreGState(ctx);
}
- (void)frameStart
{
pcrit_->Enter();
pbm_->ResetChanged();
}
- (void)invalidate
{
// Runs on main thread
base::CritScope cs(pcrit_);
for (int i = 0; i < crcInvalid_; i++) {
[self setNeedsDisplayInRect:arcInvalid_[i]];
}
crcInvalid_ = 0;
}
//#define INVALID_RECTS
- (void)frameComplete:(int)cfrmm maps:(wi::UpdateMap **)apupd
rects:(wi::Rect *)arc scrolled:(bool)fScrolled
{
if (!havePalette_) {
pcrit_->Leave();
return;
}
// Sprites may have changes, or front dib may have changed, or neither.
bool fImageChanged = false;
if (pbm_->HasChanged()) {
if (image_ != NULL) {
CGImageRelease(image_);
image_ = NULL;
}
image_ = CGBitmapContextCreateImage(bmCtx_);
fImageChanged = true;
}
bool fSpriteChanged = false;
if (fSpriteDirty_) {
fSpriteDirty_ = false;
fSpriteChanged = true;
}
if (!fSpriteChanged && !fImageChanged) {
pcrit_->Leave();
return;
}
if (fScrolled || fSpriteChanged) {
#ifdef INVALID_RECTS
arcInvalid_[0] = rect_;
crcInvalid_ = 1;
[self performSelectorOnMainThread:@selector(invalidate)
withObject:nil waitUntilDone: NO];
#else
[self performSelectorOnMainThread:@selector(setNeedsDisplay)
withObject:nil waitUntilDone: NO];
#endif
pcrit_->Leave();
return;
}
if (fImageChanged) {
#ifdef INVALID_RECTS
// Collect the invalid rects, and send them over to the main
// thread
CGRect *prc = &arcInvalid_[crcInvalid_];
CGRect *prcMax = &arcInvalid_[crcInvalidMax_];
int cy = (int)rect_.size.width;
for (int i = 0; i < cfrmm; i++) {
wi::UpdateMap *pupd = apupd[i];
int yTop = arc[i].top;
bool fFirst = true;
wi::Rect rc;
while (prc < prcMax && pupd->EnumUpdateRects(fFirst, NULL, &rc)) {
fFirst = false;
prc->origin.x = cy - (rc.bottom + yTop);
prc->origin.y = rc.left;
prc->size.width = rc.Height();
prc->size.height = rc.Width();
prc++;
}
}
crcInvalid_ = prc - arcInvalid_;
[self performSelectorOnMainThread:@selector(invalidate)
withObject:nil waitUntilDone: NO];
#else
[self performSelectorOnMainThread:@selector(setNeedsDisplay)
withObject:nil waitUntilDone: NO];
#endif
pcrit_->Leave();
return;
}
}
- (wi::DibBitmap *)createFrontDibWithOrientation:(int)nDegreeOrientation width:(int)cx height:(int)cy
{
wi::SurfaceProperties props;
[self getSurfaceProperties:&props];
pbm_ = wi::CreateCgDib(pb_, &props, cx, cy, nDegreeOrientation);
return pbm_;
}
- (void)setPalette:(wi::Palette *)ppal
{
if (pbm_ != NULL) {
// 8->8888 mapping table. 3x faster than 555 format even though it is
// converted to 565 for display.
dword mp8bpp32bpp[256];
for (int n = 0; n < BigWord(ppal->cEntries); n++) {
byte *pb = (byte *)&mp8bpp32bpp[n];
*pb++ = 0;
*pb++ = ppal->argb[n][0];
*pb++ = ppal->argb[n][1];
*pb++ = ppal->argb[n][2];
}
pbm_->SetPalette(mp8bpp32bpp, sizeof(mp8bpp32bpp));
havePalette_ = true;
}
}
- (void)getSurfaceProperties:(wi::SurfaceProperties *)pprops
{
pprops->cxWidth = (int)rect_.size.width;
pprops->cyHeight = (int)rect_.size.height;
pprops->cbxPitch = 4;
pprops->cbyPitch = (int)rect_.size.width * 4;
pprops->ffFormat = wi::kfDirect888;
}
@end