VBO on OpenGL ES 2.0 Not Showing Anything - opengl-es-2.0

I am learning OpenGL ES . I have successfully drawn some cubes, understanding basic matrices logic behind for camera location, etc. Right now I am trying to build an example for VBO but It is not drawn anything into the screen. I will paste my code, probably someone could realize what I am doing wrong.
Fragment Shader Code
precision mediump float;
varying vec2 v_texCoord;
varying vec3 v_colour;
uniform sampler2D s_texture;
void main()
{
gl_FragColor = texture2D(s_texture, v_texCoord);
}
Vertex Shader
attribute vec3 av3position;
attribute vec2 a_texCoord;
attribute vec3 av3colour;
uniform mat4 PerspectiveMatrix;
uniform mat4 ModelViewMatrix;
varying vec2 v_texCoord;
varying vec3 v_colour;
void main()
{
v_texCoord = a_texCoord;
v_colour =av3colour;
vec4 pos = ModelViewMatrix * vec4(av3position,1.0);
gl_Position = PerspectiveMatrix * pos;
}
Texture Loading
Texture01RGBA->boLoadTextureFromfile("BitmapData/cubeLayout_02.png" );
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Use tightly packed data
glGenTextures(1, &gluiTextureID); // Generate a texture object
glBindTexture(GL_TEXTURE_2D, gluiTextureID); // Bind the texture object
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Texture01RGBA->getWidth(), Texture01RGBA->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, Texture01RGBA->getPixmapPointer());
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture ( GL_TEXTURE0 );
glBindTexture ( GL_TEXTURE_2D, gluiTextureID );
// Set the sampler texture unit to 0
glUniform1i ( iLoc2DSampler, 0 );
Vertex Object Structure
const float aCubeVertices[] =
{ // x, y, z, nx, ny, nz, u, v
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 0.500000,
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 0.250000,
-1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.250000, 0.250000,
-1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.250000, 0.500000,
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 0.750000,
-1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.250000, 0.750000,
-1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.250000, 1.000000,
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 1.000000,
1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.750000, 0.250000,
1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.750000, 0.000000,
1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.500000, 0.000000,
1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.500000, 0.250000,
1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.500000, 0.250000,
1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.500000, 0.000000,
-1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.250000, 0.000000,
-1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.250000, 0.250000,
-1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.250000, 0.250000,
-1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.250000, 0.000000,
-1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000,
-1.000000,1.000000, 1.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.250000,
1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.500000, 0.750000,
1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.500000, 0.500000,
-1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.250000, 0.500000,
-1.000000,1.000000, 1.000000, 0.000000, 1.000000, 0.000000, 0.250000, 0.750000
};
unsigned short aCubeIndices[]= // 36 Elements. 3 Groups
{ 0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23 };
VBO Creation
glGenBuffers (1, &vao);
glBindBuffer (GL_ARRAY_BUFFER, vao);
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float)*8, aCubeVertices, GL_STATIC_DRAW);
glBindBuffer (GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &vinx);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vinx);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36* sizeof(GLushort), aCubeIndices, GL_STATIC_DRAW);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
VBO Drawing
glBindBuffer (GL_ARRAY_BUFFER, vao);
// set up vertex attributes
glEnableVertexAttribArray(iLocPosition);
glEnableVertexAttribArray(iLocTexCoord);
glVertexAttribPointer(iLocPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float)*8, 0);
glVertexAttribPointer(iLocTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(float)*8, (const void *)24 );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vinx);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(iLocPosition);
glDisableVertexAttribArray(iLocTexCoord);
As I pointed out before I have been using basically the same code for previous more simple examples I've done (textures,transformation matrices). I have also checked for errors with and no code error is present.
I will appreciate if someone highlight what could be wrong with my code.

Your vertex buffer (or at least your index buffer) seems incorrect. For instance, the first triangle is defined by the indices 0, 1, 2, which correspond to the following vertices:
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 0.500000,
1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.500000, 0.250000,
-1.000000,1.000000, 1.000000, 0.000000, 0.000000, 1.000000, 0.250000, 0.250000,
As you can see, the position of the first and the second vertices is the same (1,1,1). The result is a degenerate triangle (a triangle with no area) which can't be rendered.

The code you show here looks correct. The problem could be in other parts of the code. One source of error could be how you setup your modelview and perspective matrix. Another might be something wrong with the way you set your uniforms glUniform*() (perhaps a row/column majority mismatch with your matrices and how OpenGL expects it). If you could paste that code then we would have the complete picture
I assume the vertex and index data for the cube is correct since you mentioned that you already got cubes drawn before.

