Detect MouseClick in C using GLut [duplicate] - c

I am a beginner at OpenGL and I am trying to create a game in which as background I have a raw image. When the game starts I display that image and I want to be able to click on it and to display another image afterwards. I tried using the function glutMouseFunc but when I try to run the program I receive a message which says that the program stopped working.
Here are some parts of my code: I have a global variable onMouse; if I click the mouse button the variable takes the value 1 and if it has the value 1 I try to load the second image.
int onMouse;
void mouseClicks(int button, int state, int x, int y) {
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
onMouse = 1;
}
}
And this is the main function:
//load first texture
texture = LoadTextureRAW( "2 Lock screen.raw", TRUE );
glutMouseFunc(mouseClicks);
if(onMouse == 1){
//load second texture
texture = LoadTextureRAW( "in_game.raw", TRUE );
}
What am I doing wrong?
EDIT I have made some changes to the code, but the background image still doesn't change. Here is the new main function:
glutCreateWindow("Game");
texture = LoadTextureRAW( "2 Lock screen.raw", 1 );
glutDisplayFunc(display);
glutMouseFunc(mouseClicks);
glutKeyboardFunc(key);
glutMainLoop();
if(onMouse == 1){
texture = LoadTextureRAW( "in_game.raw", 2 );
glutDisplayFunc(display);
}
And this is the display function in which I map the texture to a quad:
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT );
// setup texture mapping
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, texture );
glPushMatrix();
glBegin( GL_QUADS );
glTexCoord2d(1.0,0.0); glVertex3d(1.0,1.0, 1.0);
glTexCoord2d(0.0,0.0); glVertex3d(-1.0,1.0,1.0);
glTexCoord2d(0.0,1.0); glVertex3d(-1.0,-1.0, -1.0);
glTexCoord2d(1.0,1.0); glVertex3d(1.0,-1.0, 1.0);
glEnd();
glPopMatrix();
glutSwapBuffers();
// free the texture
FreeTexture( texture );

