GL_QUADS undeclared

Member
Posts: 61
Joined: 2009.01
Post: #1
Hey all.

I've been developing games for a long time, but never in Objective-C or on the iPhone. I'm attempting to adapt one of my simpler games to the iPhone right now, and as per expected I've hit a syntax-based question.

I'm creating a class that turns an image file into an OpenGL texture, then has a bunch of useful drawing methods for that texture. It is, quite appropriately, called "Sprite." I know a lot of these exist already, but I'm trying to familiarize myself with this language/framework so I'm writing my own.

Anyway, I'm very oddly getting a syntax error that GL_QUADS is undeclared, even though I'm using lots of other OpenGL enumerator constants with no problem and GL_TRIANGLES works. In addition, if I do use GL_TRIANGLES instead, I get some errors (maybe they're runtime errors, I'm not sure how XCode reports those) related to glBegin() and glEnd(). I'm assuming that either EAGL or the iPhone treat these differently than I'm used to. Help or explanation is appreciated.

(Also I know that the functionality is not complete here yet, like I'm not setting width and height, for example.)

The header file:
Code:
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

@interface Sprite : NSObject
{
    /* OpenGL name for the sprite texture */
    GLuint texture;
    
    /* The width of the texture being used by this Sprite. */
    GLfloat width;
    
    /* The height of the texture being used by this Sprite. */
    GLfloat height;
}

/* Actually creates a new sprite from an image.
* Use createSpriteFromImage externally.
*/
- (id) initFromImage:(NSString *)location;

/* Actually creates a new sprite from a texture.
* Use createSpriteFromTexture externally.
*/
- (id) initFromTexture:(GLuint)tex;

/* Creates a new sprite from the passed string location/filename. */
+ (Sprite *)createSpriteFromImage:(NSString *) location;

/* Creates a new sprite using a passed OpenGL texture. Smart sprite management
* should probably be used instead of this method. */
+ (Sprite *) createSpriteFromTexture:(GLuint) tex;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect)rect;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped;

@end

The class.
Code:
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "Sprite.h"


@implementation Sprite

- (id) initFromTexture:(GLuint) tex
{
    if (self = [super init])
    {
        texture = tex;
        return self;
    }
    return nil;
}

- (id) initFromImage:(NSString *) location
{
    // Create this sprite.
    if (self = [super init])
    {
        // Creates a Core Graphics image from an image file using our location.
        CGImageRef spriteImage = [UIImage imageNamed:location].CGImage;
        
        // Get the width and height of the image.
        size_t w = CGImageGetWidth(spriteImage);
        size_t h = CGImageGetHeight(spriteImage);

        //TODO - resize the width and the height to the nearest power of 2.
        
        //Only create a sprite if we were able to properly load the CG image.
        if(spriteImage)
        {
            // Allocated memory needed for the bitmap context
            GLubyte *spriteData = (GLubyte *) malloc(w * h * 4);
            
            // Use the bitmap creation function provided by the Core Graphics framework.
            CGContextRef spriteContext = CGBitmapContextCreate(spriteData, w, h, 8, w * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
            
            // After we create the context, we can draw the sprite image to the context.
            CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)w, (CGFloat)h), spriteImage);
            
            // We don't need the context at this point, so we need to release it to avoid memory leaks.
            CGContextRelease(spriteContext);
            
            // Now use OpenGL ES to generate a name for the texture.
            // Pass by reference so that our texture variable gets set.
            glGenTextures(1, &texture);
            
            // Bind the texture name.
            glBindTexture(GL_TEXTURE_2D, texture);
            
            // Specify a 2D texture image, providing a pointer to the image data in memory
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
            
            // Release the image data, which is now unused.
            free(spriteData);
        }
        
        return self;
    }
    return nil;
}

+ (Sprite *) createSpriteFromImage: (NSString *) location
{
    return [[[self alloc] initFromImage:location] autorelease];
}

