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

263 lines
8.4 KiB
Plaintext

//
// oglview2.m
// wi
//
// Created by Scott Ludwig on 5/22/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import "oglview2.h"
@implementation OglView2
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
- (id)initWithFrame:(struct CGRect)rect
{
self = [super initWithFrame: rect];
if (self == nil)
return nil;
rect_ = rect;
pb_ = NULL;
tex_ = 0;
framebufferTex_ = 0;
renderbuffer_ = 0;
framebufferRender_ = 0;
context_ = NULL;
[self initLayer];
return self;
}
- (void)dealloc {
[super dealloc];
[self cleanupGraphics];
}
- (void)initLayer
{
// The basic approach is to update an ogl texture from back buffer +
// update map, then texture map that into a render buffer, then show
// that in this view.
//
// The contentious part is updating the ogl texture. It is regularly a
// very slow process, however when a texture is set up to be a rendering
// destination, updating the texture with glTexSubImage2D is much faster,
// because the texture bits are stored more efficiently for updating this
// way.
//
// Two framebuffer objects are created. One with the texture in the color
// buffer attach point, one with the destination renderbuffer in the color
// buffer attach point. For each frame, the texture is updated, then
// texture mapped into the render buffer, then the render buffer is shown
// on screen.
// Clear before drawing set to NO is a little faster. The game doesn't
// use a drawing context (not sure if this matters for CAEAGLLayer).
self.clearsContextBeforeDrawing = NO;
// Setting the view as opaque means the OS doesn't need to working
// about compositing layers underneath.
CAEAGLLayer *layer = (CAEAGLLayer *)self.layer;
layer.opaque = YES;
// No retained backing, and 565 format
layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:FALSE],
kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat,
(char *)NULL];
// Create and initialize an EAGL Context
context_ = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
[EAGLContext setCurrentContext:context_];
// Now create the render buffer, use the CAEAGLLayer for storage, and
// attach it to another framebuffer.
glGenRenderbuffersOES(1, &renderbuffer_);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, renderbuffer_);
[context_ renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
// Bind the renderbuffer to a framebuffer object's color
// buffer attach point. This will be the rendering destination.
glGenFramebuffersOES(1, &framebufferRender_);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebufferRender_);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, renderbuffer_);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, renderbuffer_);
// Create a texture and framebuffer. Attach texture to framebuffer.
// This is done so that the texture is internally stored in a format
// that makes glTexSubImage2D() fast (otherwise it is really slow).
// Texture must be power of 2 dimensions
int cxTex = (int)rect_.size.width;
if ((cxTex & (cxTex - 1)) != 0) {
cxTex <<= 1;
while ((cxTex & (cxTex - 1)) != 0)
cxTex &= cxTex - 1;
}
int cyTex = (int)rect_.size.height;
if ((cyTex & (cyTex - 1)) != 0) {
cyTex <<= 1;
while ((cyTex & (cyTex - 1)) != 0)
cyTex &= cyTex - 1;
}
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &tex_);
glBindTexture(GL_TEXTURE_2D, tex_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cxTex, cyTex, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
glGenFramebuffersOES(1, &framebufferTex_);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebufferTex_);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex_, 0);
// Bind framebufferRender_ and tex_ here, since this is what
// draw code needs.
glBindTexture(GL_TEXTURE_2D, tex_);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebufferRender_);
// Perform the rest of misc gl initialization.
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, rect_.size.width, rect_.size.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0.0f, rect_.size.width, rect_.size.height, 0.0f, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Texture map parameters
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Pre-initialize so this isn't done during drawing
coords_[0] = 0.0f;
coords_[1] = 0.0f;
coords_[2] = rect_.size.width / cxTex;
coords_[3] = 0.0f;
coords_[4] = 0.0f;
coords_[5] = rect_.size.height / cyTex;
coords_[6] = rect_.size.width / cxTex;
coords_[7] = rect_.size.height / cyTex;
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, coords_);
verts_[0] = 0.0f;
verts_[1] = rect_.size.height;
verts_[2] = 1.0f;
verts_[3] = rect_.size.width;
verts_[4] = rect_.size.height;
verts_[5] = 1.0f;
verts_[6] = 0.0f;
verts_[7] = 0.0f;
verts_[8] = 1.0f;
verts_[9] = rect_.size.width;
verts_[10] = 0.0f;
verts_[11] = 1.0f;
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, verts_);
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Don't have palette yet
havePalette_ = false;
}
- (void)initGraphics {
// NOTE: initGraphics is called from the game thread
[EAGLContext setCurrentContext:context_];
}
- (void)cleanupGraphics {
// NOTE: called on game thread
// Detach texture from framebufferTex_, unbind and delete both
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebufferTex_);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, 0, GL_TEXTURE_2D, 0, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &tex_);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDeleteFramebuffersOES(1, &framebufferTex_);
// Detach renderbuffer from framebufferRender_, unbind and delete both
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebufferRender_);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
glDeleteRenderbuffersOES(1, &framebufferRender_);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDeleteFramebuffersOES(1, &framebufferRender_);
[EAGLContext setCurrentContext:NULL];
[context_ release];
if (pb_ != NULL) {
free(pb_);
pb_ = NULL;
}
tex_ = 0;
framebufferTex_ = 0;
renderbuffer_ = 0;
framebufferRender_ = 0;
context_ = NULL;
}
- (void)frameStart {
pbm_->ResetChanged();
}
- (void)frameComplete {
if (!havePalette_)
return;
if (!pbm_->HasChanged())
return;
// Draw texture.
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[context_ presentRenderbuffer:renderbuffer_];
}
- (wi::DibBitmap *)createFrontDibWithOrientation:(int)nDegreeOrientation width:(int)cx height:(int)cy {
// This is called from the game thread. initGraphics here because the
// game thread will be doing the rendering.
[self initGraphics];
// Allocate the memory OglDib uses
int cb = 2 * cx * cy;
pb_ = (unsigned char *)malloc(cb);
memset(pb_, 0, cb);
wi::SurfaceProperties props;
[self getSurfaceProperties:&props];
pbm_ = wi::CreateOglDib(pb_, &props, cx, cy, nDegreeOrientation);
return pbm_;
}
- (void)setPalette:(wi::Palette *)ppal {
if (pbm_ != NULL) {
// 8->565 mapping table. OpenGL ES understands 565 format.
word mp8bpp16bpp[256];
for (int n = 0; n < BigWord(ppal->cEntries); n++) {
mp8bpp16bpp[n] = ((ppal->argb[n][0] << 8) & 0xf800) | ((ppal->argb[n][1] << 3) & 0x07e0) | ((ppal->argb[n][2] >> 3) & 0x001f);
}
pbm_->SetPalette(mp8bpp16bpp, sizeof(mp8bpp16bpp));
havePalette_ = true;
}
}
@end