You have the order wrong.
glutMouseFunc(mouseClicks);
Here you register the function to be called when the mouse is clicked.
if(onMouse == 1) {
You immediately check if the mouse had been clicked. It's impossible for the mouse to have been clicked in the brief period between these two lines, and glutMainLoop hasn't been entered yet so your program didn't even have a chance to listen for mouse events.
As for the crash, I can't help you debug it with just the code you have provided. Please try a debugger and find which line causes the crash.

What am I doing wrong?
You're expecting glutMouseFunc to wait for a mouse click. This is not how GLUT works (GLUT is not part of OpenGL BTW). Another callback to be registered is the drawing function (usually called display in GLUT based programs).
Once you enter the GLUT main loop (glutMainLoop() call) user events are processed and if a redisplay is requested the display function is called.
So here's what you do (in simplified pseudocode)
// Define bitmasks for mouse status, we assume mice have less than 17 buttons
#define MB_LEFT 0
#define MB_MIDDLE 1
#define MB_RIGHT 2
#define LMB_PRESSED (1<<0)
#define MMB_PRESSED (1<<1)
#define RMB_PRESSED (1<<2)
#define LMB_CLICKED (1<<16)
#define MMB_CLICKED (1<<17)
#define RMB_CLICKED (1<<18)
#define MB_PRESSED(state, button) (1<<(button))
#define MB_CLICKED(state, button) (1<<((button)+16)))
#define MB_MASK_PRESSED 0x0000ffffL
#define MB_MASK_CLICKED 0xffff0000L
uint32_t mouse_status = 0;
void onMouseButton(int button, int state, int x, int y)
{
int b;
switch(button) {
case GLUT_LEFT_BUTTON: b=MB_LEFT; break;
case GLUT_MIDDLE_BUTTON: b=MB_MIDDLE; break;
case GLUT_RIGHT_BUTTON: b=MB_RIGHT; break;
}
if(mouse_status & MB_PRESSED(b) && GLUT_UP == state) {
mouse_status |= MB_CLICKED(b);
}
if( !(mouse_status & MB_PRESSED(b)) && GLUT_DOWN == state) {
mouse_status = (mouse_status & ~(0L | MB_CLICKED(b))) | MB_PRESSED(b);
}
glutPostRedisplay();
}
void display(void)
{
if(mouse_status & MB_CLICKED(MB_LEFT)) {
/* do something */
…
/* clear the click flag */
mouse_status &= ~MB_MASK_CLICKED;
}
}
int main(…)
{
…
glutCreateWindow(…);
glutDisplayFunc(display);
glutMouseFunc(onMouseButton);
glutMainLoop();
}
You can of course use any other kind of structure you like to pass the mouse button status between program parts. I prefer bitmasks for such. Other people may prefer arrays (personally I don't like arrays for tasks like this, because they're not as easy to look at in a debugger than a simple bitfield).

glutMouseFunc registers a callback: a function to be called on specific events (here mouse events). These events are collected by glutMainLoop, which has not been called yet when you test onMouse.
Another thing, though I cannot tell for sure from the small code excerpt you provide, is that you'd better load the assets from the start of the programme, rather than wait for a user event to do it. Load them first, and simply change texture to whichever id correspond to the texture you wish to display then.

Related

SDL, how to fix key input lag [duplicate]

I am making a game where a nozzle of a tank rotates around when space is pressed to shoot enemies. However, right in the beginning when the space is pressed, it seems to stop for a few milliseconds and then continues without any problems. How can I make it so that the rotations is smooth and consistent as soon as the space is pressed, right from the start? Here is a minimal reproducible example:
#include "SDL.h"
#include <iostream>
class Nozzle
{
public:
void draw(SDL_Renderer* renderer, int cx, int cy, int l)
{
float x = ((float)cos(angle) * l) + cx;
float y = ((float)sin(angle) * l) + cy;
SDL_RenderDrawLine(renderer, cx, cy, (int)x, (int)y);
}
void plusAngle(float a)
{
angle += a;
}
private:
float angle = 0.0f;
};
int main(int argc, char* argv[])
{
SDL_Window* window = SDL_CreateWindow("RGame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 600, false);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Event event;
Nozzle nozzle;
bool running = true;
while (running)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
running = false;
if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_SPACE)
nozzle.plusAngle(0.1f);
}
}
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
nozzle.draw(renderer, 600, 300, 70);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_SPACE)
nozzle.plusAngle(0.1f);
}
This is not how you do controls in a game.
If you open a text editor and hold a key, you'll see one letter being typed, then, after a delay, a steady stream of the same repeated letter. And SDL does the same thing, it gives you fake repeated "key down" events in this manner. This is normally used for editing text, not for game controls. (Those repeated events are marked by event.key.repeat == true).
What you should do is to create something like bool space_key_down, set it to true when you get SDL_KEYDOWN for the space key, and to false when you get SDL_KEYUP for the same key. Then, outside of the event loop, if the variable is set, you rotate your nozzle.
Or you can use SDL_GetKeyboardState. SDL does this thing automatically for every key, and you can access the list of flags it maintains using this function.
Also, while we're at it, you normally don't want to use keycodes (.sym == SDLK_SPACE) for game controls. Prefer scancodes (.scancode == SDL_SCANCODE_SPACE). The difference only becomes apparent on exotic layouts (e.g. AZERTY): keycodes represent the letters printed on the keycaps, while scancodes represent physical key locations. For example, on AZERTY you want to use ZQSD instead of WASD. If you use scancodes, it will happen automatically (SDL_SCANCODE_W will represent Z, and so on).
scaling rotation with frame-rate isn't really what I am looking for. Its a different problem
You need to solve this problem too. If you don't want the rotation speed to depend on FPS (bad thing), you must either mutliply the rotation angle by the frame length (it works, but it's easy to make mistakes this way), or make sure your game logic runs the fixed amount of times per second regardless of the FPS (I prefer this solution). See Fix Your Timestep!.

Generating N x N grid to display in center of window using OpenGL/C

