mirror of
https://github.com/thes3m/XNI
synced 2024-12-26 13:26:06 +01:00
289 lines
9.0 KiB
Objective-C
289 lines
9.0 KiB
Objective-C
//
|
|
// GraphicsDevice.m
|
|
// XNI
|
|
//
|
|
// Created by Matej Jan on 27.7.10.
|
|
// Copyright 2010 Retronator. All rights reserved.
|
|
//
|
|
|
|
#import "GraphicsDevice.h"
|
|
#import <OpenGLES/ES1/gl.h>
|
|
|
|
#import "Retronator.Xni.Framework.h"
|
|
#import "Retronator.Xni.Framework.Graphics.h"
|
|
|
|
@interface GraphicsDevice()
|
|
|
|
+ (void) getFormat:(GLenum*)format AndType:(GLenum*)type ForSurfaceFormat:(SurfaceFormat)surfaceFormat;
|
|
|
|
@end
|
|
|
|
@implementation GraphicsDevice
|
|
|
|
- (id) initWithGame:(Game*)theGame
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
game = theGame;
|
|
|
|
// Create an OpenGL ES context
|
|
context = [self createContext];
|
|
|
|
if (!context || ![EAGLContext setCurrentContext:context]) {
|
|
[self release];
|
|
return nil;
|
|
}
|
|
|
|
// Create default framebuffer object.
|
|
glGenFramebuffersOES(1, &defaultFramebuffer);
|
|
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
|
|
|
|
// Create the color buffer.
|
|
glGenRenderbuffersOES(1, &colorRenderbuffer);
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
|
|
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
|
|
|
|
// Create the depth buffer.
|
|
glGenRenderbuffersOES(1, &depthRenderbuffer);
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
|
|
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
|
|
|
|
// Do the initial reset.
|
|
[self reset];
|
|
|
|
// Initialize defaults.
|
|
self.blendFactor = [Color white];
|
|
self.blendState = [BlendState opaque];
|
|
self.depthStencilState = [DepthStencilState defaultDepth];
|
|
graphicsDeviceStatus = GraphicsDeviceStatusNormal;
|
|
self.indices = nil;
|
|
self.rasterizerState = [RasterizerState cullClockwise];
|
|
self.referenceStencil = 0;
|
|
samplerStates = [[SamplerStateCollection alloc] init];
|
|
textures = [[TextureCollection alloc] init];
|
|
[samplerStates insertObject:[SamplerState linearClamp] atIndex:0];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
#define FLAG_BLOCK(variable, parameter) if (variable) { glEnable(parameter); } else { glDisable(parameter);}
|
|
|
|
@synthesize blendFactor;
|
|
@synthesize blendState;
|
|
- (void) setBlendState:(BlendState*)value {
|
|
if (value != blendState) {
|
|
[value retain];
|
|
[blendState release];
|
|
blendState = value;
|
|
|
|
// Apply the blend state.
|
|
glBlendFunc(blendState.colorSourceBlend, blendState.colorDestinationBlend);
|
|
}
|
|
}
|
|
|
|
@synthesize depthStencilState;
|
|
- (void) depthStencilState:(DepthStencilState*)value {
|
|
if (value != depthStencilState) {
|
|
[value retain];
|
|
[depthStencilState release];
|
|
depthStencilState = value;
|
|
}
|
|
}
|
|
|
|
@synthesize graphicsDeviceStatus;
|
|
@synthesize graphicsProfile;
|
|
@synthesize indices;
|
|
@synthesize rasterizerState;
|
|
- (void) setRasterizerState:(RasterizerState*)value {
|
|
if (value != rasterizerState) {
|
|
[value retain];
|
|
[rasterizerState release];
|
|
rasterizerState = value;
|
|
}
|
|
}
|
|
|
|
@synthesize referenceStencil;
|
|
@synthesize samplerStates;
|
|
@synthesize textures;
|
|
|
|
+ (int) getNumberOfVerticesForPrimitiveType:(PrimitiveType)primitiveType primitiveCount:(int)primitiveCount {
|
|
switch (primitiveType) {
|
|
case PrimitiveTypeLineStrip:
|
|
return primitiveCount + 1;
|
|
case PrimitiveTypeLineList:
|
|
return 2 * primitiveCount;
|
|
case PrimitiveTypeTriangleStrip:
|
|
return primitiveCount + 2;
|
|
case PrimitiveTypeTriangleList:
|
|
return 3 * primitiveCount;
|
|
default:
|
|
[NSException raise:@"NotImplementedException"
|
|
format:@"The primitive type %i is not yet implemented.", primitiveType];
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Presentation
|
|
- (void) reset {
|
|
CAEAGLLayer *layer = (CAEAGLLayer*)game.window.handle;
|
|
|
|
// Allocate color buffer backing based on the current layer size.
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
|
|
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer];
|
|
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
|
|
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
|
|
glViewport(0, 0, backingWidth, backingHeight);
|
|
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
|
|
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
|
|
|
|
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES){
|
|
NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
|
|
} else {
|
|
NSLog(@"Created a device with dimensions: %ix%i.", backingWidth, backingHeight);
|
|
}
|
|
}
|
|
|
|
- (void) present {
|
|
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
|
|
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
|
|
}
|
|
|
|
// Render buffers
|
|
|
|
- (void) clearWithColor:(Color *)color {
|
|
glClearColor(color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
|
|
glClearDepthf(1);
|
|
glClear(ClearOptionsTarget | ClearOptionsDepthBuffer);
|
|
}
|
|
|
|
- (void) clearWithOptions:(ClearOptions)options color:(Color *)color depth:(float)depth stencil:(int)stencil {
|
|
glClearColor(color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
|
|
glClearDepthf(depth);
|
|
glClearStencil(stencil);
|
|
glClear(options);
|
|
}
|
|
|
|
// Vertex buffers
|
|
- (NSArray*) getVertexBuffers {
|
|
return [[NSArray arrayWithArray:vertices] autorelease];
|
|
}
|
|
|
|
- (void) setVertexBuffer:(VertexBuffer*)vertexBuffer {
|
|
VertexBufferBinding *binding = [[VertexBufferBinding alloc] initWithVertexBuffer:vertexBuffer];
|
|
[vertices insertObject:binding atIndex:0];
|
|
[binding release];
|
|
}
|
|
|
|
- (void) setVertexBuffer:(VertexBuffer*)vertexBuffer vertexOffset:(int)vertexOffset {
|
|
VertexBufferBinding *binding = [[VertexBufferBinding alloc] initWithVertexBuffer:vertexBuffer vertexOffset:vertexOffset];
|
|
[vertices insertObject:binding atIndex:0];
|
|
[binding release];
|
|
}
|
|
|
|
- (void) setVertexBuffers:(VertexBufferBinding*)vertexBuffer, ... {
|
|
if (vertexBuffer != nil) {
|
|
va_list args;
|
|
va_start(args, vertexBuffer);
|
|
VertexBufferBinding *binding = vertexBuffer;
|
|
for (int i = 0; binding; i++) {
|
|
[vertices insertObject:binding atIndex:i];
|
|
binding = va_arg(args, VertexBufferBinding*);
|
|
}
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
// Low level methods
|
|
- (uint) createTexture {
|
|
GLuint textureId;
|
|
glGenTextures(1, &textureId);
|
|
return textureId;
|
|
}
|
|
|
|
- (void) setData:(void*)data toTexture2D:(Texture2D*)texture SourceRectangle:(Rectangle*)rect level:(int)level {
|
|
GLenum format, type;
|
|
[GraphicsDevice getFormat:&format AndType:&type ForSurfaceFormat:texture.format];
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture.textureId);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
if (rect) {
|
|
glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, rect.y, rect.width, rect.height, format, type, data);
|
|
} else {
|
|
glTexImage2D(GL_TEXTURE_2D, level, format, texture.width, texture.height, 0, format, type, data);
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
|
|
// Profile specific
|
|
|
|
- (EAGLContext*) createContext { return nil; }
|
|
|
|
- (void) drawPrimitivesOfType:(PrimitiveType)primitiveType startingAt:(int)startVertex count:(int)primitiveCount {}
|
|
|
|
- (void) drawIndexedPrimitivesOfType:(PrimitiveType)primitiveType offsetVerticesBy:(int)baseVertex
|
|
startingAt:(int)startIndex count:(int)primitiveCount {}
|
|
|
|
- (void) drawUserPrimitivesOfType:(PrimitiveType)primitiveType vertices:(VertexArray*)vertexData
|
|
startingAt:(int)vertexOffset count:(int)primitiveCount {}
|
|
|
|
- (void) drawUserPrimitivesOfType:(PrimitiveType)primitiveType
|
|
vertices:(void*)vertexData ofType:(VertexDeclaration*) vertexDeclaration
|
|
startingAt:(int)vertexOffset count:(int)primitiveCount {}
|
|
|
|
- (void) drawUserIndexedPrimitivesOfType:(PrimitiveType)primitiveType
|
|
vertices:(void*)vertexData ofType:(VertexDeclaration*) vertexDeclaration
|
|
offsetVerticesBy:(int)vertexOffset indices:(void*)indexData dataType:(DataType)dataType
|
|
startingAt:(int)indexOffset count:(int)primitiveCount {}
|
|
|
|
// Private methods
|
|
|
|
+ (void) getFormat:(GLenum*)format AndType:(GLenum*)type ForSurfaceFormat:(SurfaceFormat)surfaceFormat {
|
|
switch (surfaceFormat) {
|
|
case SurfaceFormatColor:
|
|
*format = GL_RGBA;
|
|
*type = GL_UNSIGNED_BYTE;
|
|
break;
|
|
case SurfaceFormatAlpha8:
|
|
*format = GL_ALPHA;
|
|
*type = GL_UNSIGNED_BYTE;
|
|
break;
|
|
case SurfaceFormatRgb565:
|
|
*format = GL_RGB;
|
|
*type = GL_UNSIGNED_SHORT_5_6_5;
|
|
break;
|
|
case SurfaceFormatRgba4444:
|
|
*format = GL_RGBA;
|
|
*type = GL_UNSIGNED_SHORT_4_4_4_4;
|
|
break;
|
|
case SurfaceFormatRgba5551:
|
|
*format = GL_RGBA;
|
|
*type = GL_UNSIGNED_SHORT_5_5_5_1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
[blendState release];
|
|
[depthStencilState release];
|
|
[rasterizerState release];
|
|
[samplerStates release];
|
|
[textures release];
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
|
|
@end
|