hostile-takeover/game/iphone/layerview.mm
2016-01-03 23:19:26 -08:00

204 lines
5.5 KiB
Plaintext

#import <QuartzCore/QuartzCore.h>
#import "game/iphone/layerview.h"
#import "game/iphone/iphone.h"
#include "base/log.h"
@implementation LayerView
- (id)initWithFrame:(struct CGRect)rect
{
self = [super initWithFrame: rect];
if (self == nil) {
return nil;
}
//self.backgroundColor = [UIColor clearColor];
[[self layer] setOpaque: YES];
self.clearsContextBeforeDrawing = NO;
[[self.superview layer] setOpaque: YES];
self.superview.clearsContextBeforeDrawing = NO;
rect_ = rect;
// This produces a coordinate system that is like a landscape sector 0NO;
// (origin bottom left). This will make the OS rotate blts for us.
tm_ = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
rect.size.height);
tm_ = CGAffineTransformRotate(tm_, 4.7123889749);
tm_ = CGAffineTransformTranslate(tm_, -rect_.size.height, 0);
initialized_ = false;
crcInvalid_ = 0;
arcInvalid_ = NULL;
return self;
}
- (void)dealloc
{
if (bmCtx_ != NULL) {
CGContextRelease(bmCtx_);
}
delete arcInvalid_;
[super dealloc];
}
- (void)setFormMgrs:(wi::FormMgr *)pfrmmSimUI input:(wi::FormMgr *)pfrmmInput
{
wi::Size sizMap0;
pfrmmSimUI->GetUpdateMap()->GetMapSize(&sizMap0);
wi::Size sizDib;
pfrmmSimUI->GetDib()->GetSize(&sizDib);
wi::Rect rc;
rc.Set(0, 0, sizDib.cx, sizDib.cy);
pbm_->InitLayerMap(0, &rc, &sizMap0);
wi::Size sizMap1;
pfrmmInput->GetUpdateMap()->GetMapSize(&sizMap1);
rc.top = sizDib.cy;
pfrmmInput->GetDib()->GetSize(&sizDib);
rc.bottom = rc.top + sizDib.cy;
pbm_->InitLayerMap(1, &rc, &sizMap1);
// Now allocate the max # of invalid rects that may result
int crcMax = (sizMap0.cx * sizMap0.cy + sizMap1.cx * sizMap1.cy) / 2;
arcInvalid_ = new CGRect[crcMax];
initialized_ = true;
}
- (void)drawRect:(CGRect)frame
{
if (!initialized_) {
return;
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
base::CritScope cs(pcrit_);
CGContextSaveGState(ctx);
CGContextConcatCTM(ctx, tm_);
// iPhone expands invalid areas in some mysterious cases,
// so it is not possible to rely solely on game invalid rects.
// This bounding rect is the best thing iPhone provides - however
// the ctx is clipped to the rects the game provided (plus the
// mysterious extra).
// Also: there appears to be no way to stop iPhone from erasing
// the invalid areas before drawRect gets control. Setting
// the clear property to NO does nothing.
CGRect rcInvalid= CGRectMake(frame.origin.y, frame.origin.x,
frame.size.height, frame.size.width);
pbm_->Draw(ctx, rcInvalid);
// [self drawSprites: ctx];
CGContextRestoreGState(ctx);
}
- (void)frameStart
{
// Hold the critical section around game drawing. This way,
// the graphics, and the invalidation of the view can be updated
// atomically.
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;
}
- (void)frameComplete:(int)cfrmm maps:(wi::UpdateMap **)apupd
rects:(wi::Rect *)arc scrolled:(bool)fScrolled
{
if (!havePalette_ || !pbm_->HasChanged()) {
pcrit_->Leave();
return;
}
// Everything needs to redraw if scrolling
if (fScrolled) {
pbm_->MarkUpdate();
arcInvalid_[0] = rect_;
crcInvalid_ = 1;
pcrit_->Leave();
[self performSelectorOnMainThread:@selector(invalidate)
withObject:nil waitUntilDone: NO];
return;
}
// Collect the invalid rects, and send them over to the main
// thread
CGRect *prc = arcInvalid_;
crcInvalid_ = 0;
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 (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_ = (int)(prc - arcInvalid_);
pcrit_->Leave();
[self performSelectorOnMainThread:@selector(invalidate)
withObject:nil waitUntilDone: NO];
}
- (wi::DibBitmap *)createFrontDibWithOrientation:(int)nDegreeOrientation width:(int)cx height:(int)cy
{
pbm_ = wi::CreateLayerDib(cx, cy);
return pbm_;
}
- (void)resetScrollOffset
{
pbm_->ResetScrollOffset();
}
- (void)setPalette:(wi::Palette *)ppal
{
if (pbm_ != NULL) {
// 8->8888 mapping table. 3x faster than 555 format.
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