I need to create an NxN gameboard that's determined by the user input (ie if they enter 6, it'll be a 6x6 gameboard, etc), and create a tic-tac toe like game. I'm just starting and was trying to build the board, but I can only get it to create a 5 x 5 board in the upper right hand corner and I'd like to make it the full window screen. Here's some of the code so far:
#include <stdio.h> //for text output
#include <stdlib.h> //for atof() function
#include <GL/glut.h> //GL Utility Toolkit
//to hold for size and tokens for gameboard
float grid, tokens;
void init(void);
/*Function to build the board*/
void buildGrid(float size) {
glBegin(GL_LINES);
for(int i = 0; i < size; i++) {
glVertex2f(0.0, i/5.0f);
glVertex2f(1.0, i/5.0f);
glVertex2f(i/5.0f, 0.0);
glVertex2f(i/5.0f, 1.0);
}
glEnd();
}
/*Callback function for display */
void ourDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT);
buildGrid(grid);
glFlush();
}
int main(int argc, char* argv[]) {
/*User arguments*/
if (argc != 3) {
printf("You are missing parts of the argument!");
printf("\n Need game size and how many in a row to win by\n");
exit(1);
}
/*Take arguments and convert to floats*/
grid = atof(argv[1]);
tokens = atof(argv[2]);
/* Settupp OpenGl and Window */
glutInit(&argc, argv);
/* Set up display */
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 800); // obvious
glutInitWindowPosition(0, 0); // obvious
glutCreateWindow("Tic Tac Oh"); // window title
/* Call the display callback handler */
glutDisplayFunc(ourDisplay);
init();
/* Start the main loop that waits for events to happen and
then to process them */
glutMainLoop();
}
I'm thinking it has to do with the x,y coordinates of glVertex2f, I've tried using different coordinates (negatives) and it would just move the box into a different quarter of the window. I'm also thinking that the coordinates of the window (800 x 800) needs to be manipulated somehow, but I'm just not sure.
You're using the old-school fixed-function pipeline, but you're not setting up your model-view-projection matrixes. This means that your OpenGL window uses "clip space" coordinates, which go from -1 to +1. So, the lower-left corner of your screen is (-1, -1), and the upper right is (+1, +1).
At the bare minimum, you will probably want to call glOrtho() to set your projection matrix, then glTranslatef() and glScalef() to set up your modelview matrix. (Or you can just continue to supply coordinates in clip space, but there's no real advantage to doing that, so you might as well choose your own coordinate system to make things easier for you.)
This will be covered in any OpenGL 1.x tutorial, perhaps you just haven't read that far yet. Look for phrases "matrix stack", "projection matrix", "modelview matrix".

Opengl shapes not drawing in callback function

In my opengl program, I want to make the screen turn red when a user hits a certain key. In my my_keyboard function, I have the following:
void my_keyboard( unsigned char key, int x, int y ) {
int feedback_code=0;
if (key == 49) {
feedback_code=1;
}
if (feedback_code==1) {
flash_screen();
}
My flash_screen method is as follows:
void screen_flash() {
float mat[16];
glGetFloatv(GL_MODELVIEW_MATRIX,mat);
glColor3f(1.0f,0.0f,0.0f);
glBegin(GL_POLYGON);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, 640.0f);
glVertex2f(888.0f, 640.f);
glVertex2f(888.0f, 0.0f);
glEnd();
}
By the glGetFloatv call, I know that my transformation matrix is back at the lower left corner where it should be, at point (0,0). So the draw function should draw a red square 888x640px, the size of my window. When I run the program and hit the '1' key, however, I don't get a shape! I've used breakpoints and determined that the GlBegin-GlEnd statements DO run, they just don't seem to produce anything.
The only other shapes I have are done in my main display function, called before the main_loop starts.
What am I doing wrong?
It's a common newbie mistake. So here's the general rule: Never make OpenGL drawing calls from event handlers. Never!
When you want something on the screen happen in reaction to a input event, set some flag variables, and signal a redraw. Then in the drawing function draw according to the signal.

opengl animations slow down when window size is increased

In many OpenGL tutorials, e.g. swiftless tutorials and many others, whenever there is an animation in the scene and the window is resized, the speed of the animation changes.
Description of strange behaviour
when the window is small, the animation speeds upwhen the window is large the animation slows downIs there an explanation for this?
#include <GL/glew.h> // Include the GLEW header file
#include <GL/glut.h> // Include the GLUT header file
bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)
bool movingUp = false; // Whether or not we are moving up or down
float yLocation = 0.0f; // Keep track of our position on the y axis.
float yRotationAngle = 0.0f; // The angle of rotation for our object
void keyOperations (void) {
if (keyStates[GLUT_KEY_LEFT]) { // If the left arrow key has been pressed
// Perform left arrow key operations
}
}
void display (void) {
keyOperations();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our <a title="window" href="http://www.swiftless.com/tutorials/opengl/window.html">window</a> to red
glClear(GL_COLOR_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations
glTranslatef(0.0f, 0.0f, -5.0f); // Push eveything 5 units back into the scene, otherwise we won't see the primitive
glTranslatef(0.0f, yLocation, 0.0f); // Translate our object along the y axis
glRotatef(yRotationAngle, 0.0f, 1.0f, 0.0f); // Rotate our object around the y axis
glutWireCube(2.0f); // Render the primitive
glFlush(); // Flush the OpenGL buffers to the window
if (movingUp) // If we are moving up
yLocation -= 0.005f; // Move up along our yLocation
else // Otherwise
yLocation += 0.005f; // Move down along our yLocation
if (yLocation < -3.0f) // If we have gone up too far
movingUp = false; // Reverse our direction so we are moving down
else if (yLocation > 3.0f) // Else if we have gone down too far
movingUp = true; // Reverse our direction so we are moving up
yRotationAngle += 0.005f; // Increment our rotation value
if (yRotationAngle > 360.0f) // If we have rotated beyond 360 degrees (a full rotation)
yRotationAngle -= 360.0f; // Subtract 360 degrees off of our rotation
}
void reshape (int width, int height) {
glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window
glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed
glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly
}
void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed
}
void keyUp (unsigned char key, int x, int y) {
keyStates[key] = false; // Set the state of the current key to not pressed
}
int main (int argc, char **argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode (GLUT_SINGLE); // Set up a basic display buffer (only single buffered for now)
glutInitWindowSize (500, 500); // Set the width and height of the window
glutInitWindowPosition (100, 100); // Set the position of the window
glutCreateWindow ("You’re first OpenGL Window"); // Set the title for the window
glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering
glutIdleFunc(display); // Tell GLUT to use the method "display" as our idle method as well
glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping
glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses
glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events
glutMainLoop(); // Enter GLUT's main loop
}
The way this is written it uses an "as fast as possible" rendering approach. This, together with V-Sync disabled will make the animation speed depend on the time it takes to calculate the pixels of one frame. The larger the window, the more pixels there are to fill (look up the keyword fillrate).
The solution is, to measure the time between rendering frames and advance the animation by this.