Related

Draw IOSurfaces to another IOSurface

How can I draw a series of IOSurfaces to another then draw it to the screen? I've played around with some source from apple in the MultiGPU sample project, but the best I managed to do is draw a white screen or get tons of artifacts and crash the app.
I'm very new to openGL and I don't quite understand the binding of framebuffers and textures and how they interact with IOSurfaces.
This is what I have to create a texture from an IOSurface (directly from Apple's source)
// Create an IOSurface backed texture
// Create an FBO using the name of this texture and bind the texture to the color attachment of the FBO
- (GLuint)setupIOSurfaceTexture:(IOSurfaceRef)ioSurfaceBuffer {
GLuint name;
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA, 512, 512, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
ioSurfaceBuffer, 0);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate an FBO using the same name with the same texture bound to it as a render target.
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, name);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, name, 0);
if(!_depthBufferName) {
glGenRenderbuffersEXT(1, &_depthBufferName);
glRenderbufferStorageEXT(GL_TEXTURE_RECTANGLE_EXT, GL_DEPTH, 512, 512);
}
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_EXT, _depthBufferName);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return name;
}
And I have this piece of code to draw the surface to the screen. (Also from Apple's source)
// Fill the view with the IOSurface backed texture
- (void)textureFromCurrentIOSurface {
NSRect bounds = [self bounds];
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
// Render quad from our iosurface texture
glViewport(0, 0, (GLint)bounds.size.width, (GLint)bounds.size.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLfloat)bounds.size.width, 0.0f, (GLfloat)bounds.size.height, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, [[NSApp delegate] currentTextureName]); // Grab the texture from the delegate
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glTexEnvi(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(512.0f, 0.0f);
glVertex2f((GLfloat)bounds.size.width, 0.0f);
glTexCoord2f(512.0f, 512.0f);
glVertex2f((GLfloat)bounds.size.width, (GLfloat)bounds.size.height);
glTexCoord2f(0.0f, 512.0f);
glVertex2f(0.0f, (GLfloat)bounds.size.height);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_EXT);
}
With a single IOSurface being draw to the screen this works fine. What am I missing to draw an IOSurface to another?
Assuming I have textures A, B, C, and D I want to:
-Draw A onto C in a specific region,
-Draw B onto C in a different region (may overlap A),
-Draw C to the screen.
I solved the issue using the following code, however there are some minor issues with scaling the IOSurface before drawing.
- (void)renderIOSurface:(IOSurfaceRef)surface toBuffer:(GLuint)buffer atPoint:(CGPoint)point withSize:(CGSize)size {
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
// Bind framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer);
glViewport(0, 0, TEXWIDE, TEXHIGH);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, TEXWIDE, 0.0, TEXHIGH, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLsizei sH = (GLsizei)IOSurfaceGetHeight(surface);
GLsizei sW = (GLsizei)IOSurfaceGetWidth(surface);
// Create texture
GLuint name;
glGenTextures(1, &name);
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA, sW, sH, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
//glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(point.x, point.y);
glTexCoord2f(sW, 0.0f);
glVertex2f(point.x + size.width, point.y);
glTexCoord2f(sW, sH);
glVertex2f(point.x + size.width, point.y + size.height);
glTexCoord2f(0.0f, sH);
glVertex2f(point.x, point.y + size.height);
glEnd();
//glDisable(GL_TEXTURE_RECTANGLE_EXT);
// Bindback to normal
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Delete the name texture
glDeleteTextures(1, &name);
// [[self openGLContext] flushBuffer];
// This flush is necessary to ensure proper behavior if the MT engine is enabled.
// glFlush();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
}

Drawing textures in OpenGL objective c os x

