Mesh creation in openGL iphone sdk - iphone

I am using this source code as my base and trying to change the code as per my requirements. I have included the following code to create a mesh on image.
-(void)populateMesh{
verticalDivisions = kVerticalDivisions;
horizontalDivisions = kHorisontalDivisions;
unsigned int verticesArrsize = (kVerticalDivisions * ((2 + kHorisontalDivisions * 2) * 3));
unsigned int textureCoordsArraySize = kVerticalDivisions * ((2 + kHorisontalDivisions * 2) * 2);
verticesArr = (GLfloat *)malloc(verticesArrsize * sizeof(GLfloat));
textureCoordsArr = (GLfloat*)malloc(textureCoordsArraySize * sizeof(GLfloat));
if (verticesArr == NULL) {
NSLog(#"verticesArr = NULL!");
}
float height = kWindowHeight/verticalDivisions;
float width = kWindowWidth/horizontalDivisions;
int i,j, count;
count = 0;
for (j=0; j<verticalDivisions; j++) {
for (i=0; i<=horizontalDivisions; i++, count+=6) { //2 vertices each time...
float currX = i * width;
float currY = j * height;
verticesArr[count] = currX;
verticesArr[count+1] = currY + height;
verticesArr[count+2] = 0.0f;
verticesArr[count+3] = currX;
verticesArr[count+4] = currY;
verticesArr[count+5] = 0.0f;
}
}
float xIncrease = 1.0f/horizontalDivisions;
float yIncrease = 1.0f/verticalDivisions;
int x,y;
//int elements;
count = 0;
for (y=0; y<verticalDivisions; y++) {
for (x=0; x<horizontalDivisions+1; x++, count+=4) {
float currX = x *xIncrease;
float currY = y * yIncrease;
textureCoordsArr[count] = (float)currX;
textureCoordsArr[count+1] = (float)currY + yIncrease;
textureCoordsArr[count+2] = (float)currX;
textureCoordsArr[count+3] = (float)currY;
}
}
// int cnt;
// int cnt = 0;
NSLog(#"expected %i vertices, and %i vertices were done",(verticalDivisions * ((2 + horizontalDivisions*2 ) * 2) ) , count );
}
Following is the drawView code.
- (void)drawView:(GLView*)view;
{
static GLfloat rot = 0.0;
glBindTexture(GL_TEXTURE_2D, texture[0]);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordsArr);
glVertexPointer(3, GL_FLOAT, 0, verticesArr);
glPushMatrix();{
int i;
for (i=0; i<verticalDivisions; i++) {
glDrawArrays(GL_TRIANGLE_STRIP, i*(horizontalDivisions*2+2), horizontalDivisions*2+2);
}
}glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
In the setup view I have called [self populateMesh]; at the end of the function.
My problem is after changing the code, a blank rather say black view is appeared on the screen. Can anyone figure out where I am doing some mistake. I am newbie for openGL and trying to manipulate images through mesh. Please help asap. Thanks in advance.
Following is the setup view code.
-(void)setupView:(GLView*)view {
const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = view.bounds;
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);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_SRC_COLOR);
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
NSString *path = [[NSBundle mainBundle] pathForResource:#"texture" ofType:#"png"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(#"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGContextTranslateCTM (context, 0, height);
CGContextScaleCTM (context, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ),image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
[image release];
[texData release];
[self populateMesh];
}
EDIT This is what I am getting as an out put. While expected is regular grid...

Guessing the mesh is cut out with zNear value. Try to change z value to -2.
verticesArr[count+2] = -2.0f;
verticesArr[count+5] = -2.0f;
By default, the camera is situated at the origin, points down the negative z-axis, and has an up-vector of (0, 1, 0).
Notice that your mesh is out of view frustum (pyramid). Check it out in OpenGL red book:
http://glprogramming.com/red/chapter03.html

The grid is not regular because of the way how vertices are ordered. Also are you sure that GL_TRIANGLE_STRIP is desired option. Maybe, GL_TRIANGLES is that what you need.
I propose simpler solution with using indices array. For example in initialization code make vertices and texture array for your grid in normal order as:
0 1 2
3 4 5
6 7 8
Update:
- (void) setup
{
vertices = (GLfloat*)malloc(rows*colums*3*sizeof(GLfloat));
texCoords = (GLfloat*)malloc(rows*columns*2*sizeof(GLfloat));
indices = (GLubyte*)malloc((rows-1)*(columns-1)*6*sizeof(GLubyte));
float xDelta = horizontalDivisions/columns;
float yDelta = verticalDivisions/rows;
for (int i=0;i<columns;i++) {
for(int j=0;j<rows; j++) {
int index = j*columns+i;
vertices[3*index+0] = i*xDelta; //x
vertices[3*index+1] = j*yDelta; //y
vertices[3*index+2] = -10; //z
texCoords[2*index+0] = i/(float)(columns-1); //x texture coordinate
texCoords[2*index+1] = j/(float)(rows-1); //y tex coordinate
}
}
for (int i=0;i<columns-1;i++) {
for(int j=0;j<rows-1; j++) {
indices[6*(j*columns+i)+0] = j*columns+i;
indices[6*(j*columns+i)+1] = j*columns+i+1;
indices[6*(j*columns+i)+2] = (j+1)*columns+i;
indices[6*(j*columns+i)+3] = j*columns+i+1;
indices[6*(j*columns+i)+4] = (j+1)*columns+i+1;
indices[6*(j*columns+i)+5] = (j+1)*columns+i;
}
}
}
- (void) dealloc {
free(vertices); free(texCoords); free(indices);
}
Practically this indices order means that tringles are rendered as following:
(013)(143)(124)(254)(346)(476)... and so on.
In render method use the following lines:
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawElements(GL_TRIANGLES, 6*(columns-1)*(rows-1), GL_UNSIGNED_BYTE, indices);
Hope that will help.

This is a great tutorial on drawing a grid in 3D. It should have the code necessary to help you. I'm not sure if you are working in 3D or 2D, but even if it is 2D, it should be fairly easy to adapt to your needs. Hope that helps!

Related

Drawing with with blur effect on image using opengl

I have the same requirement as this question
I am right now at situation where i set UIImage on my opengl view.
Below is the complete code i used to set uiimage. Also it includes the drawing code.
Using below code I am able to set image and drawing on it.
when i do not set image in background it allows me to draw blur and smooth drawing
but if i set background image it draws solid drawing
I want smooth drawing on background image.
I have used some of GLPaint code of apple for drawing.
- (id)initWithCoder:(NSCoder*)coder
{
CGImageRef brushImage;
CGContextRef brushContext;
GLubyte *brushData;
size_t width, height;
if ((self = [super initWithCoder:coder]))
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = NO;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!_context || ![EAGLContext setCurrentContext:_context])
{
return nil;
}
{
brushImage = [UIImage imageNamed:#"Brush.png"].CGImage;
width = CGImageGetWidth(brushImage);
height = CGImageGetHeight(brushImage);
if(brushImage) {
brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
brushContext = CGBitmapContextCreate(brushData, width, width, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);
CGContextRelease(brushContext);
glGenTextures(1, &brushTexture);
glBindTexture(GL_TEXTURE_2D, brushTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
free(brushData);
}
}
// Setup OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
glViewport(0, 0, frame.size.width , frame.size.height);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SPRITE_OES);
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glPointSize(10);
}
return self;
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:_context];
[self destroyFramebuffer];
[self createFramebuffer];
if (texture) {
[self _updateContent];
glDeleteTextures(1, &texture);
texture = 0;
}
}
- (void)_updateContent {
NSUInteger width = self.frame.size.width;
NSUInteger height = self.frame.size.height;
CGFloat texWidth = (1.0 * width)/TEX_SIZE;
CGFloat texHeight = (1.0 * height)/TEX_SIZE;
GLfloat verts[12] = {
0, height,
width, height,
width, 0,
0, height,
0, 0,
width, 0
};
GLfloat txcoord[12] = {
0, texHeight,
texWidth, texHeight,
texWidth, 0,
0, texHeight,
0, 0,
texWidth, 0
};
[EAGLContext setCurrentContext:_context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer);
glVertexPointer(2, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, txcoord);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER_OES];
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
- (void)setContent:(UIImage*)image
{
if (image) {
// self.isNotEmpty = YES;
CGImageRef contentImage = image.CGImage;
[EAGLContext setCurrentContext:_context];
CGFloat w = CGImageGetWidth(contentImage);
CGFloat h = CGImageGetHeight(contentImage);
GLubyte *data = (GLubyte *)calloc(TEX_SIZE * TEX_SIZE * 4, sizeof(GLubyte));
CGContextRef ctx = CGBitmapContextCreate(data, TEX_SIZE, TEX_SIZE, 8, TEX_SIZE * 4, CGImageGetColorSpace(contentImage), kCGImageAlphaPremultipliedLast);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -TEX_SIZE);
CGContextDrawImage(ctx, CGRectMake(0, 0, w, h), contentImage);
CGContextRelease(ctx);
if (!texture) {
glGenTextures(1, &texture);
}
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
free(data);
}
[self setNeedsLayout];
glDisable(GL_VERTEX_ARRAY);
}
//Called on touchedMoved
- (void) renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
glEnable(GL_BLEND);
if(1){
sharedDelegate = [AppDelegate appDelegate];
static GLfloat* vertexBuffer = NULL;
static NSUInteger vertexMax = 64;
NSUInteger vertexCount = 0,
count,
i;
GLenum err;
glColor4f(1.0, 0.0, 1.0, 1.0);
// Convert locations from Points to Pixels
CGFloat scale = self.contentScaleFactor;
start.x *= scale;
start.y *= scale;
end.x *= scale;
end.y *= scale;
// Allocate vertex array buffer
if(vertexBuffer == NULL)
vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
// Add points to the buffer so there are drawing points every X pixels
count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
for(i = 0; i < count; ++i) {
if(vertexCount == vertexMax) {
vertexMax = 2 * vertexMax;
vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
}
vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
vertexCount += 1;
}
if(sharedDelegate.boolIsEraser)
{
glColor4f(1.0, 1.0, 1.0, 0.5);
glBlendFunc( GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
}
// Render the vertex array
glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
glDrawArrays(GL_POINTS, 0, vertexCount);
if(sharedDelegate.boolIsEraser){
// at last restore the mixed-mode
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER_OES];
err = glGetError();
if (err != GL_NO_ERROR)
NSLog(#"Error in frame. glError: 0x%04X", err);
}
}
Any workaround to accomplish this?
I am almost there to my goal but badly stuck here.Any help will be appreciated.
You might try setting the shadow color to the same as the stroke color, and the stroke blur radius to however many points out from the edge of the stroke you want the blur to extend. You'll probably want to set the shadow offset to CGSizeZero.
You can try openGL code from This Link
or try this
CGSize offset;
float blur;//set this variable as per your requirement
offset.width = 10;
offset.height = -10;
CGContextSetShadow(context, offset, blur);
I got the solution...
The thing remaining was I need to set my opengl states after i draw UIImage in opengl view. The same thing i did when i initialized brush texture...
I just added below code in LayoutSubviews method after _updateContent method
// Setup OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
glViewport(0, 0, frame.size.width , frame.size.height);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SPRITE_OES);
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE)
and now this code is working perfectly..
You can use
CGContextSetBlendMode(context, kCGBlendModeClear) ike real eraser effect

