Related
For the life of me, I can't render an image to the iPhone simulator screen. I've simplified my code as much as possible.
The following code is in ViewController.m, a class that extends GLKViewController and is also a GLKViewDelegate.
- (void)viewDidLoad {
[super viewDidLoad];
/*Setup EAGLContext*/
self.context = [self createBestEAGLContext];
[EAGLContext setCurrentContext:self.context];
/*Setup View*/
GLKView *view = [[GLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
view.context = self.context;
view.delegate = self;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
self.view = view;
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
/*Setup GLK effect*/
self.effect = [[GLKBaseEffect alloc] init];
self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(0, 320, 480, 0, -1, 1);
glClearColor(0.5, 1, 1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:#"soccerball" ofType:#"jpg"];
GLKTextureInfo * textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (textureInfo == nil) {
NSLog(#"Error loading file: %#", [error localizedDescription]);
}
TexturedQuad newQuad;
newQuad.bl.geometryVertex = CGPointMake(0, 0);
newQuad.br.geometryVertex = CGPointMake(textureInfo.width, 0);
newQuad.tl.geometryVertex = CGPointMake(0, textureInfo.height);
newQuad.tr.geometryVertex = CGPointMake(textureInfo.width, textureInfo.height);
newQuad.bl.textureVertex = CGPointMake(0, 0);
newQuad.br.textureVertex = CGPointMake(1, 0);
newQuad.tl.textureVertex = CGPointMake(0, 1);
newQuad.tr.textureVertex = CGPointMake(1, 1);
self.effect.texture2d0.name = textureInfo.name;
self.effect.texture2d0.enabled = YES;
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
modelMatrix = GLKMatrix4Translate(modelMatrix, 100, 200, 0);
self.effect.transform.modelviewMatrix = modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&(newQuad);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
and some of the structs used...
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
Right now the only thing that is working is
glClearColor(0.5, 1, 1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
Which does adjust the background colour. There is no 'soccerball' image.
Any help is greatly appreciated.
EDIT - The TextureVertex CGPoints were incorrect so I fixed them. The problem still persists.
Solution:
The TexturedVertex struct must not use CGPoint, but rather GLKVector2.
This is because there is a conversion issue from the float values stored in these points. GLKit expects float values that have single point precision, but CGPoint float values have double point precision and things get weird. Furthermore, this problem only occurs after iOS 7.0
Refer to here for more detail on the issue.
OpenGL ES Shaders and 64-bit iPhone 5S
I'm using cocos2d as a game enigne and I'm trying to draw nice anti-aliased polygons in there.
I wrote a simple polygon (for now only triangle) drawing class similar to the CCDrawNode of cocos2d.
How can I apply anti-aliasing to only these triangles w/o applying AA to the whole system? :)
MLDrawNode.h
#import "CCNode.h"
#import "CCProgressTimer.h"
typedef struct {
NSUInteger indexInBuffer;
NSUInteger vertexCount;
MLVertexData *vertexData;
} mlPolygonData;
#interface MLDrawNode : CCNode
{
GLuint _vao;
GLuint _vbo;
NSUInteger _bufferCapacity;
GLsizei _bufferCount;
MLVertexData *_buffer;
ccBlendFunc _blendFunc;
NSUInteger _nextFreeVertexIndex;
BOOL _dirty;
}
#property(nonatomic, assign) ccBlendFunc blendFunc;
-(mlPolygonData) drawPolyWithVerts:(CGPoint *)verts count:(NSUInteger)count fillColor:(ccColor4F)fill borderWidth:(CGFloat)width borderColor:(ccColor4F)line;
-(void) clear;
#end
MLDrawNode.m
#implementation MLDrawNode
-(void)ensureCapacity:(NSUInteger)count
{
if(_bufferCount + count > _bufferCapacity){
_bufferCapacity += MAX(_bufferCapacity, count);
_buffer = realloc(_buffer, _bufferCapacity*sizeof(MLVertexData));
// NSLog(#"Resized vertex buffer to %d", _bufferCapacity);
}
}
-(id)init {
if((self = [super init])){
self.blendFunc = (ccBlendFunc){CC_BLEND_SRC, CC_BLEND_DST};
self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionLengthTexureColor];
[self ensureCapacity:512];
glGenVertexArrays(1, &_vao);
ccGLBindVAO(_vao);
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(ccV2F_C4B_T2F)*_bufferCapacity, _buffer, GL_STREAM_DRAW);
glEnableVertexAttribArray(kCCVertexAttrib_Position);
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, sizeof(MLVertexData), (GLvoid *)offsetof(ccV2F_C4B_T2F, vertices));
glEnableVertexAttribArray(kCCVertexAttrib_Color);
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, sizeof(MLVertexData), (GLvoid *)offsetof(MLVertexData, color));
glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(MLVertexData), (GLvoid *)offsetof(MLVertexData, texCoord));
glBindBuffer(GL_ARRAY_BUFFER, 0);
ccGLBindVAO(0);
CHECK_GL_ERROR();
_dirty = YES;
_nextFreeVertexIndex = 0;
}
return self;
}
-(void)dealloc
{
#ifdef __CC_PLATFORM_IOS
NSAssert([EAGLContext currentContext], #"No GL context set!");
#endif
free(_buffer); _buffer = NULL;
glDeleteBuffers(1, &_vbo); _vbo = 0;
glDeleteVertexArrays(1, &_vao); _vao = 0;
}
-(void)render
{
if( _dirty ) {
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(MLVertexData)*_bufferCapacity, _buffer, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
_dirty = NO;
}
ccGLBindVAO(_vao);
glDrawArrays(GL_TRIANGLES, 0, _bufferCount);
CC_INCREMENT_GL_DRAWS(1);
CHECK_GL_ERROR();
}
-(void)draw
{
_dirty = YES;
ccGLBlendFunc(_blendFunc.src, _blendFunc.dst);
[_shaderProgram use];
[_shaderProgram setUniformsForBuiltins];
[self render];
}
-(mlPolygonData)drawPolyWithVerts:(CGPoint *)verts count:(NSUInteger)count fillColor: (ccColor4F)fill borderWidth:(CGFloat)width borderColor:(ccColor4F)line;
{
[self ensureCapacity: count];
for (int i = 0; i < count; i++) {
MLVertexData newVertex = MLVertexDataMake(0.0, 0.0, verts[i].x, verts[i].y, mlColor4FMake(fill.r, fill.g, fill.b, fill.a));
_buffer[_nextFreeVertexIndex + i] = newVertex;
}
mlPolygonData polyData;
polyData.indexInBuffer = _nextFreeVertexIndex;
polyData.vertexCount = count;
polyData.vertexData = _buffer;
_nextFreeVertexIndex += count;
_bufferCount += count;
_dirty = YES;
return polyData;
}
-(void)clear
{
_bufferCount = 0;
_nextFreeVertexIndex = 0;
_dirty = YES;
}
#end
Basically, in my iOS app, i have a modal screen, in which i display some OpenGL ES graphics. I am able to enter and exit this modal screen 6 times, before the application crashes. I'm assuming this is a memory issue, but i'm stuck as to what and / or where.
Any help on this matter is incredibly appreciated.
In my OGLViewController:
#define OPENGL_ERROR_CHECK {GLuint error = glGetError(); ((error == GL_NO_ERROR) ? : NSLog(#"GL Error: %d", (error)));}
#interface OGLItemViewController : GLKViewController
#property (nonatomic) GLuint program;
// item ogl arrays + buffers
#property (nonatomic) NSInteger numOGLBuffers;
#property (nonatomic) GLuint* vertexArrays;
#property (nonatomic) GLuint* vertexBuffers;
// index buffer for ogl item vertices
#property (nonatomic) GLuint* indexBuffers;
#property (strong, nonatomic) EAGLContext *context;
#property (strong, nonatomic) GLKBaseEffect *effect;
#end
#implementation
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
OPENGL_ERROR_CHECK
glFinish(); // put this in here to make sure all previous calls have been finished
OPENGL_ERROR_CHECK
if (!self.context)
{
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *) self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.opaque = NO;
self.numOGLBuffers = 0;
self.vertexArrays = nil;
self.vertexBuffers = nil;
self.indexBuffers = nil;
}
- (void)setupGL
{
OPENGL_ERROR_CHECK
[EAGLContext setCurrentContext:self.context];
OPENGL_ERROR_CHECK
[self loadShaders];
OPENGL_ERROR_CHECK
self.effect = [[GLKBaseEffect alloc] init];
OPENGL_ERROR_CHECK
self.effect.light0.enabled = GL_TRUE;
OPENGL_ERROR_CHECK
self.effect.colorMaterialEnabled = GL_TRUE;
OPENGL_ERROR_CHECK
self.effect.lightModelTwoSided = GL_FALSE;
OPENGL_ERROR_CHECK
self.effect.light0.diffuseColor = GLKVector4Make(0.69f, 0.69f, 0.69f, 0.5f);
OPENGL_ERROR_CHECK
glEnable(GL_DEPTH_TEST);
OPENGL_ERROR_CHECK
Item *item = [GlobalStore sharedInstance].item
NSMutableArray *shells = item.geometry;
if (shells.count > 0)
{
_vertexArrays = malloc(shells.count * sizeof(GLuint));
_vertexBuffers = malloc(shells.count * sizeof(GLuint));
_indexBuffers = malloc(shells.count * sizeof(GLuint));
self.numOGLBuffers = shells.count;
for (int i = 0; i < shells.count; i++)
{
Geometry *geom = [shells objectAtIndex:i];
if (geom.vertexCount > 0)
{
GLuint vao = 0;
OPENGL_ERROR_CHECK
glGenVertexArraysOES(1, &vao);
OPENGL_ERROR_CHECK
glBindVertexArrayOES(vao);
OPENGL_ERROR_CHECK
_vertexArrays[i] = vao;
if (!geom.vertices)
{
[self displayError:-998]; // generic error codes that i've just canned in to see if any problems with these pointers
}
if (!geom.indices)
{
[self displayError:-997];
}
// create vertice buffer
GLuint vbo = 0;
glGenBuffers(1, &vbo);
OPENGL_ERROR_CHECK
glBindBuffer(GL_ARRAY_BUFFER, vbo);
OPENGL_ERROR_CHECK
glBufferData(GL_ARRAY_BUFFER, geom.vertexCount * sizeof(OGLVertices), geom.vertices, GL_STATIC_DRAW);
OPENGL_ERROR_CHECK
_vertexBuffers[i] = vbo;
// create index by buffer
GLuint ibo = 0;
glGenBuffers(1, &ibo);
OPENGL_ERROR_CHECK
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
OPENGL_ERROR_CHECK
glBufferData(GL_ELEMENT_ARRAY_BUFFER, geom.indexCount * sizeof(GLuint), geom.indices, GL_STATIC_DRAW);
OPENGL_ERROR_CHECK
_indexBuffers[i] = ibo;
// enable position, normal and colour attributes
glEnableVertexAttribArray(GLKVertexAttribPosition);
OPENGL_ERROR_CHECK
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Position));
OPENGL_ERROR_CHECK
glEnableVertexAttribArray(GLKVertexAttribNormal);
OPENGL_ERROR_CHECK
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Normal));
OPENGL_ERROR_CHECK
glEnableVertexAttribArray(GLKVertexAttribColor);
OPENGL_ERROR_CHECK
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(OGLVertices), (const GLvoid *) offsetof(OGLVertices, Colour));
OPENGL_ERROR_CHECK
}
}
glBindVertexArrayOES(0);
OPENGL_ERROR_CHECK
}
}
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
self.effect = nil;
[self deleteOGLData];
}
- (void)dealloc
{
[self tearDownGL];
if ([EAGLContext currentContext] == self.context)
{
[EAGLContext setCurrentContext:nil];
}
}
- (void) viewDidDisappear:(BOOL)animated
{
[self tearDownGL];
}
- (void)deleteOGLData
{
// delete ogl buffers and arrays
if (self.numOGLBuffers > 0)
{
if (_vertexBuffers)
{
OPENGL_ERROR_CHECK
glDeleteBuffers(self.numOGLBuffers, _vertexBuffers);
OPENGL_ERROR_CHECK
free(_vertexBuffers);
_vertexBuffers = nil;
}
if (_vertexArrays)
{
glDeleteVertexArraysOES(self.numOGLBuffers, _vertexArrays);
OPENGL_ERROR_CHECK
free(_vertexArrays);
_vertexArrays = nil;
}
if (_indexBuffers)
{
glDeleteBuffers(self.numOGLBuffers, _indexBuffers);
OPENGL_ERROR_CHECK
free(_indexBuffers);
_indexBuffers = nil;
}
}
self.numOGLBuffers = 0;
glDeleteProgram(self.program);
OPENGL_ERROR_CHECK
self.program = 0;
glFinish(); // again, just put this in here to check everything has finished
OPENGL_ERROR_CHECK
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
OPENGL_ERROR_CHECK
glClearColor(1.0, 1.0, 1.0, 0.0);
OPENGL_ERROR_CHECK
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
OPENGL_ERROR_CHECK
// Render the object with GLKit
[self.effect prepareToDraw];
OPENGL_ERROR_CHECK
NSMutableArray *shells = [GlobalStore sharedInstance].item.geometry;
if (shells && _vertexArrays && _vertexBuffers)
{
for (int i = 0; i < shells.count; i++)
{
Geometry *geom = [shells objectAtIndex:i];
if (geom.vertexCount > 0)
{
GLuint vao = self.vertexArrays[i];
glBindVertexArrayOES(vao);
OPENGL_ERROR_CHECK
if(geom.indexCount == 0)
[self displayError:-996];
glDrawElements(GL_TRIANGLES, geom.indexCount, GL_UNSIGNED_INT, 0);
OPENGL_ERROR_CHECK
self.initialised = YES;
}
}
}
}
- (BOOL)loadShaders
{
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
self.program = glCreateProgram();
OPENGL_ERROR_CHECK
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:#"Shader" ofType:#"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
{
NSLog(#"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:#"Shader" ofType:#"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname])
{
NSLog(#"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(_program, vertShader);
OPENGL_ERROR_CHECK
// Attach fragment shader to program.
glAttachShader(_program, fragShader);
OPENGL_ERROR_CHECK
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
OPENGL_ERROR_CHECK
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
OPENGL_ERROR_CHECK
// Link program.
if (![self linkProgram:_program])
{
NSLog(#"Failed to link program: %d", _program);
if (vertShader)
{
glDeleteShader(vertShader);
OPENGL_ERROR_CHECK
vertShader = 0;
}
if (fragShader)
{
glDeleteShader(fragShader);
OPENGL_ERROR_CHECK
fragShader = 0;
}
if (_program)
{
glDeleteProgram(_program);
OPENGL_ERROR_CHECK
_program = 0;
}
return NO;
}
// Get uniform locations.
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");
// Release vertex and fragment shaders.
if (vertShader)
{
glDetachShader(_program, vertShader);
OPENGL_ERROR_CHECK
glDeleteShader(vertShader);
OPENGL_ERROR_CHECK
}
if (fragShader)
{
glDetachShader(_program, fragShader);
OPENGL_ERROR_CHECK
glDeleteShader(fragShader);
OPENGL_ERROR_CHECK
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
GLint status;
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source)
{
NSLog(#"Failed to load vertex shader");
return NO;
}
*shader = glCreateShader(type);
OPENGL_ERROR_CHECK
glShaderSource(*shader, 1, &source, NULL);
OPENGL_ERROR_CHECK
glCompileShader(*shader);
OPENGL_ERROR_CHECK
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
OPENGL_ERROR_CHECK
if (status == 0)
{
glDeleteShader(*shader);
OPENGL_ERROR_CHECK
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog
{
GLint status;
glLinkProgram(prog);
OPENGL_ERROR_CHECK
glGetProgramiv(prog, GL_LINK_STATUS, &status);
OPENGL_ERROR_CHECK
if (status == 0)
{
return NO;
}
return YES;
}
- (BOOL)validateProgram:(GLuint)prog
{
GLint logLength, status;
glValidateProgram(prog);
OPENGL_ERROR_CHECK
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
OPENGL_ERROR_CHECK
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
OPENGL_ERROR_CHECK
NSLog(#"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
OPENGL_ERROR_CHECK
if (status == 0)
{
return NO;
}
return YES;
}
-(void)displayError: (GLuint) err
{
NSString *msg = [[NSString alloc] initWithFormat:#"OpenGL Error: %d", err];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Error"
message: msg
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
#end
Now - i don't know if it's the right way to do this, but in the viewdiddisappear method, i make sure to delete all the ogl data. i wanted to make sure that when i exited the view, the ogl data is deleted from memory.
So, if i enter the modal view, exit, and repeat 5 more times, i will get a black screen crash, and will break, with the following screen:
I have made sure everything is done in a single thread where appropriate. I have tried to make sure all objects and buffers are deleted.
So i'm wondering what on earth am i doing wrong to cause it to suddenly crash..... Nothing in the profiler seems to indicate anything. I don't seem to have any memory leaks or anything too substantial that would cause memory to run out.
( i do know i'm rendering every frame, when i dont need to - i will address this at a later point.)
The globalstore i have holds an instance of some objects that i use. These should always be valid (i've checked).
What i needed to do, was to delete the GLKView drawables.
In the ViewDidDisappear method (might not be the proper place, but it works) add the following:
GLKView *view = (GLKView*) self.view;
[view deleteDrawable];
I use Xcode 4.4 and I develope app for iOS 5.1 with ARC. I have a thread (other than main) that invokes periodically method below.
- (void)updateLabels:(NSTimeInterval)timeSinceLastUpdate
{
int lastTime = self.time;
self.scoreScale -= ((self.scoreScale-1)/5);
self.time -= timeSinceLastUpdate;
if (self.time <= 0) {
self.time = 0.0;
}
if (lastTime != (int) self.time) {
self.timeChanged = YES;
}
#autoreleasepool {
NSString *timeString = [NSString stringWithFormat:#"%.2d:%.2d",(int)(self.time/60),((int)self.time%60)]; //leak!!!
if (self.scoreScale <=1) self.scoreScale = 1;
GLKBaseEffect *scoreValueEffect = [self.sprites objectForKey:#"score_value"];
if (self.scoreChanged) {
scoreValueEffect = [[ILUtils sharedInstance] makeEffectWithString:[NSString stringWithFormat:#"%#",self.score] alignment:UITextAlignmentLeft fontName:#"WetLetters EFN" fontSize:20 withViewSize:self.view.bounds.size withRect:CGRectMake(935, 50, 100, 30)];
}
scoreValueEffect.transform.modelviewMatrix = [[ILUtils sharedInstance] setupSpriteModelviewMatrixWithViewRect:CGRectMake(955, 46-(30*self.scoreScale-30)/2, 100*self.scoreScale, 30*self.scoreScale)];
[self.sprites setObject:scoreValueEffect forKey:#"score_value"];
if (self.timeChanged) {
GLKBaseEffect *timeValueEffect = [[ILUtils sharedInstance] makeEffectWithString:timeString alignment:UITextAlignmentLeft fontName:#"WetLetters EFN" fontSize:24 withViewSize:self.view.bounds.size withRect:CGRectMake(955, 75, 100, 30)];
[self.sprites setObject:timeValueEffect forKey:#"time_value"];
}
}
}
When I use Instruments I can see that memory usage increases in time. When I comment out line creating string memory usage is stable. I also tried to create string with alloc & init methods, but it didn't helped. I've found similiar thread in https://stackoverflow.com/questions/ask?title=#autoreleasepool%20not%20working but enabling/disabling NSZombieEnabled option makes no difference.
I can't figure out why all these strings are not deallocated though I use #autorelease block as said in https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html.
Did I miss something?
Thanks.
//EDIT
Stuff invoked by makeEffectWithString:
- (GLKBaseEffect*)makeEffectWithString:(NSString*)string alignment:(UITextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size withViewSize:(CGSize)viewSize withRect:(CGRect)rect
{
GLKBaseEffect *effect = [[GLKBaseEffect alloc] init];
effect.texture2d0.enabled = YES;
effect.texture2d0.name = [self textureWithString:string dimensions:rect.size alignment:alignment fontName:name fontSize:size].name;
effect.transform.projectionMatrix = [self setupOrthoProjectionMatrixWithViewSize:viewSize];
effect.transform.modelviewMatrix = [[ILUtils sharedInstance] setupSpriteModelviewMatrixWithViewRect:rect];
effect.useConstantColor = YES;
effect.constantColor = GLKVector4Make(0.7f,0.7f,0.7f,0.7f);
return effect;
}
- (GLKTextureInfo*)textureWithString:(NSString*)string dimensions:(CGSize)dimensions alignment:(UITextAlignment)alignment fontName:(NSString*)name fontSize:(CGFloat)size
{
UIFont *font = [UIFont fontWithName:name size:size];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate(nil, dimensions.width, dimensions.height, 8, dimensions.width, colorSpace, kCGImageAlphaOnly);
CGColorSpaceRelease(colorSpace);
CGContextSetGrayFillColor(context, 1.0, 1.0);
UIGraphicsPushContext(context);
[string drawInRect:CGRectMake(0, 0, dimensions.width, dimensions.height) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:alignment];
UIGraphicsPopContext();
NSMutableDictionary *options = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:GLKTextureLoaderOriginBottomLeft];
GLKTextureInfo *texture = [GLKTextureLoader textureWithCGImage:CGBitmapContextCreateImage(context) options:options error:nil];
CGContextRelease(context);
return texture;
}
//EDIT
- (void)drawSpriteUsingEffect:(GLKBaseEffect*)effect
{
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 20, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 20, BUFFER_OFFSET(12));
[effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
You can use the Allocations instruments to "Mark Heap". This seems to have some instructions on how to debug such memory issues.
I have for example following code (just as example, I'm building not game, I'm trying to build KNOB control by OpenGL ES, Quartz2D not does not fit, do not ask why):
Original code from here:
http://www.raywenderlich.com/9743/how-to-create-a-simple-2d-iphone-game-with-opengl-es-2-0-and-glkit-part-1
Code drawing following images on the screen, in future I'll replace this images by my KNOB:
Basically I interested to rotate only Player (the man in the left area).
I want him to rotate continuously from 0 to 360 degrees. I tried following code, but...
self.effect.transform.modelviewMatrix = GLKMatrix4Rotate(self.effect.transform.modelviewMatrix, radians(10), 0, 0, -1);
I give full screen rotating (with monsters also), but I want to rotate only one object (in this example only player in left area). Also want to note that the monsters are moving.
The code for function [sprite render]; see below.
Here is main code:
//
// SGGViewController.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGViewController.h"
#import "SGGSprite.h"
#interface SGGViewController ()
#property (strong, nonatomic) EAGLContext *context;
#property (strong) GLKBaseEffect * effect;
#property (strong) SGGSprite * player;
#property (strong) NSMutableArray * children;
#property (assign) float timeSinceLastSpawn;
#end
#implementation SGGViewController
#synthesize effect = _effect;
#synthesize context = _context;
#synthesize player = _player;
#synthesize children = _children;
#synthesize timeSinceLastSpawn = _timeSinceLastSpawn;
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, 1024, 0, 768, -1, 1);
self.effect.transform.projectionMatrix = projectionMatrix;
self.player = [[SGGSprite alloc] initWithFile:#"2.png" effect:self.effect];
self.player.position = GLKVector2Make(self.player.contentSize.width/2, 160);
self.children = [NSMutableArray array];
[self.children addObject:self.player];
}
- (void)addTarget {
SGGSprite * target = [[SGGSprite alloc] initWithFile:#"Target.png" effect:self.effect];
[self.children addObject:target];
int minY = target.contentSize.height/2;
int maxY = 320 - target.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
target.position = GLKVector2Make(480 + (target.contentSize.width/2), actualY);
int minVelocity = 480.0/4.0;
int maxVelocity = 480.0/2.0;
int rangeVelocity = maxVelocity - minVelocity;
int actualVelocity = (arc4random() % rangeVelocity) + minVelocity;
target.moveVelocity = GLKVector2Make(-actualVelocity, 0);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#pragma mark - GLKViewDelegate
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (SGGSprite * sprite in self.children) {
[sprite render];
}
}
- (void)update {
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
if (self.timeSinceLastSpawn > 1.0) {
self.timeSinceLastSpawn = 0;
[self addTarget];
}
for (SGGSprite * sprite in self.children) {
[sprite update:self.timeSinceLastUpdate];
}
}
#end
This is code for function [sprite render];
//
// SGGSprite.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGSprite.h"
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
#interface SGGSprite()
#property (strong) GLKBaseEffect * effect;
#property (assign) TexturedQuad quad;
#property (strong) GLKTextureInfo * textureInfo;
#end
#implementation SGGSprite
#synthesize position = _position;
#synthesize contentSize = _contentSize;
#synthesize effect = _effect;
#synthesize quad = _quad;
#synthesize textureInfo = _textureInfo;
#synthesize moveVelocity = _moveVelocity;
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect {
if ((self = [super init])) {
self.effect = effect;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfo == nil) {
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSize = CGSizeMake(self.textureInfo.width, self.textureInfo.height);
TexturedQuad newQuad;
newQuad.bl.geometryVertex = CGPointMake(0, 0);
newQuad.br.geometryVertex = CGPointMake(self.textureInfo.width, 0);
newQuad.tl.geometryVertex = CGPointMake(0, self.textureInfo.height);
newQuad.tr.geometryVertex = CGPointMake(self.textureInfo.width, self.textureInfo.height);
newQuad.bl.textureVertex = CGPointMake(0, 0);
newQuad.br.textureVertex = CGPointMake(1, 0);
newQuad.tl.textureVertex = CGPointMake(0, 1);
newQuad.tr.textureVertex = CGPointMake(1, 1);
self.quad = newQuad;
}
return self;
}
- (GLKMatrix4) modelMatrix {
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0);
modelMatrix = GLKMatrix4Translate(modelMatrix, -self.contentSize.width/2, -self.contentSize.height/2, 0);
return modelMatrix;
}
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)render {
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)update:(float)dt {
GLKVector2 curMove = GLKVector2MultiplyScalar(self.moveVelocity, dt);
self.position = GLKVector2Add(self.position, curMove);
}
#end
In this example you share the same functions to draw the player, the target, and the background.
You have to define a new effect and matrix independently for the player to apply a separate effect like rotation.
For example, here it is for SGGViewController.m:
//
// SGGViewController.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGViewController.h"
#import "SGGSprite.h"
float _rotation;
#interface SGGViewController ()
#property (strong, nonatomic) EAGLContext *context;
#property (strong) GLKBaseEffect * effect;
#property (strong) GLKBaseEffect * effectPlayer; //Added For The Player
#property (strong) SGGSprite * player;
#property (strong) NSMutableArray * children;
#property (strong) NSMutableArray * childrenPlayer; //Added For The Player
#property (assign) float timeSinceLastSpawn;
#end
#implementation SGGViewController
#synthesize effect = _effect;
#synthesize effectPlayer = _effectPlayer;
#synthesize context = _context;
#synthesize player = _player;
#synthesize children = _children;
#synthesize childrenPlayer = _childrenPlayer;
#synthesize timeSinceLastSpawn = _timeSinceLastSpawn;
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
//--------------------This Is To Define Effect For The background-------------------
self.effect = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, 480, 0, 320, -1024, 1024);
self.effect.transform.projectionMatrix = projectionMatrix;
//----------------------------------------------------------------------------------
//--------This One For The Player ---------
self.effectPlayer = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrixPlay = GLKMatrix4MakeOrtho(0, 480, 0, 320, -1024, 1024);
self.effectPlayer.transform.projectionMatrix = projectionMatrixPlay;
//----------------------------------------------------------------------------------
//----Note Here I Have Uses Another Separate Function To Init The Texture File----
self.player = [[SGGSprite alloc] initWithFilePlayer:#"2.png" effectPlayer:self.effectPlayer];
self.player.positionPlayer = GLKVector2Make(self.player.contentSizePlayer.width/2, 160);
//--The Array Setting For Target And Anything Else (Background, Splash, Etc.)---
self.children = [NSMutableArray array];
//---And This Is The Array Setting For The Player---
self.childrenPlayer = [NSMutableArray array];
[self.childrenPlayer addObject:self.player];
}
//-----While The Target As Usual--------
- (void)addTarget
{
SGGSprite * target = [[SGGSprite alloc] initWithFile:#"Target.png" effect:self.effect];
[self.children addObject:target];
int minY = target.contentSize.height/2;
int maxY = 320 - target.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
target.position = GLKVector2Make(480 + (target.contentSize.width/2), actualY);
int minVelocity = 480.0/4.0;
int maxVelocity = 480.0/2.0;
int rangeVelocity = maxVelocity - minVelocity;
int actualVelocity = (arc4random() % rangeVelocity) + minVelocity;
target.moveVelocity = GLKVector2Make(-actualVelocity, 0);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#pragma mark - GLKViewDelegate
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (SGGSprite * sprite in self.children) {
[sprite render];
}
//--------Separate Rendering For The Player In A New Function RenderPlayer-----------
for (SGGSprite * sprite in self.childrenPlayer) {
[sprite renderPlayer];
}
}
- (void)update
{
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
_rotation += self.timeSinceLastUpdate * 20; //Speed And Angle Of Rotation
if (self.timeSinceLastSpawn > 1.0) {
self.timeSinceLastSpawn = 0;
[self addTarget];
}
for (SGGSprite * sprite in self.children)
{
[sprite update:self.timeSinceLastUpdate];
}
//---Another One For The Player Note Theres A New Function Called updatePlayer---
for (SGGSprite * sprite in self.childrenPlayer)
{
[sprite updatePlayer:self.timeSinceLastUpdate rotationPlayer:_rotation];
}
}
#end
And Now For SGGSprite.m
//
// SGGSprite.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGSprite.h"
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
typedef struct {
CGPoint geometryVertexPlayer;
CGPoint textureVertexPlayer;
} TexturedVertexPlayer;
typedef struct {
TexturedVertexPlayer bl;
TexturedVertexPlayer br;
TexturedVertexPlayer tl;
TexturedVertexPlayer tr;
} TexturedQuadPlayer;
#interface SGGSprite()
#property (strong) GLKBaseEffect * effect;
#property (strong) GLKBaseEffect * effectPlayer; //Added
#property (assign) TexturedQuad quad;
#property (strong) GLKTextureInfo * textureInfo;
#property (assign) TexturedQuadPlayer quadPlayer; //Added
#property (strong) GLKTextureInfo * textureInfoPlayer; //Added
#end
#implementation SGGSprite
#synthesize position = _position;
#synthesize positionPlayer = _positionPlayer; //Added
#synthesize contentSize = _contentSize;
#synthesize contentSizePlayer = _contentSizePlayer; //Added
#synthesize effect = _effect;
#synthesize effectPlayer = _effectPlayer; //Added
#synthesize quad = _quad;
#synthesize quadPlayer = _quadPlayer; //Added
#synthesize textureInfo = _textureInfo;
#synthesize moveVelocity = _moveVelocity;
#synthesize textureInfoPlayer = _textureInfoPlayer; //Added
#synthesize moveVelocityPlayer = _moveVelocityPlayer; //Added
int moved = 0; // to make sure the game just started
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect
{
if ((self = [super init]))
{
self.effect = effect;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfo == nil)
{
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSize = CGSizeMake(self.textureInfo.width, self.textureInfo.height);
TexturedQuad newQuad;
newQuad.bl.geometryVertex = CGPointMake(0, 0);
newQuad.br.geometryVertex = CGPointMake(self.textureInfo.width, 0);
newQuad.tl.geometryVertex = CGPointMake(0, self.textureInfo.height);
newQuad.tr.geometryVertex = CGPointMake(self.textureInfo.width, self.textureInfo.height);
newQuad.bl.textureVertex = CGPointMake(0, 0);
newQuad.br.textureVertex = CGPointMake(1, 0);
newQuad.tl.textureVertex = CGPointMake(0, 1);
newQuad.tr.textureVertex = CGPointMake(1, 1);
self.quad = newQuad;
}
return self;
}
//----------The Init Function For The Player Only-------------
- (id)initWithFilePlayer:(NSString *)fileName effectPlayer:(GLKBaseEffect *)effectPlayer
{
if ((self = [super init]))
{
self.effectPlayer = effectPlayer;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfoPlayer = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfoPlayer == nil)
{
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSizePlayer = CGSizeMake(self.textureInfoPlayer.width, self.textureInfoPlayer.height);
TexturedQuadPlayer newQuad;
newQuad.bl.geometryVertexPlayer = CGPointMake(0, 0);
newQuad.br.geometryVertexPlayer = CGPointMake(self.textureInfoPlayer.width, 0);
newQuad.tl.geometryVertexPlayer = CGPointMake(0, self.textureInfoPlayer.height);
newQuad.tr.geometryVertexPlayer = CGPointMake(self.textureInfoPlayer.width, self.textureInfoPlayer.height);
newQuad.bl.textureVertexPlayer = CGPointMake(0, 0);
newQuad.br.textureVertexPlayer = CGPointMake(1, 0);
newQuad.tl.textureVertexPlayer = CGPointMake(0, 1);
newQuad.tr.textureVertexPlayer = CGPointMake(1, 1);
self.quadPlayer = newQuad;
}
return self;
}
- (GLKMatrix4) modelMatrix
{
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0);
modelMatrix = GLKMatrix4Translate(modelMatrix, -self.contentSize.width/2, -self.contentSize.height/2, 0);
return modelMatrix;
}
//-------------Added For The Player-----------------
- (GLKMatrix4) modelMatrixPlayer
{
GLKMatrix4 modelMatrixPlayer = GLKMatrix4Identity;
modelMatrixPlayer = GLKMatrix4Translate(modelMatrixPlayer, self.positionPlayer.x, self.positionPlayer.y, 0);
modelMatrixPlayer = GLKMatrix4Translate(modelMatrixPlayer, -self.contentSizePlayer.width/2, -self.contentSizePlayer.height/2, 0);
return modelMatrixPlayer;
}
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)render
{
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)renderPlayer
{
self.effectPlayer.texture2d0.name = self.textureInfoPlayer.name;
self.effectPlayer.texture2d0.enabled = YES;
if (moved == 0) // Only Applied When You Restart Game To Position The Player In The Center
{
self.effectPlayer.transform.modelviewMatrix = self.modelMatrixPlayer;
}
[self.effectPlayer prepareToDraw];
long offset = (long)&_quadPlayer;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertexPlayer), (void *) (offset + offsetof(TexturedVertexPlayer, geometryVertexPlayer)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertexPlayer), (void *) (offset + offsetof(TexturedVertexPlayer, textureVertexPlayer)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)update:(float)dt
{
GLKVector2 curMove = GLKVector2MultiplyScalar(self.moveVelocity, dt);
self.position = GLKVector2Add(self.position, curMove);
}
// ------------- Rotate The Object --------------------------------------------
- (void)updatePlayer:(float)rt rotationPlayer:(float)rotate
{
moved = 1;
self.effectPlayer.transform.modelviewMatrix = self.modelMatrixPlayer; //Adjust the player Location And Ready To Move
//Moving The Object
GLKVector2 curRotate = GLKVector2MultiplyScalar(self.moveVelocityPlayer, rt);
self.positionPlayer = GLKVector2Add(self.positionPlayer, curRotate);
//Rotation Section
self.effectPlayer.transform.modelviewMatrix = GLKMatrix4Rotate(self.effectPlayer.transform.modelviewMatrix, rotate, 0, 0, -1);
}
#end
Well Thats Not Everything Here Is The SGGSprite.h
//
// SGGSprite.h
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#interface SGGSprite : NSObject
#property (assign) GLKVector2 position;
#property (assign) GLKVector2 positionPlayer; //Position For The Player
#property (assign) CGSize contentSize;
#property (assign) CGSize contentSizePlayer; //Size Of The Player
#property (assign) GLKVector2 moveVelocity;
#property (assign) GLKVector2 moveVelocityPlayer; //Speed Of The Player If Moved
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect;
- (id)initWithFilePlayer:(NSString *)fileName effectPlayer:(GLKBaseEffect *)effectPlayer;
- (void)render;
- (void)renderPlayer;
- (void)update:(float)dt; //Move Object
- (void)updatePlayer:(float)rt rotationPlayer:(float)rotate; //Rotate Object
#end