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
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 have the following source code where i can draw some objects to the screen but i want to rotate and scale the drawed object and nothing happens when i am touching the screen. (In the log i can see if i am doing a pan gesture or a pinch gesture so the detection is ok)
What am i doing wrong?
UPDATE
Now it moves (instead of rotation) maybe i rotate it not around the center of the pointcloud. I tried to move it to center but now nothing is on the screen. Here is the updated Code:
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import "EAGLView.h"
#import "VertexPoint.h"
#import "CamOnMap-Swift.h"
#import <Math.h>
#define USE_DEPTH_BUFFER 1
#define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI)
// A class extension to declare private methods
#interface EAGLView ()
#property (nonatomic, retain) EAGLContext *context;
//#property (nonatomic, assign) NSTimer *animationTimer;
- (BOOL) createFramebuffer;
- (void) destroyFramebuffer;
#end
#implementation EAGLView
#synthesize context;
//#synthesize animationTimer;
//#synthesize animationInterval;
// You must implement this method
+ (Class)layerClass {
return [CAEAGLLayer class];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
NSLog(#"Ide eljutottam ez az initWithCoder");
TOUCH_ROT_FACTOR = (180.0 / 320.0);
if ((self = [super initWithCoder:aDecoder])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
//[self release];
return nil;
}
// animationInterval = 1.0 / 60.0;
[self setupView];
}
return self;
}
- (void)setupView {
const GLfloat zNear = 0.1, zFar = 1000.0, fieldOfView = 60.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
//Grab the size of the screen
CGRect rect = self.frame;
glFrustumf(-size, size,
-size / (rect.size.width / rect.size.height),
size / (rect.size.width / rect.size.height),
zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
//Initialize touchLocation to 0, 0
// touchLocation = CGPointMake(rect.size.width/2, rect.size.height/2);
// touchLocation = CGPointMake(0, 0);
// GLfloat x = (touchLocation.x);
// GLfloat y = (touchLocation.y);
//translate the triangle
// glTranslatef(x, y, -10.0);
multitouch_distance_start = 0;
viewDistance = -100;
[self setupGestures];
[self getPly];
}
- (void)setupGestures{
[self setUserInteractionEnabled:true];
[self setMultipleTouchEnabled:true];
pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchHandler:)];
panGesture =[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panHandler:)];
[self addGestureRecognizer:pinchGesture];
[self addGestureRecognizer:panGesture];
};
-(VertexPoint*)center:(NSMutableArray *)vertices2{
float sum_x =0.0f;
float sum_y =0.0f;
float sum_z =0.0f;
for (int i=0; i<vertices2.count; i++) {
VertexPoint *point =vertices2[i];
sum_x +=point.x;
sum_y +=point.y;
sum_z +=point.z;
}
center_ = [[VertexPoint alloc] init];
GLfloat point[] = {(sum_x / vertices2.count),(sum_y / vertices2.count), (sum_z / vertices2.count)};
[center_ setPosition:point];
return center_;
}
-(float)multiTouchDistance:(UIPinchGestureRecognizer *) recognizer{
float x1 = [recognizer locationOfTouch:0 inView:self].x;
float y1 = [recognizer locationOfTouch:0 inView:self].y;
float x2 = [recognizer locationOfTouch:1 inView:self].x;
float y2 = [recognizer locationOfTouch:1 inView:self].y;
float dx = x2 - x1;
float dy = y2 - y1;
return sqrt(dx*dx + dy*dy);
}
- (void)pinchHandler:(UIPinchGestureRecognizer *)recognizer {
glPopMatrix();
float d = [self multiTouchDistance:recognizer];
NSLog(#"d: %f",d);
if(d > 0.0f)multitouch_distance_start = d;
viewDistance *= multitouch_distance_start / d;
multitouch_distance_start = d;
//glScalef(recognizer.scale, recognizer.scale, recognizer.scale);
//recognizer.scale = 1;
NSLog(#"viewDistance: %f",viewDistance);
glPushMatrix();
[self render];
}
- (void)panHandler:(UIPanGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateBegan){
CGPoint translation = [recognizer translationInView:self];
xPrev = translation.x;
yPrev = translation.y;
}
if(recognizer.state == UIGestureRecognizerStateChanged){
glPopMatrix();
CGPoint translation = [recognizer translationInView:self];
GLfloat dx = translation.x - xPrev;
GLfloat dy = translation.y - yPrev;
xAngle += ((dx) * (TOUCH_ROT_FACTOR));
yAngle += ((dy) * (TOUCH_ROT_FACTOR));
// glRotatef(xAngle,1,0,0);
// glRotatef(yAngle,0,1,0);
xPrev = translation.x;
yPrev = translation.y;
glPushMatrix();
NSLog(#"pan");
[self render];
}
};
-(void)completionHandler:(NSString *) data{
// NSLog(#"%#",data);
NSArray *dataArray = [data componentsSeparatedByString:#"\n"];
vertices = [[NSMutableArray alloc] init];
for(NSInteger i = 14; i < dataArray.count; i++ ){
NSArray *row = [dataArray[i] componentsSeparatedByString:#" "];
if(![dataArray[i] isEqual: #""]){
VertexPoint *point = [[VertexPoint alloc] init];
GLfloat a[] = { [[row objectAtIndex:0] floatValue], [[row objectAtIndex:1] floatValue], [[row objectAtIndex:2] floatValue]};
[point setPosition:a];
GLfloat b[] = { [[row objectAtIndex:6] floatValue],[[row objectAtIndex:7] floatValue], [[row objectAtIndex:8] floatValue], [[row objectAtIndex:9] floatValue]};
[point setColor:b];
[vertices addObject:point];
}
}
long vcount = [vertices count] * 3; // * 2 for the two coordinates of a loc object
glVertices = (GLfloat *)malloc(vcount * sizeof(GLfloat));
int currIndex = 0;
for (VertexPoint *loc in vertices) {
glVertices[currIndex++] = (loc.x);
glVertices[currIndex++] =(loc.y);
glVertices[currIndex++] =(loc.z);
}
long ccount = [vertices count] * 4;
glColors = (GLfloat *)malloc(ccount * sizeof(GLfloat));
int currColorIndex = 0;
for(VertexPoint *color in vertices){
glColors[currColorIndex++] = (color.r);
glColors[currColorIndex++] = (color.g);
glColors[currColorIndex++] = (color.b);
glColors[currColorIndex++] = (color.a);
}
center_ = [self center: vertices];
glTranslatef(0, 0, -100);
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
NSLog(#"x: %f, y: %f, z:%f",-1 * center_.x,-1 * center_.y,-1 * center_.z);
[self drawView];
};
-(void)getPly{
GlobalDataFunctions *globalDataFunctions = [[GlobalDataFunctions alloc] init];
NSString *ply = [globalDataFunctions selectedPly];
NSLog(#"%#",ply);
RestClient *restClient = [[RestClient alloc] init];
NSString *username = [[NSUserDefaults standardUserDefaults] objectForKey:#"username"];
NSString *password = [[NSUserDefaults standardUserDefaults] objectForKey:#"password"];
[restClient getPly: username password:password ply:ply myComletionHandler: ^(NSString *data){
[self completionHandler:data];
}];
};
- (void)drawView {
NSLog(#"drawView");
//setting up the draw content
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
//Draw stuff
//reset matrix to identity
glLoadIdentity();
//rough approximation of screen to current 3D space
GLfloat x = (touchLocation.x - 160.0) / 38.0;
GLfloat y = (240.0 - touchLocation.y) / 38.0;
//translate the triangle
glTranslatef(x, y, -1.0);
[self render];
}
-(void)render{
NSLog(#"render");
center_ = [self center: vertices];
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
//clear the back color back to our original color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//rough approximation of screen to current 3D space
//set the format and location for verticies
glVertexPointer(3, GL_FLOAT, 0, glVertices);
//set the opengl state
glEnableClientState(GL_VERTEX_ARRAY);
//set the format and location for colors
glColorPointer(4, GL_FLOAT, 0, glColors);
//set the opengl state
glEnableClientState(GL_COLOR_ARRAY);
glPointSize(3);
//draw the triangles
// glTranslatef(0,0,viewDistance);
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
glDrawArrays(GL_POINTS, 0, vertices.count);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
//show the render buffer
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
touchLocation = [touch locationInView:self];
NSLog(#"touch");
[self drawView];
}
- (void)layoutSubviews {
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
[self drawView];
}
- (BOOL)createFramebuffer {
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
if (USE_DEPTH_BUFFER) {
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
}
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer);
viewFramebuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
viewRenderbuffer = 0;
if(depthRenderbuffer) {
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
depthRenderbuffer = 0;
}
}
And here can you find a sample input data: http://pastebin.com/rcrfZdyt
I can't figure out what happens when I'm starting recording with GPUImageMovieWriter. While it's just preview everything is OK, but when I'm pressing record button my filter breaks up. I can't find how GPUImageMovieWriter changing my filter, help me.
My start record action:
- (void)cameraButton:(id)sender
{
// Recording.
NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Movie.m4v"];
unlink([pathToMovie UTF8String]);
NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
self.movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(1080.0, 1920.0)];
self.movieWriter.encodingLiveVideo = YES;
self.movieWriter.shouldPassthroughAudio = YES;
[self.blendFilter addTarget:self.movieWriter];
self.videoCamera.audioEncodingTarget = self.movieWriter;
// Start recording.
[self.movieWriter startRecording];
double delayInSeconds = 10.0;
dispatch_time_t stopTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(stopTime, dispatch_get_main_queue(), ^(void){
[self.blendFilter removeTarget:self.movieWriter];
self.videoCamera.audioEncodingTarget = nil;
[self.movieWriter finishRecording];
UISaveVideoAtPathToSavedPhotosAlbum(pathToMovie, nil, NULL, NULL);
NSLog(#"Movie completed");
});
}
My filter cropping input image by shape which is uniform sampler2D shape.
My filter code:
#import "GPUImageShapeCropFilter.h"
NSString *const kGPUImageShapeCropShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform highp float aspectRatio;
uniform highp vec2 center;
uniform highp float radius;
uniform highp float scale;
uniform sampler2D shape;
void main()
{
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
lowp vec4 shapeColor = texture2D(shape, textureCoordinateToUse);
textureCoordinateToUse = textureCoordinate;
textureCoordinateToUse -= center;
textureCoordinateToUse = textureCoordinateToUse * scale;
textureCoordinateToUse += center;
if (shapeColor.w > 0.0) {
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinateToUse);
textureColor.w = shapeColor.w;
gl_FragColor = textureColor;
} else {
gl_FragColor = shapeColor;
}
}
);
#interface GPUImageShapeCropFilter ()
{
GLint _aspectRatioUniform;
GLint _radiusUniform;
GLint _centerUniform;
GLint _scaleUniform;
GLuint _oldTextureIndex;
}
- (void)adjustAspectRatio;
#property (readwrite, nonatomic) CGFloat aspectRatio;
#end
#implementation GPUImageShapeCropFilter
#synthesize aspectRatio = _aspectRatio;
#synthesize center = _center;
#synthesize radius = _radius;
#synthesize scale = _scale;
#pragma mark -
#pragma mark Initialization and teardown
- (id)init
{
self = [super initWithFragmentShaderFromString:kGPUImageShapeCropShaderString];
if (!self) {
return nil;
}
// Get uniforms.
_aspectRatioUniform = [filterProgram uniformIndex: #"aspectRatio"];
_radiusUniform = [filterProgram uniformIndex: #"radius"];
_scaleUniform = [filterProgram uniformIndex: #"scale"];
_centerUniform = [filterProgram uniformIndex: #"center"];
// Set default values.
self.scale = 0.5;
self.center = CGPointMake(0.5, 0.5);
[self setShape:[UIImage imageNamed:#"circle"]];
return self;
}
- (void)setShape:(UIImage *)shape
{
[self setTexture:shape forUniform:#"shape"];
}
- (void)setTexture:(UIImage *)image forUniform:(NSString *)uniform
{
// Find texture size.
CGSize sizeOfImage = [image size];
CGFloat scaleOfImage = [image scale];
CGSize pixelSizeOfImage = CGSizeMake(scaleOfImage * sizeOfImage.width, scaleOfImage * sizeOfImage.height);
// Create context.
GLubyte * spriteData = (GLubyte *)malloc(pixelSizeOfImage.width * pixelSizeOfImage.height * 4 * sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, pixelSizeOfImage.width, pixelSizeOfImage.height, 8, pixelSizeOfImage.width * 4, CGImageGetColorSpace(image.CGImage), (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
// Draw image into context.
CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, pixelSizeOfImage.width, pixelSizeOfImage.height), image.CGImage);
// Get uniform of texture
GLuint uniformIndex = [filterProgram uniformIndex:uniform];
// Generate texture.
GLuint textureIndex;
glGenTextures(1, &textureIndex);
glBindTexture(GL_TEXTURE_2D, textureIndex);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelSizeOfImage.width, pixelSizeOfImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureIndex);
// "Send" to shader.
glUniform1i(uniformIndex, 1);
// Remove old texture if it is.
if (_oldTextureIndex) {
glDeleteTextures(1, &_oldTextureIndex);
}
_oldTextureIndex = textureIndex;
free(spriteData);
CGContextRelease(spriteContext);
}
#pragma mark -
#pragma mark Accessors
- (void)adjustAspectRatio;
{
if (GPUImageRotationSwapsWidthAndHeight(inputRotation)) {
[self setAspectRatio:inputTextureSize.width / inputTextureSize.height];
} else {
[self setAspectRatio:inputTextureSize.height / inputTextureSize.width];
}
}
- (void)forceProcessingAtSize:(CGSize)frameSize;
{
[super forceProcessingAtSize:frameSize];
[self adjustAspectRatio];
}
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex
{
CGSize oldInputSize = inputTextureSize;
[super setInputSize:newSize atIndex:textureIndex];
if ( (!CGSizeEqualToSize(oldInputSize, inputTextureSize)) && (!CGSizeEqualToSize(newSize, CGSizeZero)) ) {
[self adjustAspectRatio];
}
}
- (void)setAspectRatio:(CGFloat)newValue
{
_aspectRatio = newValue;
[self setFloat:self.aspectRatio forUniform:_aspectRatioUniform program:filterProgram];
}
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
{
[super setInputRotation:newInputRotation atIndex:textureIndex];
[self setCenter:self.center];
[self adjustAspectRatio];
}
- (void)setScale: (CGFloat)newValue;
{
_scale = newValue;
[self setFloat:self.scale forUniform:_scaleUniform program:filterProgram];
}
- (void)setCenter: (CGPoint)newValue;
{
_center = newValue;
CGPoint rotatedPoint = [self rotatedPoint:self.center forRotation:inputRotation];
[self setPoint:rotatedPoint forUniform:_centerUniform program:filterProgram];
}
#end
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
The problem:
I've to render a big image 7148x15000px (a custom map), so i've looking around for something usefull and i've found BitmapSlice, but the problem is that the very first time i run the app (on device and simulator) several slices aren't loaded correctly and i see the image with large black holes.
Code:
BitmapSliceViewController.h
#import <UIKit/UIKit.h>
#interface BitmapSliceViewController : UIViewController<UIScrollViewDelegate>
#property (nonatomic, retain) UIImageView *_zoomView;
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
- (void)saveTilesOfSize:(CGSize)size forImage:(UIImage*)image toDirectory
(NSString*)directoryPath usingPrefix:(NSString*)prefix;
#end
BitmapSliceViewController.m
#import "BitmapSliceViewController.h"
#import "TileView.h"
#implementation BitmapSliceViewController
#synthesize scrollView;
- (void)dealloc
{
[super dealloc];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *directoryPath = [paths objectAtIndex:0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *big = [UIImage imageNamed:#"map.jpg"];
[self saveTilesOfSize:(CGSize){256, 256} forImage:big toDirectory:directoryPath usingPrefix:#"map_"];
dispatch_async(dispatch_get_main_queue(), ^{
[scrollView setNeedsDisplay];
});
});
TileView *tv = [[TileView alloc] initWithFrame:(CGRect){{0,0}, (CGSize){7148,15000}}];
[tv setTileTag:#"map_"];
[tv setTileDirectory:directoryPath];
[scrollView addSubview:tv];
[scrollView setContentSize:(CGSize){7148,15000}];
[scrollView setDelegate:self];
}
- (void)saveTilesOfSize:(CGSize)size
forImage:(UIImage*)image
toDirectory:(NSString*)directoryPath
usingPrefix:(NSString*)prefix
{
CGFloat cols = [image size].width / size.width;
CGFloat rows = [image size].height / size.height;
int fullColumns = floorf(cols);
int fullRows = floorf(rows);
CGFloat remainderWidth = [image size].width - (fullColumns * size.width);
CGFloat remainderHeight = [image size].height - (fullRows * size.height);
if (cols > fullColumns) fullColumns++;
if (rows > fullRows) fullRows++;
CGImageRef fullImage = [image CGImage];
for (int y = 0; y < fullRows; ++y) {
for (int x = 0; x < fullColumns; ++x) {
CGSize tileSize = size;
if (x + 1 == fullColumns && remainderWidth > 0) {
// Last column
tileSize.width = remainderWidth;
}
if (y + 1 == fullRows && remainderHeight > 0) {
// Last row
tileSize.height = remainderHeight;
}
CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage,
(CGRect){{x*size.width, y*size.height},
tileSize});
NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:tileImage], 1);
CGImageRelease(tileImage);
NSString *path = [NSString stringWithFormat:#"%#/%#%d_%d.png",
directoryPath, prefix, x, y];
[imageData writeToFile:path atomically:NO];
}
}
}
#end
TileView.h
#interface TileView : UIView
#property (nonatomic, copy) NSString *tileTag;
#property (nonatomic, copy) NSString *tileDirectory;
- (UIImage*)tileAtCol:(int)col row:(int)row;
#end
TileView.m
#import "TileView.h"
#implementation TileView
#synthesize tileTag;
#synthesize tileDirectory;
+ layerClass
{
return [CATiledLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) return nil;
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
//CGContextRef context = UIGraphicsGetCurrentContext();
CGSize tileSize = (CGSize){256, 256};
int firstCol = floorf(CGRectGetMinX(rect) / tileSize.width);
int lastCol = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
int firstRow = floorf(CGRectGetMinY(rect) / tileSize.height);
int lastRow = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);
for (int row = firstRow; row <= lastRow; row++) {
for (int col = firstCol; col <= lastCol; col++) {
UIImage *tile = [self tileAtCol:col row:row];
if (tile)
{
CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row, tileSize.width, tileSize.height);
tileRect = CGRectIntersection(self.bounds, tileRect);
[tile drawInRect:tileRect];
// [[UIColor whiteColor] set];
// CGContextSetLineWidth(context, 6.0);
// CGContextStrokeRect(context, tileRect);
}
}
}
}
- (UIImage*)tileAtCol:(int)col row:(int)row
{
NSString *path = [NSString stringWithFormat:#"%#/%#%d_%d.png", tileDirectory, tileTag, col, row];
return [UIImage imageWithContentsOfFile:path];
}
#end
This is the main code of the app, you can download the entire example from the site linked on the top of the post.
As i said the main problem is the rendering of some slices that fail in the first run of the app, other runs seem works correctly.
modifing a bit - (UIImage*)tileAtCol:(int)col row:(int)row
- (UIImage*)tileAtCol:(int)col row:(int)row
{
NSString *path = [NSString stringWithFormat:#"%#/%#%d_%d.png", tileDirectory, tileTag, col, row];
UIImage *img = [UIImage imageWithContentsOfFile:path];
if (img) {
NSLog(#"good");
}
else {
NSLog(#"bad");
}
return img;
}
The problem seems to be here...
Any ideas to fix it?
Thanks in advance