I tried to display a picture, but it is not displayed.
Here is my code for an NSOpenGLView subclass:
//
// MyOpenGLView.m
// OpenGLTests
//
// Created by Tom Schamberger on 10.12.12.
// Copyright (c) 2012 Tom Schamberger. All rights reserved.
//
#import "MyOpenGLView.h"
#implementation MyOpenGLView
- (id)initWithFrame:(NSRect)frame
{
NSOpenGLPixelFormat * pf = [MyOpenGLView basicPixelFormat];
self = [super initWithFrame: frame pixelFormat: pf];
return self;
}
+ (NSOpenGLPixelFormat*) basicPixelFormat
{
NSOpenGLPixelFormatAttribute attributes [] = {
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer, // double buffered
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
(NSOpenGLPixelFormatAttribute)nil
};
return [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
}
- (void) prepareOpenGL
{
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glPolygonOffset (1.0f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
if([self loadTextures])
NSLog(#"Load");
}
- (void)drawRect:(NSRect)dirtyRect
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture( GL_TEXTURE_2D, texture);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glColor3f(1, 1, 1);
glBegin( GL_QUADS );
glTexCoord2f( 0.0f, 0.0f);
glVertex2f( -0.5f, -0.5f);
glTexCoord2f( 1.0f, 0.0f);
glVertex2f( 0.5f, -0.5f);
glTexCoord2f( 1.0f, 1.0f);
glVertex2f( 0.5f, 0.5f);
glTexCoord2f( 0.0f, 1.0f);
glVertex2f( -0.5f, 0.5f);
glEnd();
glFlush();
}
- (BOOL) loadTextures
{
NSImage *img = [NSImage imageNamed:#"NeHe.bmp"];
if(img == nil)
return FALSE;
else if(img.size.height == 0 || img.size.width == 0)
return FALSE;
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithData: [img TIFFRepresentation]];
glGenTextures( 1, &texture);
glBindTexture( GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, rep.size.width,
rep.size.height, 0, GL_RGB,
GL_UNSIGNED_BYTE, rep.bitmapData);
return TRUE;
}
#end
It draws a rectangle, but the texture is not displayed.
You should probably set you clear color alpha to 0.0 rather than 0.5
This code for loading a texture works.
backGroundPath = #"Background.bmp";
NSData* backGroundData = [NSData dataWithContentsOfFile:backGroundPath options:NSUncachedRead error:nil];
backGroundImage = [NSBitmapImageRep imageRepWithData:backGroundData];
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures( 1, backGroundTexture);
glBindTexture(GL_TEXTURE_2D, backGroundTexture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backGroundImage.size.width,
backGroundImage.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
backGroundImage.bitmapData);

OpenGL ES 2.0 Texture mapped, but shows as black

I am trying to get my texture to show up in a basic OpenGL view (subclass of UIView), but no matter which texture I use, it shows up black. The code for my view is as follows:
#implementation SymGLView
typedef struct {
float Position[3];
float Color[4];
float TexCoord[2];
} Vertex;
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}, {0, 0}},
{{1, 1, 0}, {0, 1, 0, 1}, {0, 1}},
{{-1, 1, 0}, {0, 0, 1, 1}, {1, 1}},
{{-1, -1, 0}, {0, 0, 0, 1}, {1, 0}}
};
const GLubyte Indices[] = {
0, 1, 2,
2, 3, 0
};
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (void)setupLayer {
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;
}
- (void)setupContext {
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(#"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
if (![EAGLContext setCurrentContext:_context]) {
NSLog(#"Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
- (void)setupDepthBuffer {
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);
}
- (void)setupFrameBuffer {
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}
- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:#"glsl"];
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(#"Error loading shader: %#", error.localizedDescription);
exit(1);
}
GLuint shaderHandle = glCreateShader(shaderType);
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = [shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
glCompileShader(shaderHandle);
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
return shaderHandle;
}
- (void)compileShaders {
GLuint vertexShader = [self compileShader:#"SimpleVertex" withType:GL_VERTEX_SHADER];
GLuint fragmentShader = [self compileShader:#"SimpleFragment" withType:GL_FRAGMENT_SHADER];
GLuint programHandle = glCreateProgram();
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
glUseProgram(programHandle);
_positionSlot = glGetAttribLocation(programHandle, "Position");
_colorSlot = glGetAttribLocation(programHandle, "SourceColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
_modelViewUniform = glGetUniformLocation(programHandle, "Modelview");
_texCoordSlot = glGetAttribLocation(programHandle, "TexCoordIn");
glEnableVertexAttribArray(_texCoordSlot);
_textureUniform = glGetUniformLocation(programHandle, "Texture");
}
- (void)setupVBOs {
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)render {
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _floorTexture);
glUniform1i(_textureUniform, 0);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),
GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (GLuint)setupTexture:(NSString *)fileName {
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage) {
NSLog(#"Failed to load image %#", fileName);
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
[self setupContext];
[self setupDepthBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self compileShaders];
[self setupVBOs];
[self render];
}
_floorTexture = [self setupTexture:#"tile_floor.png"];
return self;
}
#end
Vertex shader:
attribute vec4 Position;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
Fragment shader:
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = texture2D(Texture, TexCoordOut);
}
I can create a gradient by changing the values for gl_FragColor, but I have tried several different textures and am at a loss.
This could be depending on the fact that your textures are not power of 2 (i.e. 512X512)
Some OpenGL drivers react in weird ways to this, some others just perform a rescaling of the textures to the nearest power of 2 size.
From OpenGL gold book you can find the below:
You can find a quite good explanation in the OpenGL Gold Book, the OpenGL ES 2.0:
In OpenGL ES 2.0, textures can have non-power-of-two (npot)
dimensions. In other words, the width and height do not need to be a
power of two. However, OpenGL ES 2.0 does have a restriction on the
wrap modes that can be used if the texture dimensions are not power of
two. That is, for npot textures, the wrap mode can only be
GL_CLAMP_TO_EDGE and the minifica- tion filter can only be GL_NEAREST
or GL_LINEAR (in other words, not mip- mapped). The extension
GL_OES_texture_npot relaxes these restrictions and allows wrap modes
of GL_REPEAT and GL_MIRRORED_REPEAT and also allows npot textures to
be mipmapped with the full set of minification filters.
I hope this helps.
Cheers

Weird dispatch_async memory behavior

I have the following dispatch_async code:
dispatch_async(openGLESContextQueue, ^{
[(EAGLView *)self.view setFramebuffer];
// Replace the implementation of this method to do your own custom drawing.
static const GLfloat squareVertices[] = {
-0.5f, -0.33f,
0.5f, -0.33f,
-0.5f, 0.33f,
0.5f, 0.33f,
};
static const GLubyte squareColors[] = {
127, 127, 0, 127,
0, 255, 255, 255,
0, 0, 0, 0,
255, 0, 255, 255,
};
static float transY = 0.0f;
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
transY += 0.075f;
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[(EAGLView *)self.view presentFramebuffer];
});
And when in Instruments, and even though the animation is running fine, I get tons of "64 bytes malloc"s that never get freed. Anyone know why?
I was finally able to solve the problem using semaphores:
if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) == 0)
{
dispatch_async(openGLESContextQueue, ^{
[(EAGLView *)self.view setFramebuffer];
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
transY += 0.075f;
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
[(EAGLView *)self.view presentFramebuffer];
dispatch_semaphore_signal(frameRenderingSemaphore);
});
}
I guess the dispatch queue was getting flooded without time to handle every opengl redraw. This way, it will only process one redraw at a time, asynchronously. Curiously, it has no side effects on the frame rate! :D
Thanks :)

Drawing a text along a path in QuartzCore

Say I have an array of points that form a line and a text. How can I go about drawing the text along this line in
- (void)drawRect:(CGRect)rect
of a UIView?
I am able to draw the path without a problem. Is there a standard method that I overlooked or a framework that would allow me to draw the text along that path? Ideally I would like to do this using only QuartzCore/CoreGraphics.
I tried calculating the width of each character and rotating every character. This kind of works, but I was wondering if there is a more elegant method.
I believe you can do this in Mac OS X, but the closest you'll come on the iPhone is CGContextShowGlyphsWithAdvances and this wont even rotate.
It shouldn't be too hard to use a loop and draw each character using something like the following. This is adapted from Apple's documentation and not tested, so beware:
CGContextSelectFont(myContext, "Helvetica", 12, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(myContext, 10);
CGContextSetTextDrawingMode(myContext, kCGTextFillStroke);
CGContextSetRGBFillColor(myContext, 0, 0, 0, 1);
CGContextSetRGBStrokeColor(myContext, 0, 0, 0, 1);
NSUInteger charIndex = 0;
for(NSString *myChar in arrayOfChars) {
char *cString = [myChar UTF8String];
CGPoint charOrigin = originForPositionAlongPath(charIndex, myPath);
CGFloat slope = slopeForPositionAlongPath(charIndex, myPath);
CGContextSetTextMatrix(myContext, CGAffineTransformMakeRotation(slope));
CGContextShowTextAtPoint(myContext, charOrigin.x, charOrigin.y, cString, 1);
}
Edit: Here's an idea of the PositionAlongPath functions. Again, they aren't tested, but should be close. originAlong... returns (-1, -1) if you run out of path.
CGPoint originForPositionAlongPath(int index, NSArray *path) {
CGFloat charWidth = 12.0;
CGFloat widthToGo = charWidth * index;
NSInteger i = 0;
CGPoint position = [path objectAtIndex:i];
while(widthToGo >= 0) {
//out of path, return invalid point
if(i >= [path count]) {
return CGPointMake(-1, -1);
}
CGPoint next = [path objectAtIndex:i+1];
CGFloat xDiff = next.x - position.x;
CGFloat yDiff = next.y - position.y;
CGFloat distToNext = sqrt(xDiff*xDiff + yDiff*yDiff);
CGFloat fracToGo = widthToGo/distToNext
//point is before next point in path, interpolate the answer
if(fracToGo < 1) {
return CGPointMake(position.x+(xDiff*fracToGo), position.y+(yDiff*fracToGo));
}
//advance to next point on the path
widthToGo -= distToNext;
position = next;
++i;
}
}
CGFloat slopeForPositionAlongPath(int index, NSArray *path) {
CGPoint begin = originForPositionAlongPath(index, path);
CGPoint end = originForPositionAlongPath(index+1, path);
CGFloat xDiff = end.x - begin.x;
CGFloat yDiff = end.y - begin.y;
return atan(yDiff/xDiff);
}
This is probably irrelevant but you can text along a path with SVG (http://www.w3.org/TR/SVG/text.html#TextOnAPath), and the iPhoneOS supports it.
Above example unfortunately didn't work as expected.
I have now finally found the correct way to paint a text along the path.
Here we go:
You cannot take this code 1:1 as its just excerpted from my application, but i will make things clear with some comments.
// MODIFIED ORIGIN FUNCTION
CGPoint originForPositionAlongPath(float *l, float nextW, int index, NSArray *path) {
CGFloat widthToGo = *l + nextW;
NSInteger i = 0;
CGPoint position = [[path objectAtIndex:i] CGPointValue];
while(widthToGo >= 0) {
//out of path, return invalid point
if(i+1 >= [path count]) {
return CGPointMake(-1, -1);
}
CGPoint next = [[path objectAtIndex:i+1] CGPointValue];
CGFloat xDiff = next.x - position.x;
CGFloat yDiff = next.y - position.y;
CGFloat distToNext = sqrt(xDiff*xDiff + yDiff*yDiff);
CGFloat fracToGo = widthToGo/distToNext;
//point is before next point in path, interpolate the answer
if(fracToGo < 1) {
return CGPointMake(position.x+(xDiff*fracToGo), position.y+(yDiff*fracToGo));
}
//advance to next point on the path
widthToGo -= distToNext;
position = next;
++i;
}
}
// MODIFIED SLOPE FUNCTION
CGFloat slopeForPositionAlongPath(float* l, float nextW, int index, NSArray *path) {
CGPoint begin = originForPositionAlongPath(l, 0, index, path);
CGPoint end = originForPositionAlongPath(l, nextW, index+1, path);
CGFloat xDiff = end.x - begin.x;
CGFloat yDiff = end.y - begin.y;
return atan(yDiff/xDiff);
}
// IMPORTANT: CHARACTER WIDTHS FOR HELVETICA, ABOVE EXAMPLE USES FIXED WIDTHS WHICH IS NOT ACCURATE
float arraychars[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0.278, 0.333, 0.474, 0.556, 0.556, 0.889, 0.722, 0.278,
0.333, 0.333, 0.389, 0.584, 0.278, 0.584, 0.278, 0.278,
0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.556,
0.556, 0.556, 0.333, 0.333, 0.584, 0.584, 0.584, 0.611,
0.975, 0.722, 0.722, 0.722, 0.722, 0.667, 0.611, 0.778,
0.722, 0.278, 0.556, 0.722, 0.611, 0.833, 0.722, 0.778,
0.667, 0.778, 0.722, 0.667, 0.611, 0.722, 0.667, 0.944,
0.667, 0.667, 0.611, 0.333, 0.278, 0.333, 0.584, 0.556,
0.278, 0.556, 0.611, 0.556, 0.611, 0.556, 0.333, 0.611,
0.611, 0.278, 0.278, 0.556, 0.278, 0.889, 0.611, 0.611,
0.611, 0.611, 0.389, 0.556, 0.333, 0.611, 0.556, 0.778,
0.556, 0.556, 0.5, 0.389, 0.28, 0.389, 0.584, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0.278, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333, 0.333,
0.333, 0, 0.333, 0.333, 0, 0.333, 0.333, 0.333,
0.278, 0.333, 0.556, 0.556, 0.556, 0.556, 0.28, 0.556,
0.333, 0.737, 0.37, 0.556, 0.584, 0.333, 0.737, 0.333,
0.4, 0.584, 0.333, 0.333, 0.333, 0.611, 0.556, 0.278,
0.333, 0.333, 0.365, 0.556, 0.834, 0.834, 0.834, 0.611,
0.722, 0.722, 0.722, 0.722, 0.722, 0.722, 1, 0.722,
0.667, 0.667, 0.667, 0.667, 0.278, 0.278, 0.278, 0.278,
0.722, 0.722, 0.778, 0.778, 0.778, 0.778, 0.778, 0.584,
0.778, 0.722, 0.722, 0.722, 0.722, 0.667, 0.667, 0.611,
0.556, 0.556, 0.556, 0.556, 0.556, 0.556, 0.889, 0.556,
0.556, 0.556, 0.556, 0.556, 0.278, 0.278, 0.278, 0.278,
0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.611, 0.584,
0.611, 0.611, 0.611, 0.611, 0.611, 0.556, 0.611, 0.556,
};
void o_DrawContourLabel(void *myObjectInstance, TransBuffer* transBuffer, MapPainterIphone* mp,const Projection& projection,
const MapParameter& parameter,
const LabelStyle& style,
const std::string& text,
size_t transStart, size_t transEnd){
// HERE WE Initialize the font etc.
CGContextSelectFont(context, "Helvetica-Bold", 10, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, 0);
CGContextSetTextDrawingMode(context, kCGTextFillStroke);
CGContextSetLineWidth(context, 3.0);
CGContextSetRGBFillColor(context, style.GetTextR(), style.GetTextG(), style.GetTextB(), style.GetTextA());
CGContextSetRGBStrokeColor(context, 1, 1, 1, 1);
// Here we prepare a NSArray holding all waypoints of our path.
// I fill it from a "transBuffer" but you may fill it with whatever you want
NSMutableArray* path = [[NSMutableArray alloc] init];
if (transBuffer->buffer[transStart].x<transBuffer->buffer[transEnd].x) {
for (size_t j=transStart; j<=transEnd; j++) {
if (j==transStart) {
[path addObject:[NSValue valueWithCGPoint:CGPointMake(transBuffer->buffer[j].x,transBuffer->buffer[j].y)]];
}
else {
[path addObject:[NSValue valueWithCGPoint:CGPointMake(transBuffer->buffer[j].x,transBuffer->buffer[j].y)]];
}
}
}
else {
for (size_t j=0; j<=transEnd-transStart; j++) {
size_t idx=transEnd-j;
if (j==0) {
[path addObject:[NSValue valueWithCGPoint:CGPointMake(transBuffer->buffer[idx].x,transBuffer->buffer[idx].y)]];
}
else {
[path addObject:[NSValue valueWithCGPoint:CGPointMake(transBuffer->buffer[idx].x,transBuffer->buffer[idx].y)]];
}
}
}
// if path is too short for "estimated text length" then exit
if (pathLength(path)<text.length()*7) {
// Text is longer than path to draw on
return;
}
// NOW PAINT CHAR FOR CHAR USING CHARACTER WIDTHS TABLE
float lenUpToNow = 0;
CGAffineTransform transform=CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
NSUInteger charIndex = 0;
for(int i=0;i<text.length();i++) {
char *cString = (char*)malloc(2*sizeof(char));
cString[0] = text.at(i);
cString[1]=0;
float nww = arraychars[cString[0]]*8*1.4;
CGPoint charOrigin = originForPositionAlongPath(&lenUpToNow, 0, charIndex, path);
CGFloat slope = slopeForPositionAlongPath(&lenUpToNow, nww, charIndex, path);
std::cout << " CHARACTER " << cString << " placed at " << charOrigin.x << "," << charOrigin.y << std::endl;
// DO NOT FORGET TO DO THIS (TWO TRANSFORMATIONS) .. one for the rotation
// and one for mirroring, otherwise the text will be mirrored due to a
// crappy coordinate system in QuartzCore.
CGAffineTransform ct = CGAffineTransformConcat(transform,CGAffineTransformMakeRotation(slope));
CGContextSetTextMatrix(context, ct);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextShowTextAtPoint(context, charOrigin.x, charOrigin.y, cString, 1);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextShowTextAtPoint(context, charOrigin.x, charOrigin.y, cString, 1);
std::cout << " ... len (" << (int)cString[0] << ") = " << arraychars[cString[0]] << " up to now: " << lenUpToNow << std::endl;
lenUpToNow += nww;
charIndex++;
free(cString);
}
}