Related
I've been trying for the last two and a half hours to get a simple 2D texture renderer working using opengl es on ios. I've tried following this tutorial to no avail. I've checked my gl errors , checked my triangle ordering, even tried switching back to ES1 to use the fixed function pipeline to absolutely no avail. I'm at a complete loss here, what is going wrong? For completeness' sake, here is my setup and draw code:
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
GLenum err = 0;
glEnable(GL_TEXTURE_2D);
CHECK_GL_ERR();
glEnable(GL_BLEND);
CHECK_GL_ERR();
glBlendFunc(GL_ONE, GL_SRC_COLOR);
CHECK_GL_ERR();
glGenTextures(1, &texture);
CHECK_GL_ERR();
glBindTexture(GL_TEXTURE_2D, texture);
CHECK_GL_ERR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
CHECK_GL_ERR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
CHECK_GL_ERR();
UIImage *image = [UIImage imageNamed:#"GL_Target"];
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 );
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM( context, 0, height - 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);
CHECK_GL_ERR();
CGContextRelease(context);
free(imageData);
effect = [[GLKBaseEffect alloc] init];
}
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
GLfloat rot = 0.0;
GLenum err = 0;
glColor4f(0.0, 0.0, 0.0, 0.0);
CHECK_GL_ERR();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CHECK_GL_ERR();
glEnableClientState(GL_VERTEX_ARRAY);
CHECK_GL_ERR();
glEnableClientState(GL_NORMAL_ARRAY);
CHECK_GL_ERR();
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
CHECK_GL_ERR();
static const GLfloat vertices[] = {
-1.0, 1.0, -0.0,
1.0, 1.0, -0.0,
-1.0, -1.0, -0.0,
1.0, -1.0, -0.0
};
static const GLfloat normals[] = {
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0
};
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0
};
glLoadIdentity();
CHECK_GL_ERR();
glTranslatef(0.0, 0.0, -3.0);
CHECK_GL_ERR();
glRotatef(rot, 1.0, 1.0, 1.0);
CHECK_GL_ERR();
glBindTexture(GL_TEXTURE_2D, texture);
CHECK_GL_ERR();
glVertexPointer(3, GL_FLOAT, 0, vertices);
CHECK_GL_ERR();
glNormalPointer(GL_FLOAT, 0, normals);
CHECK_GL_ERR();
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
CHECK_GL_ERR();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
CHECK_GL_ERR();
glDisableClientState(GL_VERTEX_ARRAY);
CHECK_GL_ERR();
glDisableClientState(GL_NORMAL_ARRAY);
CHECK_GL_ERR();
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
CHECK_GL_ERR();
static NSTimeInterval lastDrawTime;
if (lastDrawTime)
{
NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
rot+= 60 * timeSinceLastDraw;
}
lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
}
EDIT
After scrapping that approach, I am now trying to mirror this project because I was actually able to get that to build, run, and render on my machine. I started by copying the code I thought was important, then copied line by line, then copied entire file contents, then copied entire files, and then created a brand new project, copied over the view controller, sprite, and storyboard files and it still doesn't work. What part of project setup am I missing that is making new projects not work with 100% the exact same code as a project that does work?
From just that code, it seems you are missing binding the shaders.
glUseProgram(program);
Also make sure your shaders compile without error when you run the program.
The author of that blog has also a sample OpenGL ES 2.0 project for XCode in github. Please take a look at it, https://github.com/jlamarche/iOS-OpenGLES-Stuff
I use the following code to render a UIImage using openGL. the Texture2D class is from Apple, so I assume it's correct. The image does not get displayed. I just get the background color produced by glClearColor. My app is based on GLpaint sample code from Apple, so the setup is correct and I am able to draw lines using openGL just fine.
Is this render code below missing something?
- (void) render:(UIImage *)image
{
[EAGLContext setCurrentContext:context];
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// texturing will need these
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glOrthof(0, backingWidth, 0, backingHeight, -1, 1);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
Texture2D *texture = [[Texture2D alloc] initWithImage:image];
[texture drawInRect: self.frame];
// This application only creates a single color renderbuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple renderbuffers.
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
update: replaced the broken link in the original answer with actual code.
Here is the code that worked for me:
-(void) mergeWithImage:(UIImage*) image
{
if(image==nil)
{
return;
}
glPushMatrix();
glColor4f(256,
256,
256,
1.0);
GLuint stampTexture; // = texture.id;
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(1, &stampTexture);
glBindTexture(GL_TEXTURE_2D, stampTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
GLuint imgwidth = CGImageGetWidth(image.CGImage);
GLuint imgheight = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( imgheight * imgwidth * 4 );
CGContextRef context2 = CGBitmapContextCreate( imageData, imgwidth, imgheight, 8, 4 * imgwidth, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGContextTranslateCTM (context2, 0, imgheight);
CGContextScaleCTM (context2, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context2, CGRectMake( 0, 0, imgwidth, imgheight ) );
CGContextTranslateCTM( context2, 0, imgheight - imgheight );
CGContextDrawImage( context2, CGRectMake( 0, 0, imgwidth, imgheight ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgwidth, imgheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context2);
free(imageData);
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0
};
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
/*
These arrays would need to be changed if the size of the paintview changes. You must make sure that all image imput is 64x64, 256x256, 512x512 or 1024x1024. Here we are using 512, but you can use 1024 as follows:
use the numbers:
{
0.0, height, 0.0,
1024, height, 0.0,
0.0, height-1024, 0.0,
1024, height-1024, 0.0
}
*/
NSLog(#"height of me: %f", self.bounds.size.height);
static const GLfloat vertices[] = {
0.0, 643, 0.0,
1024, 643, 0.0,
0.0, -381, 0.0,
1024, -381, 0.0
};
static const GLfloat normals[] = {
0.0, 0.0, 1024,
0.0, 0.0, 1024,
0.0, 0.0, 1024,
0.0, 0.0, 1024
};
glBindTexture(GL_TEXTURE_2D, stampTexture);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, normals);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glPopMatrix();
glDeleteTextures( 1, &stampTexture );
// Display the buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
-(void) addImageToView{
UIImage* imageToAdd= [UIImage imageNamed:#"IMAGE_TO_ADD_TO_GL_VIEW.png"];
// all images added to the paining view MUST be 512x512.
// You can also add smaller images (even transformed ones) using this method - just add it to a UIView and then get it's graphics context
UIView* imageView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 512, 512)];
UIImageView* subView = [[UIImageView alloc] initWithImage:imageToAdd];
[imageView addSubview:subView];
UIImage* blendedImage =nil;
UIGraphicsBeginImageContext(imageView.frame.size);
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
blendedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self mergeWithImage: blendedImage ];
I'm trying to learn OpenGL on iOS. I'm following this tutorial.
http://www.raywenderlich.com/5235/beginning-opengl-es-2-0-with-glkit-part-2
I'm sure I followed the steps carefully, but when I get to the end, only don't see any shapes on the screen.
https://gist.github.com/seanhess/5356598
I do see the background color changing, so OpenGL is working in general. Just the call to glDrawElements doesn't seem to be doing anything.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
He has some demo code, but it's not the same as the code he has you write in the tutorial, and I want to understand why this doesn't work before pasting his in.
Where is the GLKBaseEffect supposed to be drawn? I don't see how we actually used it.
The following seems to be wrong, as all the vertices are the same:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
};
Even if everything else is correct, your triangle is degenerate as
all is vertices are coincident. When you fix the coordinates, make
sure that the indices reference the vertices in a counter-clockwise
fashion or, even better for your first experiments, call
glDisable(GL_CULL_FACE);
before drawing. You could try to pick your vertices like this:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
Edit
Try to comment away the second part of update:
/*
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
*/
The matrices you define put your object out of the final image. When you don't see anything on the screen one of the first things you should check are your transformation matrices. In your case, the problem is with the perspective transformation:
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
Your translated and rotated object must be located at a distance between the 3rd and 4th parameter of this call in order to be drawn, and actually the 3rd parameter is the distance of the so called near plane, and must be smaller than the 4th parameter, the far plane. A safe bet is usually 1 and 100 for these two parameters.
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
Edit 2
The following is a working version.
//
// HelloGLKitViewController.m
// OpenGL2Tutorial
//
// Created by Sean Hess on 4/10/13.
// Copyright (c) 2013 Sean Hess. All rights reserved.
//
#import "HelloGLKitViewController.h"
typedef struct {
float Position[3];
float Color[4];
} Vertex;
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
#interface HelloGLKitViewController () {
GLuint _vertexBuffer;
GLuint _indexBuffer;
float _rotation;
float _currentRed;
BOOL _increasing;
}
#property (nonatomic, strong) EAGLContext * context;
#property (nonatomic, strong) GLKBaseEffect * effect;
#end
#implementation HelloGLKitViewController
// I think this method just fills the objective-c stuff with the information from my c structs
- (void)setupGL {
[EAGLContext setCurrentContext:self.context];
self.effect = [GLKBaseEffect new];
glGenBuffers(1, &_vertexBuffer); // supposed to be an array of buffers, doing that trick again
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); // when I say "GL_ARRAY_BUFFER" I mean _vertexBuffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
self.effect = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) NSLog(#"FAiled to create ES Context");
GLKView * view = (GLKView *)self.view;
view.context = self.context;
// will automatically pause when interrupted
self.pauseOnWillResignActive = YES;
[self setupGL];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[self tearDownGL];
}
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(_currentRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// have to call after you change any properties in the effect, before drrawing
[self.effect prepareToDraw];
// We don't have to do this again, since we did it above in setupGL
// They're already bound to GL_ARRAY_BUFFER and GL_ELEMENT_ARRAYBUFFER
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
// remember my vertex array contains Vertex(s)
// so we're telling it how to read it
// position is 3 floats, the offset is based on that offsetof function
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Color));
// 1. pretty much always use triangles
// 2. the number of vertices to render. tricky way to do .length on array
// 3. the data type
// 4. seems like should be pointer to indices. We're using VBOs, so it's already set to the GL_ELEMENT_ARRAY_BUFFER. So give it 0.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
- (void)update {
if (_increasing) {
_currentRed += 1.0 * self.timeSinceLastUpdate;
} else {
_currentRed -= 1.0 * self.timeSinceLastUpdate;
}
if (_currentRed >= 1.0) {
_currentRed = 1.0;
_increasing = NO;
}
if (_currentRed <= 0.0) {
_currentRed = 0.0;
_increasing = YES;
}
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.paused = !self.paused;
NSLog(#"timeSinceLastUpdate: %f", self.timeSinceLastUpdate);
NSLog(#"timeSinceLastDraw: %f", self.timeSinceLastDraw);
NSLog(#"timeSinceFirstResume: %f", self.timeSinceFirstResume);
NSLog(#"timeSinceLastResume: %f", self.timeSinceLastResume);
}
#end
Whenever I attempt to render a textured quad, I end up with a triangular section of the texture distorted:
.
The texture is a PNG created in GIMP, and I've tried two seperate methods of loading the texture (both from Apple's own sample code). Each method of loading the texture produced different results (I don't know if it is different default settings, or if there is a problem with the texture), but I couldn't get either to render proper.
I've tried setting up my indices/verticles/texices in multiple different ways, from suggestions posted in Fastest way to draw quads in OpenGL ES? yet still no luck.
What could I be missing?
Code to Load Texture
- (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_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}
Texture Coordinates and Verticles
const GLfloat texices[] =
{ 0,1,
1,1,
0,0,
1,0 };
glActiveTexture(GL_TEXTURE0);
glUniform1i(_texturedTextureUniformSlot, 0);
glVertexAttribPointer(_texturedTextureSlot, 2, GL_FLOAT, GL_FALSE, 0, texices);
GLfloat vertices[] = {-1, -1, 0, //bottom left corner
-1, 1, 0, //top left corner
1, 1, 0, //top right corner
1, -1, 0}; // bottom right rocner
GLubyte indices[] = {0,1,2, // first triangle (bottom left - top left - top right)
0,2,3}; // second triangle (bottom left - top right - bottom right)
glVertexAttribPointer(3, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
It looks like your texture coordinates may be wrong (notice the texture appears to be wrapping around the left side).
Here is a snippet of code that I've used in the past:
const float quadPositions[] = { 1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0 };
const float quadTexcoords[] = { 1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0 };
// stop using VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
// setup buffer offsets
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), quadPositions);
glVertexAttribPointer(ATTRIB_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), quadTexcoords);
// ensure the proper arrays are enabled
glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_TEXCOORD0);
// draw
glDrawArrays(GL_TRIANGLES, 0, 2*3);
That should draw a two triangles at z=0. You'll want to setup your projection from -1 to 1 in width and height.
Edit:
Here's a working version of your code:
const GLfloat texices[] = { 0, 0,
0, 1,
1, 1,
1, 0 };
const GLfloat vertices[] = { -1, -1, 0, // bottom left corner
-1, 1, 0, // top left corner
1, 1, 0, // top right corner
1, -1, 0}; // bottom right corner
const GLubyte indices[] = { 0, 2, 1, // first triangle (bottom left - top left - top right)
0, 3, 2 };
// ensure no VBOs or IBOs are bound
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), vertices);
glVertexAttribPointer(ATTRIB_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), texices);
// ensure the proper arrays are enabled
glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_TEXCOORD0);
glDisable(GL_CULL_FACE);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
I want to draw text use Quartz 2D. The "menu" direction is wrong. I want "Menu" still readable and have 45 degree with X-axis. Below is my code:
CGContextSelectFont(context, "Arial", 12, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1); // 6
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));
CGContextSetTextMatrix(context, CGAffineTransformMakeRotation(45));
CGContextShowTextAtPoint(context,10, 10, "Menu", 4);
CGAffineTransformMakeRotation expects angle in radians, not in degrees.
#define DEGREES_TO_RADIANS(x) (M_PI * (x) / 180.0)
...
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));
[view setTransform:CGAffineTransformMakeRotation(M_PI / 2)];