Texture Mapping - Cocos2d/OpenGL ES 1.0

This lightning is really affecting my game's performance because I am constantly adding and removing the lightning, but also each lighting strike is composed of 3 anti aliased lines using:
void ccDrawSmoothLine(CGPoint pos1, CGPoint pos2, float width)
{
GLfloat lineVertices[12], curc[4];
GLint ir, ig, ib, ia;
CGPoint dir, tan;
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
//glEnable(GL_LINE_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
pos1.x *= CC_CONTENT_SCALE_FACTOR();
pos1.y *= CC_CONTENT_SCALE_FACTOR();
pos2.x *= CC_CONTENT_SCALE_FACTOR();
pos2.y *= CC_CONTENT_SCALE_FACTOR();
width *= CC_CONTENT_SCALE_FACTOR();
width = width*2;
dir.x = pos2.x - pos1.x;
dir.y = pos2.y - pos1.y;
float len = sqrtf(dir.x*dir.x+dir.y*dir.y);
if(len<0.00001)
return;
dir.x = dir.x/len;
dir.y = dir.y/len;
tan.x = -width*dir.y;
tan.y = width*dir.x;
lineVertices[0] = pos1.x + tan.x;
lineVertices[1] = pos1.y + tan.y;
lineVertices[2] = pos2.x + tan.x;
lineVertices[3] = pos2.y + tan.y;
lineVertices[4] = pos1.x;
lineVertices[5] = pos1.y;
lineVertices[6] = pos2.x;
lineVertices[7] = pos2.y;
lineVertices[8] = pos1.x - tan.x;
lineVertices[9] = pos1.y - tan.y;
lineVertices[10] = pos2.x - tan.x;
lineVertices[11] = pos2.y - tan.y;
glGetFloatv(GL_CURRENT_COLOR,curc);
ir = 255.0*curc[0];
ig = 255.0*curc[1];
ib = 255.0*curc[2];
ia = 255.0*curc[3];
const GLubyte lineColors[] = {
ir, ig, ib, 0,
ir, ig, ib, 0,
ir, ig, ib, ia,
ir, ig, ib, ia,
ir, ig, ib, 0,
ir, ig, ib, 0,
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, lineVertices);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, lineColors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
glDisableClientState(GL_COLOR_ARRAY);
// restore default state
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
}
My FPS will drop to about 40, then shoot back up to 60. I've read that texture mapping the line could improve my game's performance.
I have been trying to figure this out for several weeks now, with no luck. Can someone PLEASE help me with this?
This is my current ccDrawLines and draw method
-(void) draw
{
numPoints_ = 0;
glColor4ub(_color.r, _color.g, _color.b, _opacity);
if (_opacity != 255)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawLightning(_strikePoint2, _strikePoint, _displacement, _minDisplacement, _seed, lightningPoints_, &numPoints_);
ccDrawLines(lightningPoints_, numPoints_, texture);
if (_opacity != 255)
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
glColor4f(1.0, 1.0, 1.0, 1.0);
}
void ccDrawLines( CGPoint* points, uint numberOfPoints, CCTexture2D* texture )
{
//layout of points [0] = origin, [1] = destination and so on
ccVertex2F vertices[numberOfPoints];
if (CC_CONTENT_SCALE_FACTOR() != 1 )
{
for (int i = 0; i < numberOfPoints; i++)
{
vertices[i].x = points[i].x * CC_CONTENT_SCALE_FACTOR();
vertices[i].y= points[i].y * CC_CONTENT_SCALE_FACTOR();
}
glVertexPointer(2, GL_FLOAT, 0, vertices);
}
else glVertexPointer(2, GL_FLOAT, 0, points);
ccTex2F texCoords[numberOfPoints];
float width = texture.pixelsWide;
float height = texture.pixelsHigh;
if (CC_CONTENT_SCALE_FACTOR() != 1 )
{
for (int i = 0; i < numberOfPoints; i++)
{
texCoords[i].u = (vertices[i].x * CC_CONTENT_SCALE_FACTOR()) / width;
texCoords[i].v = (vertices[i].y * CC_CONTENT_SCALE_FACTOR()) / height;
}
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
}
else glTexCoordPointer(2, GL_FLOAT, 0, points);
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, [texture name]);
glDisableClientState(GL_COLOR_ARRAY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfPoints);
// restore default state
glEnableClientState(GL_COLOR_ARRAY);
glPopMatrix();
}
The texture is just a 32x32 .png file with a small blue dot.
If you look at ccDrawLines I have added the code to texture map the line. The problem with it is, gaps in the line, multiple lines being drawn, and it looks horrible.
EDIT:
I decided not to texture map the line and use ccDrawSmoothLine.
All I did was allocate the lightning in my gamelayer's init
lightningStrike_ = [Lightning lightningWithStrikePoint:ccp(-100, -100) strikePoint2:ccp(-100, -100)];
[self addChild:lightningStrike_ z:1];
Then, I created an instance method to set the _strikePoint and _strikePoint2 properties and call the strikeRandom method.
-(Lightning *)lightningStrike:(CGPoint)p end:(CGPoint)p2
{
lightningStrike_.strikePoint = ccp(p.x, p.y);
lightningStrike_.strikePoint2 = ccp(p2.x, p2.y);
[lightningStrike_ strikeRandom];
return lightningStrike_;
}
Usage:
[self lightningStrike:ccp(100, 100) end:ccp(100, 100)];
This fixed the FPS drop. After 24 hours I will answer and accept my own answer.
EDIT: I decided not to texture map the line and use ccDrawSmoothLine.
All I did was allocate the lightning in my gamelayer's init
lightningStrike_ = [Lightning lightningWithStrikePoint:ccp(-100, -100) strikePoint2:ccp(-100, -100)];
[self addChild:lightningStrike_ z:1];
Then, I created an instance method to set the _strikePoint and _strikePoint2 properties and call the strikeRandom method.
-(Lightning *)lightningStrike:(CGPoint)p end:(CGPoint)p2
{
    lightningStrike_.strikePoint = ccp(p.x, p.y);
    lightningStrike_.strikePoint2 = ccp(p2.x, p2.y);
    [lightningStrike_ strikeRandom];
    return lightningStrike_;
}
Usage:
[self lightningStrike:ccp(100, 100) end:ccp(100, 100)];
This fixed the FPS drop. After 24 hours I will answer and accept my own answer.