Basic skeleton for a C OpenGL program on OSX

What's the bare skeleton to get a triangle drawn on an OpenGL window in C on OSX? I've gone through the tutorials at Nehe and tried to get it working, but the CreateGLWindow seems hopelessly tied to win32.
I want to stick to just opengl and glut, etc. I'll be eventually wrapping this in scheme, but I'd like to have a firmer understanding at the c-level beforehand.
Here's what I have thus far:
#include <OpenGL/gl.h>// Header File For The OpenGL32 Library
#include <OpenGL/glu.h>// Header File For The GLu32 Library
#include <GLUT/glut.h>// Header File For The GLut Library
#define kWindowWidth 400;
#define kWindowHeight 300;
HGLRC hRC=NULL;// Permanent Rendering Context
HDC hDC=NULL;// Private GDI Device Context
HWND hWnd=NULL;// Holds Our Window Handle
HINSTANCE hInstance;// Holds The Instance Of The Application
LRESULTCALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);// Declaration For WndProc
boolkeys[256];// Array Used For The Keyboard Routine
boolactive=TRUE;// Window Active Flag Set To TRUE By Default
boolfullscreen=TRUE;// Fullscreen Flag Set To Fullscreen Mode By Default
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)// Resize And Initialize The GL Window
{
if (height==0)// Prevent A Divide By Zero By
{
height=1;// Making Height Equal One
}
glViewport(0, 0, width, height);// Reset The Current Viewport
glMatrixMode(GL_PROJECTION);// Select The Projection Matrix
glLoadIdentity();// Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);// Select The Modelview Matrix
glLoadIdentity();// Reset The Modelview Matrix
}
int InitGL(GLvoid)// All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH);// Enables Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);// Black Background
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
return TRUE;// Initialization Went OK
}
int DrawGLScene(GLvoid)// Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear The Screen And The Depth Buffer
glLoadIdentity();// Reset The Current Modelview Matrix
return TRUE;// Everything Went OK
}
GLvoid KillGLWindow(GLvoid)// Properly Kill The Window
{
if (fullscreen)// Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0);// If So Switch Back To The Desktop
ShowCursor(TRUE);// Show Mouse Pointer
}
if (hRC)// Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL))// Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC))// Are We Able To Delete The RC?
{
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
hRC=NULL;// Set RC To NULL
}
if (hDC && !ReleaseDC(hWnd,hDC))// Are We Able To Release The DC
{
MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL;// Set DC To NULL
}
if (hWnd && !DestroyWindow(hWnd))// Are We Able To Destroy The Window?
{
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;// Set hWnd To NULL
}
if (!UnregisterClass("OpenGL",hInstance))// Are We Able To Unregister Class
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;// Set hInstance To NULL
}
}
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuintPixelFormat;// Holds The Results After Searching For A Match
WNDCLASSwc;// Windows Class Structure
DWORDdwExStyle;// Window Extended Style
DWORDdwStyle;// Window Style
RECT WindowRect;// Grabs Rectangle Upper Left / Lower Right Values
WindowRect.left=(long)0;// Set Left Value To 0
WindowRect.right=(long)width;// Set Right Value To Requested Width
WindowRect.top=(long)0;// Set Top Value To 0
WindowRect.bottom=(long)height;// Set Bottom Value To Requested Height
fullscreen=fullscreenflag;// Set The Global Fullscreen Flag
hInstance= GetModuleHandle(NULL);// Grab An Instance For Our Window
wc.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// Redraw On Move, And Own DC For Window
wc.lpfnWndProc= (WNDPROC) WndProc;// WndProc Handles Messages
wc.cbClsExtra= 0;// No Extra Window Data
wc.cbWndExtra= 0;// No Extra Window Data
wc.hInstance= hInstance;// Set The Instance
wc.hIcon= LoadIcon(NULL, IDI_WINLOGO);// Load The Default Icon
wc.hCursor= LoadCursor(NULL, IDC_ARROW);// Load The Arrow Pointer
wc.hbrBackground= NULL;// No Background Required For GL
wc.lpszMenuName= NULL;// We Don't Want A Menu
wc.lpszClassName= "OpenGL";// Set The Class Name
if (!RegisterClass(&wc))// Attempt To Register The Window Class
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Exit And Return FALSE
}
if (fullscreen)// Attempt Fullscreen Mode?
{
DEVMODE dmScreenSettings;// Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));// Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings);// Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth= width;// Selected Screen Width
dmScreenSettings.dmPelsHeight= height;// Selected Screen Height
dmScreenSettings.dmBitsPerPel= bits;// Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
// If The Mode Fails, Offer Two Options. Quit Or Run In A Window.
if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE;// Select Windowed Mode (Fullscreen=FALSE)
}
else
{
// Pop Up A Message Box Letting User Know The Program Is Closing.
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return FALSE;// Exit And Return FALSE
}
}
}
if (fullscreen)// Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW;// Window Extended Style
dwStyle=WS_POPUP;// Windows Style
ShowCursor(FALSE);// Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;// Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW;// Windows Style
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);// Adjust Window To True Requested Size
if (!(hWnd=CreateWindowEx(dwExStyle,// Extended Style For The Window
"OpenGL",// Class Name
title,// Window Title
WS_CLIPSIBLINGS |// Required Window Style
WS_CLIPCHILDREN |// Required Window Style
dwStyle,// Selected Window Style
0, 0,// Window Position
WindowRect.right-WindowRect.left,// Calculate Adjusted Window Width
WindowRect.bottom-WindowRect.top,// Calculate Adjusted Window Height
NULL,// No Parent Window
NULL,// No Menu
hInstance,// Instance
NULL)))// Don't Pass Anything To WM_CREATE
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
staticPIXELFORMATDESCRIPTOR pfd=// pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR),// Size Of This Pixel Format Descriptor
1,// Version Number
PFD_DRAW_TO_WINDOW |// Format Must Support Window
PFD_SUPPORT_OPENGL |// Format Must Support OpenGL
PFD_DOUBLEBUFFER,// Must Support Double Buffering
PFD_TYPE_RGBA,// Request An RGBA Format
bits,// Select Our Color Depth
0, 0, 0, 0, 0, 0,// Color Bits Ignored
0,// No Alpha Buffer
0,// Shift Bit Ignored
0,// No Accumulation Buffer
0, 0, 0, 0,// Accumulation Bits Ignored
16,// 16Bit Z-Buffer (Depth Buffer)
0,// No Stencil Buffer
0,// No Auxiliary Buffer
PFD_MAIN_PLANE,// Main Drawing Layer
0,// Reserved
0, 0, 0// Layer Masks Ignored
};
if (!(hDC=GetDC(hWnd)))// Did We Get A Device Context?
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))// Did Windows Find A Matching Pixel Format?
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd))// Are We Able To Set The Pixel Format?
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
if (!(hRC=wglCreateContext(hDC)))// Are We Able To Get A Rendering Context?
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
if(!wglMakeCurrent(hDC,hRC))// Try To Activate The Rendering Context
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
ShowWindow(hWnd,SW_SHOW);// Show The Window
SetForegroundWindow(hWnd);// Slightly Higher Priority
SetFocus(hWnd);// Sets Keyboard Focus To The Window
ReSizeGLScene(width, height);// Set Up Our Perspective GL Screen
if (!InitGL())// Initialize Our Newly Created GL Window
{
KillGLWindow();// Reset The Display
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Return FALSE
}
return TRUE;// Success
}
LRESULT CALLBACK WndProc(HWNDhWnd,// Handle For This Window
UINTuMsg,// Message For This Window
WPARAMwParam,// Additional Message Information
LPARAMlParam)// Additional Message Information
{
switch (uMsg)// Check For Windows Messages
{
case WM_ACTIVATE:// Watch For Window Activate Message
{
if (!HIWORD(wParam))// Check Minimization State
{
active=TRUE;// Program Is Active
}
else
{
active=FALSE;// Program Is No Longer Active
}
return 0;// Return To The Message Loop
}
case WM_SYSCOMMAND:// Intercept System Commands
{
switch (wParam)// Check System Calls
{
case SC_SCREENSAVE:// Screensaver Trying To Start?
case SC_MONITORPOWER:// Monitor Trying To Enter Powersave?
return 0;// Prevent From Happening
}
break;// Exit
}
case WM_CLOSE:// Did We Receive A Close Message?
{
PostQuitMessage(0);// Send A Quit Message
return 0;// Jump Back
}
case WM_KEYDOWN:// Is A Key Being Held Down?
{
keys[wParam] = TRUE;// If So, Mark It As TRUE
return 0;// Jump Back
}
case WM_KEYUP:// Has A Key Been Released?
{
keys[wParam] = FALSE;// If So, Mark It As FALSE
return 0;// Jump Back
}
case WM_SIZE:// Resize The OpenGL Window
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));// LoWord=Width, HiWord=Height
return 0;// Jump Back
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
GLvoid InitGL(GLvoid);
GLvoid DrawGLScene(GLvoid);
GLvoid ReSizeGLScene(int Width, int Height);
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (kWindowWidth, kWindowHeight);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
InitGL();
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
glutMainLoop();
return 0;
}
As far as I can tell, the NeHe tutorials are specifically for windows and are great for higher level stuff. However, when it comes to the basics, They can become overcomplicated. So here is a simple skeletal program for rendering a triangle using only glut and opengl functionality. If you want to be Apple specific, try using agl.
// The OpenGL libraries, make sure to include the GLUT and OpenGL frameworks
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
// This is just an example using basic glut functionality.
// If you want specific Apple functionality, look up AGL
void init() // Called before main loop to set up the program
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
}
// Called at the start of the program, after a glutPostRedisplay() and during idle
// to display a frame
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.0, -10.0);
glVertex3f(1.0, 0.0, -10.0);
glVertex3f(0.0, 1.0, -10.0);
glEnd();
glutSwapBuffers();
}
// Called every time a window is resized to resize the projection matrix
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-0.1, 0.1, -float(h)/(10.0*float(w)), float(h)/(10.0*float(w)), 0.5, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv); // Initializes glut
// Sets up a double buffer with RGBA components and a depth component
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
// Sets the window size to 512*512 square pixels
glutInitWindowSize(512, 512);
// Sets the window position to the upper left
glutInitWindowPosition(0, 0);
// Creates a window using internal glut functionality
glutCreateWindow("Hello!");
// passes reshape and display functions to the OpenGL machine for callback
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(display);
init();
// Starts the program.
glutMainLoop();
return 0;
}
NeHe has a tutorial for setting up an OpenGL window on Mac OS X with GLUT here. They also provide the code for all of the lessons for various different platforms. If you scroll to the bottom of lesson 2, you can download the lesson code ready to go for a number of platforms. You probably want either the GLUT sample or the Mac OS X/Cocoa sample.
Easiest way is to use Objective-C to get everything set up, then use C for drawing. (not the only way, GLUT is also an option.)
Sample code from Apple
Here's the "hello.c" example from the OpenGL Red Book converted to R6RS Scheme:
http://gist.github.com/319363
That program runs in Ikarus Scheme and Ypsilon Scheme.
Notice that the 'import' form is referring to some 'agave' libraries. Those are available at:
http://github.com/dharmatech/agave
Agave is a project which provides a bunch of OpenGL demos and libraries for R6RS Scheme.
Ikarus and Ypsilon are both available for OS X.
Ed

Resources