+ (Sprite *) createSpriteFromTexture: (GLuint) tex
{
    return [[[self alloc] initFromTexture:tex] autorelease];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect) rect
{
    [self draw:rect withRotation:0.0f andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation
{
    [self draw:rect withRotation:rotation andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped
{
    //Push the matrix so we can keep it as it was previously.
    glPushMatrix();
    
    //Enable 2D textures.
    glEnable(GL_TEXTURE_2D);
    
    //Bind this texture.
    glBindTexture(GL_TEXTURE_2D, texture);
    
    // Set the texture parameters to use a minifying filter and a linear filer.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    //Store the coordinates/dimensions from the rectangle.
    CGFloat x = CGRectGetMinX(rect);
    CGFloat y = CGRectGetMinY(rect);
    CGFloat w = CGRectGetWidth(rect);
    CGFloat h = CGRectGetHeight(rect);
    
    //Translate the OpenGL context to the center of the sprite for rotation.
    glTranslatef(x+w/2, y+h/2, 0.0f);
    
    //Apply the rotation over the Z axis.
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);
    
    //Translate back to the top left corner of the sprite for drawing.
    glTranslatef(-w/2, -h/2, 0.0f);
    
    //Draw a quad textured to match the sprite.
    //********************************************************//
    //*****************SYNTAX ERROR HERE******************//
    //********************************************************//
    glBegin(GL_QUADS);
    //A flipped sprite has the texture width coords swapped.
    if (flipped)
    {
        glTexCoord2f(width,0);
        glVertex2f(0,0);
        
        glTexCoord2f(width,height);
        glVertex2f(0,height);
        
        glTexCoord2f(0,height);
        glVertex2f(width,height);
        
        glTexCoord2f(0,0);
        glVertex2f(width,0);
    }
    //A non-flipped sprite has texture coords matching the vertex coords.
    else
    {
        glTexCoord2f(0,0);
        glVertex2f(0,0);
        
        glTexCoord2f(0,height);
        glVertex2f(0,height);
        
        glTexCoord2f(width,height);
        glVertex2f(width,height);
        
        glTexCoord2f(width,0);
        glVertex2f(width,0);
    }
    glEnd();
    
    //Allow transparency and blending.
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //Restore the model view matrix to prevent contamination.
    glPopMatrix();
}

@end
Quote this message in a reply
Member
Posts: 39
Joined: 2008.09
Post: #2
An iPhone has an OpenGL ES 1.1, not OpenGL. So it's a little different. Use glDrawArrays() instead.
Quote this message in a reply
Member
Posts: 249
Joined: 2008.10
Post: #3
OpenGL ES (1.1 or 2.0) do not have inmediate mode. glBegin and glEnd are not available there.
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #4
GL_QUADS also doesn't exist in OpenGL ES. You'll need to use some sort of triangle mode instead. Since you're only drawing one quad at a time, you can change GL_QUADS to GL_TRIANGLE_FAN and use the same set of vertices.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #5
I just happened to put up a quick little example in another thread last night which you might find helpful for doing this using OpenGL ES (no quads, etc., etc.): http://www.idevgames.com/forum/showpost....ostcount=6

It looks like you're already on the right track with your loader, but the draw might be helpful. It's very simplistic and I just lightly modded the simple Xcode template, so it should look familiar.
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #6
Hey guys, thanks for the help. I've now got a successful Sprite class which I can use quite easily to put any image resources right into an OpenGL context.

Here it is, anyone can use it if they want to. Also, please let me know if you see anything wrong in here, extraneous statements, etc. I've tested it a fair amount but not infinitely.

Functionality:
Creates an OpenGL sprite from an image file, and provides simple draw methods that allow you to render it anywhere on the screen, with any rotation and flipped horizontally or not. Draws the sprite from its top left corner and rotates from its center.

Code:
The header file:
Code:
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

@interface Sprite : NSObject
{
    /* OpenGL name for the sprite texture */
    GLuint texture;
    
    /* The width of the texture being used by this Sprite. */
    GLfloat width;
    
    /* The height of the texture being used by this Sprite. */
    GLfloat height;
}

/* Actually creates a new sprite from an image.
* Use createSpriteFromImage externally.
*/
- (id) initFromImage:(NSString *)location;

/* Actually creates a new sprite from a texture.
* Use createSpriteFromTexture externally.
*/
- (id) initFromTexture:(GLuint)tex;

/* Creates a new sprite from the passed string location/filename. */
+ (Sprite *)createSpriteFromImage:(NSString *) location;

/* Creates a new sprite using a passed OpenGL texture. Smart sprite management
* should probably be used instead of this method. */
+ (Sprite *) createSpriteFromTexture:(GLuint) tex;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect)rect;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped;

@end

The class file:
Code:
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "Sprite.h"


@implementation Sprite

- (id) initFromTexture:(GLuint) tex
{
    if (self = [super init])
    {
        texture = tex;
        return self;
    }
    return nil;
}

- (id) initFromImage:(NSString *) location
{
    // Create this sprite.
    if (self = [super init])
    {
        // Creates a Core Graphics image from an image file using our location.
        CGImageRef spriteImage = [UIImage imageNamed:location].CGImage;
        
        // Get the width and height of the image.
        width = CGImageGetWidth(spriteImage);
        height = CGImageGetHeight(spriteImage);

        //TODO - resize the width and the height to the nearest power of 2.
        
        //Only create a sprite if we were able to properly load the CG image.
        if(spriteImage)
        {
            // Allocated memory needed for the bitmap context
            GLubyte *spriteData = (GLubyte *) malloc(width * height * 4);
            
            // Use the bitmap creation function provided by the Core Graphics framework.
            CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
            
            // After we create the context, we can draw the sprite image to the context.
            CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
            
            // We don't need the context at this point, so we need to release it to avoid memory leaks.
            CGContextRelease(spriteContext);
            
            // Now use OpenGL ES to generate a name for the texture.
            // Pass by reference so that our texture variable gets set.
            glGenTextures(1, &texture);
            
            // Bind the texture name.
            glBindTexture(GL_TEXTURE_2D, texture);
            
            // Specify a 2D texture image, providing a pointer to the image data in memory.
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
            
            // Release the image data, which is now unused.
            free(spriteData);
        }
        
        // Release the image, because now we've got an OpenGL texture for it.
        CGImageRelease(spriteImage);
        
        return self;
    }
    return nil;
}

+ (Sprite *) createSpriteFromImage: (NSString *) location
{
    return [[[self alloc] initFromImage:location] autorelease];
}

+ (Sprite *) createSpriteFromTexture: (GLuint) tex
{
    return [[[self alloc] initFromTexture:tex] autorelease];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect) rect
{
    [self draw:rect withRotation:0.0f andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation
{
    [self draw:rect withRotation:rotation andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped
{
    //Push the matrix so we can keep it as it was previously.
    glPushMatrix();
    
    //Store the coordinates/dimensions from the rectangle.
    CGFloat x = CGRectGetMinX(rect);
    CGFloat y = CGRectGetMinY(rect);
    CGFloat w = CGRectGetWidth(rect);
    CGFloat h = CGRectGetHeight(rect);
    
    //Translate the OpenGL context to the center of the sprite for rotation.
    glTranslatef(x+w/2, y+h/2, 0.0f);
    
    //Apply the rotation over the Z axis.
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);
    
    //Translate back to the top left corner of the sprite for drawing.
    glTranslatef(-w/2, -h/2, 0.0f);
    
    // Set up an array of values to use as the sprite vertices.
    GLfloat vertices[] =
    {
        0, 0,
        0, h,
        w, h,
        w, 0,
    };
    
    // Set up an array of values for the texture coordinates.
    GLfloat texcoords[] =
    {
        0, 0,
        0, 1,
        1, 1,
        1, 0,
    };
    
    //If the image is flipped, flip the texture coordinates.
    if (flipped)
    {
        texcoords[0] = 1;
        texcoords[2] = 1;
        texcoords[4] = 0;
        texcoords[6] = 0;
    }
    
    //Render the vertices by pointing to the arrays.
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
    
    // Set the texture parameters to use a linear filter when minifying.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    //Allow transparency and blending.
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //Enable 2D textures.
    glEnable(GL_TEXTURE_2D);
    
    //Bind this texture.
    glBindTexture(GL_TEXTURE_2D, texture);
    
    //Finally draw the arrays.
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
    //Restore the model view matrix to prevent contamination.
    glPopMatrix();
}

- (void) dealloc
{
    [self release];
    [super dealloc];
}

@end

Usage:
You can use one of 3 methods to draw a Sprite, each with increased complexity. In reality, however, the simpler methods are only for convenience and fill in default values for the more complex methods.
Code:
//Create a Sprite from an image.
Sprite sprite = [Sprite createSpriteFromImage:@"Sprite2.png"];

//Draw the sprite rotated 90 degrees and flipped.
//Its top left corner will be at 100,100 and it will have a size of 50x50.
[sprite draw:CGRectMake(100, 100, 50, 50) withRotation:90.0f andFlipped:YES];

//Draw the sprite rotated -15 (345) degrees and not flipped.
//Its top left corner will be at 100,100 and it will have a size of 50x50.
[sprite draw:CGRectMake(100, 100, 50, 50) withRotation:-15.0f];

Hey guys, thanks for the help. I've not got a successful Sprite class which I can use quite easily to put any image resources right into an OpenGL context.

Here it is, anyone can use it if they want to. Also, please let me know if you see anything wrong in here, extraneous statements, etc. I've tested it a fair amount but not infinitely.

[b]Functionality:[/b]
Creates an OpenGL sprite from an image file, and provides simple draw methods that allow you to render it anywhere on the screen, with any rotation and flipped horizontally or not. Draws the sprite from its top left corner and rotates from its center.

[b]Code:[/b]
The header file:
[code]
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

@interface Sprite : NSObject
{
    /* OpenGL name for the sprite texture */
    GLuint texture;
    
    /* The width of the texture being used by this Sprite. */
    GLfloat width;
    
    /* The height of the texture being used by this Sprite. */
    GLfloat height;
}

/* Actually creates a new sprite from an image.
* Use createSpriteFromImage externally.
*/
- (id) initFromImage:(NSString *)location;

/* Actually creates a new sprite from a texture.
* Use createSpriteFromTexture externally.
*/
- (id) initFromTexture:(GLuint)tex;

/* Creates a new sprite from the passed string location/filename. */
+ (Sprite *)createSpriteFromImage:(NSString *) location;

/* Creates a new sprite using a passed OpenGL texture. Smart sprite management
* should probably be used instead of this method. */
+ (Sprite *) createSpriteFromTexture:(GLuint) tex;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect)rect;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation;

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped;

@end

The class file:
Code:
//
//  Sprite.h
//  GLSprite
//
//    A Sprite is a class that contains one OpenGL texture which is created from
//    an image file. That texture can then be drawn using a variety of methods.
//
//  Created by Elijah Delventhal on 1/11/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "Sprite.h"


@implementation Sprite

- (id) initFromTexture:(GLuint) tex
{
    if (self = [super init])
    {
        texture = tex;
        return self;
    }
    return nil;
}

- (id) initFromImage:(NSString *) location
{
    // Create this sprite.
    if (self = [super init])
    {
        // Creates a Core Graphics image from an image file using our location.
        CGImageRef spriteImage = [UIImage imageNamed:location].CGImage;
        
        // Get the width and height of the image.
        width = CGImageGetWidth(spriteImage);
        height = CGImageGetHeight(spriteImage);

        //TODO - resize the width and the height to the nearest power of 2.
        
        //Only create a sprite if we were able to properly load the CG image.
        if(spriteImage)
        {
            // Allocated memory needed for the bitmap context
            GLubyte *spriteData = (GLubyte *) malloc(width * height * 4);
            
            // Use the bitmap creation function provided by the Core Graphics framework.
            CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
            
            // After we create the context, we can draw the sprite image to the context.
            CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
            
            // We don't need the context at this point, so we need to release it to avoid memory leaks.
            CGContextRelease(spriteContext);
            
            // Now use OpenGL ES to generate a name for the texture.
            // Pass by reference so that our texture variable gets set.
            glGenTextures(1, &texture);
            
            // Bind the texture name.
            glBindTexture(GL_TEXTURE_2D, texture);
            
            // Specify a 2D texture image, providing a pointer to the image data in memory.
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
            
            // Release the image data, which is now unused.
            free(spriteData);
        }
        
        // Release the image, because now we've got an OpenGL texture for it.
        CGImageRelease(spriteImage);
        
        return self;
    }
    return nil;
}

+ (Sprite *) createSpriteFromImage: (NSString *) location
{
    return [[[self alloc] initFromImage:location] retain];
}

+ (Sprite *) createSpriteFromTexture: (GLuint) tex
{
    return [[[self alloc] initFromTexture:tex] retain];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle.
*/
- (void) draw:(CGRect) rect
{
    [self draw:rect withRotation:0.0f andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation
{
    [self draw:rect withRotation:rotation andFlipped:NO];
}

/* Draws this sprite as the specified rectangle, using the
* x, y, width, and height of the passed rectangle. Also
* gives it the specified rotation. Flips it if YES is passed.
*/
- (void) draw:(CGRect)rect withRotation:(GLfloat)rotation andFlipped:(BOOL)flipped
{
    //Push the matrix so we can keep it as it was previously.
    glPushMatrix();
    
    //Store the coordinates/dimensions from the rectangle.
    CGFloat x = CGRectGetMinX(rect);
    CGFloat y = CGRectGetMinY(rect);
    CGFloat w = CGRectGetWidth(rect);
    CGFloat h = CGRectGetHeight(rect);
    
    //Translate the OpenGL context to the center of the sprite for rotation.
    glTranslatef(x+w/2, y+h/2, 0.0f);
    
    //Apply the rotation over the Z axis.
    glRotatef(rotation, 0.0f, 0.0f, 1.0f);
    
    //Translate back to the top left corner of the sprite for drawing.
    glTranslatef(-w/2, -h/2, 0.0f);
    
    // Set up an array of values to use as the sprite vertices.
    GLfloat vertices[] =
    {
        0, 0,
        0, h,
        w, h,
        w, 0,
    };
    
    // Set up an array of values for the texture coordinates.
    GLfloat texcoords[] =
    {
        0, 0,
        0, 1,
        1, 1,
        1, 0,
    };
    
    //If the image is flipped, flip the texture coordinates.
    if (flipped)
    {
        texcoords[0] = 1;
        texcoords[2] = 1;
        texcoords[4] = 0;
        texcoords[6] = 0;
    }
    
    //Render the vertices by pointing to the arrays.
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
    
    // Set the texture parameters to use a linear filter when minifying.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    //Allow transparency and blending.
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //Enable 2D textures.
    glEnable(GL_TEXTURE_2D);
    
    //Bind this texture.
    glBindTexture(GL_TEXTURE_2D, texture);
    
    //Finally draw the arrays.
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
    //Restore the model view matrix to prevent contamination.
    glPopMatrix();
}

- (void) dealloc
{
    [self release];
    [super dealloc];
}

@end

Usage:
You can use one of 3 methods to draw a Sprite, each with increased complexity. In reality, however, the simpler methods are only for convenience and fill in default values for the more complex methods.
Code:
//Create a Sprite from an image.
Sprite sprite = [Sprite createSpriteFromImage:@"Sprite2.png"];

//Draw the sprite rotated 90 degrees and flipped.
//Its top left corner will be at 200,110 and it will have a size of 76x50.
[sprite draw:CGRectMake(200, 110, 76, 50) withRotation:90.0f andFlipped:YES];

//Draw the sprite not rotated and not flipped.
//Its top left corner will be at -50,0 and it will have a size of 300x200.
[sprite draw:CGRectMake(-50, 0, 300, 200)];
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #7
I'm a newbie so I can't go back and edit my post, but I meant to say that I now have a working Sprite. Smile
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #8
demonpants Wrote:please let me know if you see anything wrong in here, extraneous statements, etc.

As previously discussed, this approach is fine for simple cases, but really not the way to do things if you're going to be animating thousands of sprites. You don't want to make a dozen GL calls per quad.
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #9
Ah great, that's incredibly useful information, thanks. I've never thought of that. Same as the reply in that post, I'll consider writing a SpriteManager class to concatenate all the sprite information into one draw if I get performance problems. Otherwise this will do for now.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #10
demonpants Wrote:Ah great, that's incredibly useful information, thanks. I've never thought of that. Same as the reply in that post, I'll consider writing a SpriteManager class to concatenate all the sprite information into one draw if I get performance problems. Otherwise this will do for now.

Even just implementing local transforms can help. It often depends on how much data you're pushing around. [e.g. 2D v 3D coords]

arekkusu *really* knows what he's talking about, so take very special heed of his advice (even if it doesn't make sense on first take)... but yes, do first, measure next, optimize last, is the standing rule. Wink
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #11
Minor ObjC nitpick:

Code:
+ (Sprite *) createSpriteFromImage: (NSString *) location
{
    return [[[self alloc] initFromImage:location] retain];
}

+ (Sprite *) createSpriteFromTexture: (GLuint) tex
{
    return [[[self alloc] initFromTexture:tex] retain];
}

Those should be autoreleased, not retained! Most users of ObjC expect class factory methods which create new objects to return autoreleased objects...
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #12
Not only are all Objective-C programmers expecting it to be autoreleased, retaining it is the exact opposite of what you want to do here.

A Sprite object created with one of these methods will have a retain count of 2. Chances are, you aren't releasing it twice when you are done. Not only are most likely leaking this object, anyone else using this class is definitely going to leak it.
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #13
I started with autorelease, but the program would inexplicably release my Sprite that I was still referencing, so I changed it to retain. I'm not sure exactly why it's doing this, but it's been causing a lot of problems. I'm aware that I should be using autorelease, but like I said it causes crashes repeatedly after the updateView function has been called just once. So somehow the autorelease thing thinks that my Sprite has gone out of focus and so deletes it. I put in the retain because this fixed it, and I'm only creating Sprites once each time the game is started up, storing them in a SpriteManager class, and referencing them via string keys from a Dictionary. I assumed that because I was putting them in a Dictionary retain would be called automatically, as would release when I pulled them out of the dictionary. This seems like it's supposed to be the case, anyway.

However, pretty much everything I've been making has been getting autoreleased at the wrong time, making the program crash. Speaking of, why does XCode have such awful error reporting? I get no error half the time and the other half I get the debugger but it doesn't tell me exactly where/what happened. Occasionally I get an obscure exception, but that's pretty rare.

Anyway, I've been creating the Sprite just as I posted above, and it has been a class variable. I still don't know why it's autoreleasing itself improperly, but after having gone beyond that I've discovered that other classes I've made are also all autoreleasing themselves. So, that's the long answer on why I put retain in there.
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #14
Well I went back to it and after putting it in my dictionary it actually does work with autorelease. The original problem was when I had a pointer to one Sprite in my View. For some reason, it would be released if I didn't tell it to retain. No such problem now, however, because dictionary calls retain.

I guess what would have been smart in the first place would have been to call retain after instantiating the Sprite?
Quote this message in a reply
Member
Posts: 73
Joined: 2009.03
Post: #15
I am brand new to iPhone dev, though I do have PC game dev experience. I tried your Sprite class, but without success. I don't know if I have to have my program set up a certain way to use this class, but basically I'm using the view-based template. The program crashes on the glGenTextures line. When I step through the code, that line causes the program to receive signal "EXC_BAD_ACCESS", whatever that means. Maybe I just don't have my program set up correctly. Do you have an example program that uses the class? Thanks.

(edit) I think I have figured out to use the OpenGL ES template, which is what the SpriteGL example program is based on. But I'm still getting the same error on the same line when trying to create the sprite. It's weird, since I noticed that the SpriteGL code for creating the sprite is essentially identical, and that works fine.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Error: 'NSImage' undeclared btarb24 2 3,409 Aug 31, 2009 01:12 AM
Last Post: btarb24