Real memory usage increases 2x when I load a texture in OpenGLES

I've been banging my head against this one for a while. The situation is this: I've made a 2D game for iphone on my own little OpenGL 2D game engine (which I built as an experiment but which may now actually ship). I'm trying to get memory under control. I'm using texture atlases, and I'm familiar with PVRTC (but as of now I'm not using it). The issue is that if I load a 1024x1024 png texture atlas, which I expect to take about 4 megs when expanded into memory (1024 x 1024 x 4 bytes per pixel - RBGA8888 = 4 megs), the real memory usage (according to Instruments-Memory Monitor) increases by 8 megs. Aaagh!
I'm aware that OpenGLES takes the texture data, expands it into memory, then reorders the pixels to work on the PowerVR chip, and then makes a texture out of it (or something similar). Is it possible that this memory is not getting freed? So that I have two copies of each texture sitting around in memory? From the ObjectiveC side of things, I see everything releasing correctly. But what goes on behind the OpenGL API, I don't know. I'm probably missing something.
My implementation for loading the textures I got from O'Reilly's iPhone Game Development book. Here are the key points I'm using for implementation:
Step 1 - get image data to correct (power of 2) size:
- (id) initWithImage:(UIImage *)uiImage
{
NSUInteger width, height, i;
CGContextRef context = nil;
void* data = nil;
CGColorSpaceRef colorSpace;
void* tempData;
unsigned int* inPixel32;
unsigned short* outPixel16;
BOOL hasAlpha;
CGImageAlphaInfo info;
CGAffineTransform transform;
CGSize imageSize;
GLTexturePixelFormat pixelFormat;
CGImageRef image;
UIImageOrientation orientation;
BOOL sizeToFit = NO;
image = [uiImage CGImage];
orientation = [uiImage imageOrientation];
if(image == NULL) {
[self release];
NSLog(#"Image is Null");
return nil;
}
info = CGImageGetAlphaInfo(image);
hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO);
if(CGImageGetColorSpace(image)) {
if(hasAlpha)
pixelFormat = kGLTexturePixelFormat_RGBA8888;
else
pixelFormat = kGLTexturePixelFormat_RGB565;
} else { //NOTE: No colorspace means a mask image
pixelFormat = kGLTexturePixelFormat_A8;
}
imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
transform = CGAffineTransformIdentity;
width = imageSize.width;
if((width != 1) && (width & (width - 1))) {
i = 1;
while((sizeToFit ? 2 * i : i) < width)
i *= 2;
width = i;
}
height = imageSize.height;
if((height != 1) && (height & (height - 1))) {
i = 1;
while((sizeToFit ? 2 * i : i) < height)
i *= 2;
height = i;
}
while((width > kMaxTextureSize) || (height > kMaxTextureSize)) {
width /= 2;
height /= 2;
transform = CGAffineTransformScale(transform, 0.5, 0.5);
imageSize.width *= 0.5;
imageSize.height *= 0.5;
}
switch(pixelFormat) {
case kGLTexturePixelFormat_RGBA8888:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
break;
case kGLTexturePixelFormat_RGB565:
colorSpace = CGColorSpaceCreateDeviceRGB();
data = malloc(height * width * 4);
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
break;
case kGLTexturePixelFormat_A8:
data = malloc(height * width);
context = CGBitmapContextCreate(data, width, height, 8, width, NULL, kCGImageAlphaOnly);
break;
default:
[NSException raise:NSInternalInconsistencyException format:#"Invalid pixel format"];
}
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextTranslateCTM(context, 0, height - imageSize.height);
if(!CGAffineTransformIsIdentity(transform))
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
if(pixelFormat == kGLTexturePixelFormat_RGB565) {
tempData = malloc(height * width * 2);
inPixel32 = (unsigned int*)data;
outPixel16 = (unsigned short*)tempData;
for(i = 0; i < width * height; ++i, ++inPixel32)
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0);
free(data);
data = tempData;
}
self = [self initWithData:data pixelFormat:pixelFormat pixelsWide:width pixelsHigh:height contentSize:imageSize];
CGContextRelease(context);
free(data);
return self;
}
Step 2 - bind and load texture:
- (id) initWithData:(const void*)data pixelFormat:(GLTexturePixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size
{
GLint saveName;
if((self = [super init])) {
glGenTextures(1, &_name); //get a new texture id. _name increases as more textures are loaded
glGetIntegerv(GL_TEXTURE_BINDING_2D, &saveName); //generally, saveName==1. gets existing bound texture, so we can restore it after load.
glBindTexture(GL_TEXTURE_2D, _name); //start working with our new texture id
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //added by ijames
//associate pixel data with the texture id.
switch(pixelFormat) {
case kGLTexturePixelFormat_RGBA8888:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
case kGLTexturePixelFormat_RGB565:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
break;
case kGLTexturePixelFormat_A8:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
break;
default:
[NSException raise:NSInternalInconsistencyException format:#""];
}
glBindTexture(GL_TEXTURE_2D, saveName); //restore the previous texture binding.
//NSLog(#"name %d, savename %d", _name, saveName);
_size = size;
_width = width;
_height = height;
_format = pixelFormat;
_maxS = size.width / (float)width;
_maxT = size.height / (float)height;
}
return self;
}
Do you see anything horribly wrong? Have any of you run into this problem before? Where on earth is this phantom memory coming from?
Thanks for your time and thoughts!
EDIT 1:
I just added some lines to initWithImage: immediately before the call to initWithData: to convert any RGBA8888 textures to RGBA4444 on the fly when being loaded, just to see what would happen and how bad the graphics hit would be. The result was that the real memory usage decreased by almost 2x. That means that wherever the mystery doubling is happening, it happens in or after the initWithData: step. Thanks again for you thoughts!
EDIT 2:
To answer one of the comments - here is how initWithImage: is called (this is the only place it happens - from a ResourceManager class that manages a cache for textures) :
//NOTE: 'texture' and '_textures' are declared earlier...
//if the texture doesn't already exist, create it and add it to the cache
NSString * fullPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: fileName];
UIImage * textureImg = [[UIImage alloc] initWithContentsOfFile: fullPath];
texture = [[GLTexture alloc] initWithImage: textureImg]; //here's the call
[textureImg release];
[_textures setValue: texture forKey: fileName];
return [texture autorelease];

How to crop the image in iPhone

I want to do the same thing as asked in this question.
In my App i want to crop the image like we do image cropping in FaceBook can any one guide me with the link of good tutorial or with any sample code. The Link which i have provided will completely describe my requirement.
You may create new image with any properties. Here is my function, witch do that. you just need to use your own parameters of new image. In my case, image is not cropped, I just making some effect, moving pixels from there original place to another. But if you initialize new image with another height and width, you can just copy from any range of pixels of old image you need, to new one:
-(UIImage *)Color:(UIImage *)img
{
int R;
float m_width = img.size.width;
float m_height = img.size.height;
if (m_width>m_height) R = m_height*0.9;
else R = m_width*0.9;
int m_wint = (int)m_width; //later, we will need this parameters in float and int. you may just use "(int)" and "(float)" before variables later, and do not implement another ones
int m_hint = (int)m_height;
CGRect imageRect;
//cheking image orientation. we will work with image pixel-by-pixel, so we need to make top side at the top.
if(img.imageOrientation==UIImageOrientationUp
|| img.imageOrientation==UIImageOrientationDown)
{
imageRect = CGRectMake(0, 0, m_wint, m_hint);
}
else
{
imageRect = CGRectMake(0, 0, m_hint, m_wint);
}
uint32_t *rgbImage = (uint32_t *) malloc(m_wint * m_hint * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImage, m_wint, m_hint, 8, m_wint *sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetShouldAntialias(context, NO);
CGContextTranslateCTM(context, 0, m_hint);
CGContextScaleCTM(context, 1.0, -1.0);
switch (img.imageOrientation) {
case UIImageOrientationRight:
{
CGContextRotateCTM(context, M_PI / 2);
CGContextTranslateCTM(context, 0, -m_wint);
}break;
case UIImageOrientationLeft:
{
CGContextRotateCTM(context, - M_PI / 2);
CGContextTranslateCTM(context, -m_hint, 0);
}break;
case UIImageOrientationUp:
{
CGContextTranslateCTM(context, m_wint, m_hint);
CGContextRotateCTM(context, M_PI);
}
default:
break;
}
CGContextDrawImage(context, imageRect, img.CGImage);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
//here is new image. you can change m_wint and m_hint as you whant
uint8_t *result = (uint8_t *) calloc(m_wint * m_hint * sizeof(uint32_t), 1);
for(int y = 0; y < m_hint; y++) //new m_hint here
{
float fy=y;
double yy = (m_height*( asinf(m_height/(2*R))-asin(((m_height/2)-fy)/R) )) /
(2*asin(m_height/(2*R))); // (xx, yy) - coordinates of pixel of OLD image
for(int x = 0; x < m_wint; x++) //new m_wint here
{
float fx=x;
double xx = (m_width*( asin(m_width/(2*R))-asin(((m_width/2)-fx)/R) )) /
(2*asin(m_width/(2*R)));
uint32_t rgbPixel=rgbImage[(int)yy * m_wint + (int)xx];
int intRedSource = (rgbPixel>>24)&255;
int intGreenSource = (rgbPixel>>16)&255;
int intBlueSource = (rgbPixel>>8)&255;
result[(y * (int)m_wint + x) * 4] = 0;
result[(y * (int)m_wint + x) * 4 + 1] = intBlueSource;
result[(y * (int)m_wint + x) * 4 + 2] = intGreenSource;
result[(y * (int)m_wint + x) * 4 + 3] = intRedSource;
}
}
free(rgbImage);
colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(result, m_wint, m_hint, 8, m_wint * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast ); //new m_wint and m_hint as well
CGImageRef image1 = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *resultUIImage = [UIImage imageWithCGImage:image1];
CGImageRelease(image1);
#try {
free(result);
}
#catch (NSException * e) {
NSLog(#"proc. Exception: %#", e);
}
return resultUIImage;
}
CGRect rectImage = CGRectMake(p1.x,p1.y, p2.x - p1.x, p4.y - p1.y);
//Create bitmap image from original image data,
//using rectangle to specify desired crop area
CGImageRef imageRef = CGImageCreateWithImageInRect([imageForCropping CGImage], rectImage);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(p1.x, p1.y,p2.x-p1.x p4.y-p1.y)];
imageView1.image = croppedImage;
[self.view addSubview:imageView1];
CGImageRelease(imageRef);

