Sunday, December 6, 2009

Drawing Rotating Pyramids (Tutorial)

As promised, code with comments on how it works:

Step 1: Add the OpenGL framework to an empty cocoa application.

Step 2: Open the .xib file for the application and drag an NSOpenGLView into the window. Bring up the inspector and click on the identity tab. The Class name should be changed to 'MyOpenGLView'.

Step 3:
.h file:

#import

#include

#include

//Color Depth

#define BITS_PER_PIXEL 32.0

//Depth of Z Buffer

#define DEPTH_SIZE 32.0

//Frames per Second

#define DEFAULT_FRAME_RATE 60.0f


@interface MyOpenGLView : NSOpenGLView

{

//The timer that runs 60 times/second

NSTimer *renderTimer;

}


//Keep track of rotation angle

float rotTri = 0.0f;


//Initialization function for OpenGL

- (void)initGL;


//Function to draw a pyramid

static void drawAnObject();



@end


Step 4:
.m file:

//Run at start

-(void)awakeFromNib

{

NSOpenGLPixelFormat *nsglFormat;

//Specify Attributes to allow screen to use various buffers

NSOpenGLPixelFormatAttribute attr[] =

{

//Enable Z sorting (make sure that polygons in front will overlap those in back)

NSOpenGLPFADoubleBuffer,

//Use Hardware Acceleration for graphics

NSOpenGLPFAAccelerated,

//Specify color depth

NSOpenGLPFAColorSize, BITS_PER_PIXEL,

//Specify Z depth

NSOpenGLPFADepthSize, DEPTH_SIZE,

//Anti-Aliasing:

NSOpenGLPFASampleBuffers, 8,

NSOpenGLPFASamples, 32,

NSOpenGLPFAMultisample,

0

};

//Set pixel format to include the attributes specified in the array attr[]

nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];

//Use the pixel format for the openGL view

[self setPixelFormat:nsglFormat];


//Initialize the view

[self initGL];

//Redraw view when window changes size

[self setPostsFrameChangedNotifications: YES];

//Update every 60 times a second

renderTimer = [NSTimer timerWithTimeInterval:1.0/60.0

target:self

selector:@selector(timerFired:)

userInfo:nil

repeats:YES];

//Activate timer to fire

[[NSRunLoop currentRunLoop] addTimer:renderTimer

forMode:NSDefaultRunLoopMode];

//Ensure timer fires during resize

[[NSRunLoop currentRunLoop] addTimer:renderTimer

forMode:NSEventTrackingRunLoopMode];

}


//Action to run when the timer is fired

- (void)timerFired:(id)sender

{

//Increase the rotation angle

rotTri += 1.0f;


//Tell the screen it needs to refresh

[self setNeedsDisplay:YES];

}


//Setup OpenGL view

- (void)initGL

{

printf("initGL\n");

// Synchronize buffer swaps with vertical refresh rate

GLint swapInt = 1;

[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];


//Apply Future Operations to The Projection Matrix

glMatrixMode(GL_PROJECTION);

//Reset The Projection Matrix

glLoadIdentity();

// Calculate The Aspect Ratio Of The Window

gluPerspective(45.0f,640.0f/480.0f,0.1f,100.0f);

//Select The Modelview Matrix

glMatrixMode(GL_MODELVIEW);

// Reset The Modelview Matrix

glLoadIdentity();

glShadeModel(GL_SMOOTH); //Smooth Shading

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //set clear color to black

glClearDepth(1.0f); // Depth Buffer Setup

glEnable(GL_DEPTH_TEST); // Enables Depth Testing

glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations

}


//Function to draw a pyramid

static void drawAnObject()

{

//Draw a 3-sided pyramid

glBegin(GL_TRIANGLES);

//DAC (counterclockwise points)

glColor3f(1.0f, 0.0f,0.0f); //RED

glVertex3f(1.0f, -1.0f,-0.798f); //D

glColor3f(0.0f, 1.0f,0.0f); //GREEN

glVertex3f(0.0f, -0.333f,0.798f); //A

glColor3f(0.0f, 0.0f,1.0f); //BLUE

glVertex3f(-1.0f, -1.0f,-0.798f); //C

//DCB

glColor3f(1.0f, 0.0f,0.0f); //RED

glVertex3f(1.0f, -1.0f,-0.798f); //D

glColor3f(0.0f, 0.0f,1.0f); //BLUE

glVertex3f(-1.0f, -1.0f,-0.798f); //C

glColor3f(1.0f, 0.0f,1.0f); //Violet

glVertex3f(0.0f,1.0f,-0.798f); //B

//CAB

glColor3f(0.0f, 0.0f,1.0f); //BLUE

glVertex3f(-1.0f, -1.0f,-0.798f); //C

glColor3f(0.0f, 1.0f,0.0f); //GREEN

glVertex3f(0.0f, -0.333f,0.798f); //A

glColor3f(1.0f, 0.0f,1.0f); //Violet

glVertex3f(0.0f,1.0f,-0.798f); //B

//BAD

glColor3f(1.0f, 0.0f,1.0f); //Violet

glVertex3f(0.0f,1.0f,-0.798f); //B

glColor3f(0.0f, 1.0f,0.0f); //GREEN

glVertex3f(0.0f, -0.333f,0.798f); //A

glColor3f(1.0f, 0.0f,0.0f); //RED

glVertex3f(1.0f, -1.0f,-0.798f); //D

glEnd();


}


//Draw Loop

- (void) drawRect: (NSRect) bounds

{

//Clear the screen and depth buffer

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

//Reset the current modelview matrix

glLoadIdentity();


//Move along the x and z axis

glTranslatef( -1.0f, 0.0f, -5.0f );

//rotate the modelview matrix by an angle of rotTri around the vector <1,>

glRotatef( rotTri,1.0f, 1.0f, 1.0f );

//Draw a pyramid to the buffers

drawAnObject();

//Reset Modelview

glLoadIdentity();

glTranslatef( 1.2f, 0.5f, -5.0f );

glRotatef( -5.0f*rotTri,0.0f, 1.0f, 0.0f );

drawAnObject();

//Display the buffer content to the screen

[ [ self openGLContext ] flushBuffer ];

}