OpenGL sprites are trembling slightly at rendering

I made a class which manage sprites in an iphone application by using opengl es.
rendering works well but when the sprite sheet is large (more than 512x512px) and the sprite has a part which doesn't move, this part seems trembling slightly (like if antialiasing was computed differently for each frame).
Is it normal or is it a bug in my code ?
Here is the code :
//set bounds of the cell
int t_x1 = position.x;
int t_y1 = MAX_SPRITE_HEIGHT - position.y;
int t_x2 = t_x1 + width;
int t_y2 = t_y1 - height;
//set vertices position
GLshort verticesBuffer[4*3];
verticesBuffer[0] = t_x1;
verticesBuffer[1] = t_y1;
verticesBuffer[2] = depth;
verticesBuffer[3] = t_x1;
verticesBuffer[4] = t_y2;
verticesBuffer[5] = depth;
verticesBuffer[6] = t_x2;
verticesBuffer[7] = t_y1;
verticesBuffer[8] = depth;
verticesBuffer[9] = t_x2;
verticesBuffer[10] = t_y2;
verticesBuffer[11] = depth;
//set texture coordinates
GLfloat texCoordBuffer[2*4]
texCoordBuffer[0] = a_cellLayer.origin.x / CGImageGetWidth(texture.textureImage);
texCoordBuffer[1] = a_cellLayer.origin.y / CGImageGetHeight(texture.textureImage);
texCoordBuffer[2] = texCoordBuffer[0];
texCoordBuffer[3] = texCoordBuffer[1] + (float)(t_y1-t_y2) / CGImageGetHeight(texture.textureImage);
texCoordBuffer[4] = texCoordBuffer[6];
texCoordBuffer[5] = texCoordBuffer[1];
texCoordBuffer[6] = texCoordBuffer[0] + (float)(t_x2-t_x1) / CGImageGetWidth(texture.textureImage);
texCoordBuffer[7] = texCoordBuffer[3];
//set texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, [texture getTexture]);
//set vertices
glVertexPointer(3, GL_SHORT, 0, verticesBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
//apply texture
glTexCoordPointer(2, GL_FLOAT, 0, texCoordBuffer);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//render
glColor4f(1.0, 1.0, 1.0, 1.0); // R V B Alpha
glNormal3f(0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4*nbOfXSudivisions*nbOfYSudivisions);
I tried to change the type of my texture coordinates with GL_FIXED but it doesn't change anything
Does anybody have an idea ?
I don't use depth buffer and I've set the projection matrix like that :
const GLfloat zNear = 100, zFar = 1000, fieldOfView = 22.5;
glMatrixMode(GL_PROJECTION);
GLfloat size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = oGLView.bounds;
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();
//set perspective
gluLookAt(PAGE_WIDTH/2, PAGE_HEIGHT/2, PAGE_WIDTH/2.0f/(tanf(DEGREES_TO_RADIANS(fieldOfView/2.0f))),
PAGE_WIDTH/2, PAGE_HEIGHT/2, 0,
0, 1, 0);