Archived

This topic is now archived and is closed to further replies.

Erunama

Computer Science Final Project

Recommended Posts

I am currently taking AP Computer Science A at my high school, and we are working on our final projects. We are allowed to work off of a base code, and I will be using NeHe''s (I hope my teacher will accept an OpenGL program, since we never even did graphics in class, just regular old DOS programming). The project must include classes and at least one AP class (I am using apvector, which is just a class for creating an array). I will be creating a room with a spinning cube inside. I also have implemented a primitive form of shading for the class Draw() function (it darkens the colors towards the back... primitive, I know, but I haven''t reached texture mapping or lighting in the tuts yet). I had a little problem with apvectors and my Cube class, but I have ironed that out. The room looks pretty good right now, and only one thing is keeping me from being "finished." The cube does not spin. Here are a few snippets of code that I thought were relevant. Can anyone figure out my problem? Creating the cube objects:
  
	// Create cube objects

	Cube room(6.0f,6.0f,15.0f);
	Cube cube(1.0f,1.0f,1.0f);

	// Modify cube parameters

	room.SetColor(0.5f,0.5f,0.5f);
	room.ShowDepth(TRUE);
	room.SetPosition(0.0f,-1.0f,-7.0f);
	cube.IsRotation(TRUE);
	cube.SetColor(0.2f,0.1f,1.0f);
	cube.SetPosition(0.0f,-1.0f,-5.0f);
	cube.SetRotation(2.0f,1.0f,1.0f,0.0f);

	apvector <Cube> cubes(2);
	cubes[0] = room;
	cubes[1] = cube;
  
The apvector with the two cubes (yes, the room is a rectangle, but I felt like calling the class Cube) gets passed the the DrawGLScene function:
  DrawGLScene(cubes);				// Draw The Scene  
Here is the DrawGLScene function:
  
int DrawGLScene(apvector <Cube> cubes)								// Here''s Where We Do All The Drawing

{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear The Screen And The Depth Buffer


	// Draw the objects

	for (int i = 0; i < cubes.length(); i++)
	{
		glLoadIdentity();
		cubes[i].Draw();
	}

	return TRUE;								// Everything Went OK

}
  
The member functions that modify rotation paramaters:
  
void Cube::IsRotation(BOOL rotation)
{
	myRotate = rotation;
}

void Cube::SetRotation(GLfloat change, GLfloat x, GLfloat y, GLfloat z)
{
	myChange = change;
	myRot[0] = x;
	myRot[1] = y;
	myRot[2] = z;
}
  
And finally, the Draw() function, which draws the cube based on all the private data members (I omitted the actual plotting of the vertices and my primitive shading code to save space):
  
void Cube::Draw()
{
	if(amIDefined)
	{
		glTranslatef(myPosition[0],myPosition[1],myPosition[2]);

		if(myRotate)
		{
			glRotatef(myAngle,myRot[0],myRot[1],myRot[2]);
			myAngle += myChange;
		}

		//Start drawing the cube

		glBegin(GL_QUADS);
	             (Insert vertice drawing code here)
		glEnd();

	}
}
  
Ok, there is all the code I think is relevant for someone to find my problem. If you want anymore code, feel free to ask. I get no errors when I compile, and everything draws to the screen fine, it''s just that the cube sits there and does not spin. Thanks for any help you can provide, Dan Carroll

Share this post


Link to post
Share on other sites
it looks like you are missing one or a couple of:

glPushMatrix()
glLoadIdentity()
glPopMatrix()

look deeper into the NeHe tuts to find out where exactly to call them

-me

Share this post


Link to post
Share on other sites
Yep. Are you using gluLookAt or something similar? If so, you don't want to use glLoadIdentity, as it will destroy your modelview matrix. Use

glLoadIdentity();
gluLookAt(...);
for (all cubes) {
glPushMatrix();
glTranslate(...);
...
// DrawCube
...
glPopMatrix();
}

If you're not using gluLookAt, what do you use?

[edited by - IndirectX on May 1, 2002 8:49:39 PM]

Share this post


Link to post
Share on other sites
Thanks for the quick replies.

IndirectX: I am not using gluLookAt (don''t even know what it is). I am just building the objects using glTranslatef and glVertex3f (very simple stuff here, along the lines of tutorial 5).

Palidine: I don''t think it has anything to do with those Matrix functions, since I have never encountered them before (again, we are looking at complexity along the lines of tutorial 5).


I am pretty sure it is a very simple code/class error that I am not catching. I programmed this without classes and it worked fine. So I am losing something in the modification to my Cube class.

Share this post


Link to post
Share on other sites
quote:
Original post by Palidine
my bad on the glLoadIdentity()


LOL! I forgot to put it in my pseudocode; that''s fixed.

Erunama: seeing that you do pretty much the same thing as Tutorial 5 does, are you initializing myAngle to 0? Step through your code and make sure that all your variables have reasonable values.

[rant]
I really dislike AP coding conventions, as well as their questions. The worst coding style I''ve ever seen (speaking of questions on the AP test). Intentionally giving you code snippets that will make anyone say "Why the hell did they do that?"

I took APCS A last year in my school, we have 32MB PII boxes with BC++4 and no help files whatsoever. No Win32 fun over there. :D
[/rant]

Share this post


Link to post
Share on other sites
I think I figured it out. But first some assumptions (if I make the wrong assumptions, the solution might not be correct). I think you use the glRotatef function incorrectly.

assumption: You have myRot[] float 3 array. Does this store the angles the cube is at?

glRotatef works like this:

glRotatef(angle, x, y, z) in which angle is the amount to rotate and x, y and z the axis. if:
x=1.0f
y=0.5f
z=0.0f
then it would rotate (1.0f * angle) degrees on the x axis
(0.5f * angle) degrees on the y axis and
(0.0f * angle) degrees on the z axis.

To rotate correctly on the angles stored in MyRot[] use 3 calls:

glRotatef(MyRot[0], 1.0f, 0.0f, 0.0f);
glRotatef(MyRot[1], 0.0f, 1.0f, 0.0f);
glRotatef(MyRot[2], 0.0f, 0.0f, 1.0f);

Hope this helps

- An eye for an eye will make the world go blind -

Share this post


Link to post
Share on other sites
Hi everyone !

Erunama, I think your problem comes from your call to glLoadIdentity() since it is used to reinitialize the matrix from wich you are doing your position calculation to the identity matrix. That means that, with this call, you''re rotating your cube by an angle of 2° along your x and y axis from it''s original orientation, not from it''s current orientation. I guess that''s one of the reasons why your cube doesn''t seems like it''s spinning.
Btw you should really use the glPushMatrix() / glPopMatrix() calls since it allows you to do any transformation you want between this two calls without affecting anything that is done outside the calls. I mean this the right way to get your cube spinning indepently from your room. Otherwise your cube and your room would be rotating the same way and you wouldn''t notice the change.
Is the room.myRotate default value false ? That''s another point that you''ve not precised.

So your code might look something like this :

for (int i = 0; i < cubes.length(); i++) {
cubes.Draw();
}

void Cube::Draw(){
if(amIDefined) {

glPushMatrix();
glTranslatef(myPosition[0],myPosition[1],myPosition[2]); if(myRotate) {
glRotatef(myAngle,myRot[0],myRot[1],myRot[2]); myAngle += myChange;
}
//Start drawing the cube
glBegin(GL_QUADS);
(Insert vertice drawing code here)
glEnd();
glPopMatrix();
}
}

Hope I''ve been clear enough and your demo will be working correctly soon. I''m still learning too and I don''t pretend that this is the answer to your problem, just that this the way I would do it.

Good luck.

Share this post


Link to post
Share on other sites
Let me clarify some of the questions you guys had.

IndirectX - Yes, I am pretty sure everything is being initialized correctly. Here is my constructor:

    
Cube::Cube(GLfloat x, GLfloat y, GLfloat z)
: amIDefined(TRUE),
myLength(z),
myHeight(y),
myWidth(x),
myDepth(FALSE),
myRotate(FALSE),
myAngle(0.0f),
myChange(0.0f),
myRot(3),
myPosition(3),
myColor(3)
{

// set default position to center of screen

myPosition[0] = 0.0f;
myPosition[1] = 0.0f;
myPosition[2] = 0.0f;

// set default color to white

myColor[0] = 1.0f;
myColor[1] = 1.0f;
myColor[2] = 1.0f;

}

And yes, I dislike the whole AP coding stuff too (I take the test May 9th, but I have been doing practice questions in class). I also hate the AP classes they use, such as apmatrix, apstring, and apvector. What is the point of teaching something that we will not use outside of the class? It's not like I am going to bring along my AP files to my first job as a programmer. They should just teach the regular C++ strings and arrays.


smarechal: The array holds the axis for the cube to spin around (so in you example, x, y, and z would be stored in myRot[0], myRot[1], and myRot[2], respectively). The angle is myAngle, which is initialized to 0.0f, and is increased by myChange every time Draw() is called.

Trexmaster: I have not yet tried your code, but let me first enter a rebuttal to what you said. The cube alway starts from it's original position (0 degrees), and I am rotating it by myAngle. But every time Draw() is called, myAngle is increased by myChange. Therefore, through the first five calls, myAngle should be 0.0f, 2.0f, 4.0f, 6.0f, 8.0f. myAngle would continually be increased, therefore spinning.


A few of you have recommended using glPushMatrix() and glPopMatrix(), which I want to avoid using since I have no idea what they do. There must be some bug that I am not catching, because this program worked before I starting using classes (without Push and PopMatrix(), just glLoadIdentity).

Can anyone figure out my problem? Need more code?

Edit: Just for the record, I tried your code Trexmaster and it did not solve the problem. Thanks for your help though.



[edited by - Erunama on May 2, 2002 4:49:50 PM]

Share this post


Link to post
Share on other sites
the reason for using such a library is becuase it makes exponential easier to get the concpet across. a good teacher will ween you off using the classes so by the end of you sequence you would be using only c++ code and classes you created (ie reimplement some of the basic classes). later on you could begin using STL, and such.

apvector from the code looks very much like an STL template so dont be so sure that you are not just using STL wrappers. though i think the classes you are using are probably designed with more error checking and you can actually see the code. thus be able to understand what is happening and not treat it as a blackbox.

also for reference. dont create varible names with my infront of them to show there are your varibles. it is not required and makes things look wierd. instead pick names that describe the varible, if you like prefixes, put the varible type infront. like flRot or iLength. this is merely a style concern, because it looks a bit unprofessional currrently. you dont need to change it if you dont want to for this project, but i would siggest starting to tear away from that. you probably picked up the habit from tutorials or how the teacher taught things.

Share this post


Link to post
Share on other sites
Here''s a quick explanation of how matrix stacks work in OpenGL. The main matrix stack is the modelview matrix. This is basically the locator (or coordinates I guess) for where in space the next object is going to be drawn (does that make sense?). Its called a stack because you can pile different matrices on. When you call glLoadIdentity() you are reseting this stack (I think, or maybe just having the top matrix an identity matrix). When you call glTranslate*() or glRotate*() you''re putting another matrix on the stack. The order you put them on the stack matters too. If you translate first, then rotate, the resulting stack is different than had you rotated then translated.

How glPushMatrix() and glPopMatrix() work is you can ''push the stack'' and that will save that place. After a push you may add more transforms, but when you pop, everything you added after the push will be erased, and it''ll be in the same position it was when you pushed. You can push multiple times, and the pop will revert the stack to the most recent push. I wonder if I''m making this seem a whole lot harder than it really is...?

--Buzzy

Share this post


Link to post
Share on other sites
Well, the explanation kind of makes sense, but I am really not looking into matrix stacks right now. I am more concerned with getting this program to run correctly. There have been a lot of helpful, concerned comments, but I still can''t get the cube to spin. I think the solution might be a lot simpler than some of you imagine, since the original program (without classes) worked perfectly (a simple glLoadIdentity, translate, rotate, and then draw).

What''s going wrong in my code?

p.s.: a person, the reason I use ''my'' is because I was taught to use it in order to mark the private data members. I think it is kind of helpful and it makes sense. While it may not be the best way to do it, I was taught that way, and since this project is going to be graded by my teacher, I better use the techniques she teaches.

Share this post


Link to post
Share on other sites
quote:
Original post by a person

also for reference. dont create varible names with my infront of them to show there are your varibles. it is not required and makes things look wierd. instead pick names that describe the varible, if you like prefixes, put the varible type infront. like flRot or iLength. this is merely a style concern, because it looks a bit unprofessional currrently. you dont need to change it if you dont want to for this project, but i would siggest starting to tear away from that. you probably picked up the habit from tutorials or how the teacher taught things.




--begin 100% subjective ranting--

The my prefixing is also enforced in coding style at at least one of the top 8 CS universities, and presumably will spread more and more. Its very convienant for declaring instance variables/member variables. And looks much more logical than some of the other notations I have seen such as m_someVar; Incidentally the notation spreads further to inherited public vars which should be prefixed with our. Ie: ourSomeVar. The type specifier prefixes are also specified, so a boolean instance var would be: bMyDone;

Very easy to understand and read at a glance. The example you gave, iLength gives no indication as to what type of variable it is.. I suppose you prefer m_iLength, g_iLength??? *shudder*

--end 100% subjective ranting--

Share this post


Link to post
Share on other sites
Do this:

for(int i = 0; i <= 10000; i++)
{

glPushMatrix();

glRotatef(i, 1, 1, 1);

glBegin(GL_TRIANGLES);

glVertex3f(-1, 0, 0);
glVertex3f(0, 1, 0);
glVertex3f(1, 0, 0);

// The above just draws a flat triangle

glEnd();

glPopMatrix();

}

After this you should see the flat triangle spinning. You can draw other objects after the glPopMatrix() line... just the flat triangle will spin.

You NEED to call glPushMatrix() and glPopMatrix() to tell OpenGL to rotate just the triangle, otherwise it will spin all the world. Calling them, just objects beeing drawed between them will be affected by the rotation.

Try this code, you'll see.

See you!

[edited by - ChacaL on May 2, 2002 12:55:48 AM]

[edited by - ChacaL on May 3, 2002 2:35:19 AM]

Share this post


Link to post
Share on other sites
Domninus: Yes, I am working off NeHe''s base code, so my Main function is exactly the same (except that I declare the objects within Main and pass an apvector to DrawGLScene, rather than passing nothing).

Chacal: Well, I can definitely see how that works, but I don''t like the way it works at all. It will have to go through the for loop 10000 times before jumping out of the loop, which means the program will not monitor for any keystrokes during that time. Also, when it reaches the end, the angle will be 10000. When the function is called the next time, the angle will be 0, and since 10000 is not a multiple of 360 (I don''t think it is), there will be a slight ''skip.''

Share this post


Link to post
Share on other sites
Well, since it seems like no one can find the problem, I might as well post all of the code.

I will do each file in a seperate post (not sure if there is a length restriction).

My main file (final_project.cpp):

    
/**************************************************************************| AP Computer Science A |
| FINAL PROJECT |
| |
| Created by: Dan Carroll |
| |
| Base code created by Jeff Molofee (NeHe) |
| - code is available for download at http://nehe.gamedev.net/ |
| - Jeff's tutorials were used to gain an understanding of the OpenGL |
| API and to learn the commands necessary for this particular |
| project. While this program is simplistic, it will be used as |
| the basis for further exploration in 3d graphics programming. |
| |
| Code modified to display a rotating cube inside a rectangular room |
| - A Cube class was created to draw cubes of various sizes and colors |
| (rectangular cubes can also be created) |
| - The apvector class is being utilized to hold multiple Cube objects |
| and allow for more than one cube to be drawn easily (by only |
| sending one apvector to the DrawGLScene function, rather than |
| individual objects). The apvector class is also being used to hold |
| variables for the cube's color, position, and rotation parameters. |
| |
| |
| Last modified: May 3, 2002 |
| |
\**************************************************************************/


#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
#include "cube.h" // Header file for the Cube class
#include "apvector.h" // Header file for the AP vector class

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
BOOL keys[256]; // Array Used For The Keyboard Routine
BOOL active=TRUE; // Window Active Flag Set To TRUE By Default
BOOL fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default

GLfloat cuberot; // Rotation angle for the spinning cube

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc

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(apvector <Cube> cubes) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer

// Draw the objects
for (int i = 0; i < cubes.length(); i++)
{
glLoadIdentity();
cubes[i].Draw();
}

/* glLoadIdentity();
glTranslatef(0.0f,-1.0f,-7.0f);
cubes[0].Draw();

glLoadIdentity();
glTranslatef(0.0f,-1.0f,-5.0f);
cubes[1].Draw();
*/

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)
{
GLuint PixelFormat; // Holds The Results After Searching For A Match

WNDCLASS wc; // Windows Class Structure

DWORD dwExStyle; // Window Extended Style

DWORD dwStyle; // 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

}
static PIXELFORMATDESCRIPTOR 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( HWND hWnd, // Handle For This Window

UINT uMsg, // Message For This Window

WPARAM wParam, // Additional Message Information

LPARAM lParam) // 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);
}

int WINAPI WinMain( HINSTANCE hInstance, // Instance

HINSTANCE hPrevInstance, // Previous Instance

LPSTR lpCmdLine, // Command Line Parameters

int nCmdShow) // Window Show State

{
MSG msg; // Windows Message Structure

BOOL done=FALSE; // Bool Variable To Exit Loop


// Ask The User Which Screen Mode They Prefer

if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE; // Windowed Mode

}
// Create Our OpenGL Window

if (!CreateGLWindow("Dan Carroll's Final Project",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created

}

// Create cube objects

Cube room(6.0f,6.0f,15.0f);
Cube cube(1.0f,1.0f,1.0f);

// Modify cube parameters

room.SetColor(0.5f,0.5f,0.5f);
room.ShowDepth(TRUE);
room.SetPosition(0.0f,-1.0f,-7.0f);
cube.IsRotation(TRUE);
cube.SetColor(0.2f,0.1f,1.0f);
cube.SetPosition(0.0f,-1.0f,-5.0f);
cube.SetRotation(2.0f,1.0f,1.0f,0.0f);

apvector <Cube> cubes(2);
cubes[0] = room;
cubes[1] = cube;

while(!done) // Loop That Runs Until done=TRUE

{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?

{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?

{
done=TRUE; // If So done=TRUE

}
else // If Not, Deal With Window Messages

{
TranslateMessage(&msg); // Translate The Message

DispatchMessage(&msg); // Dispatch The Message

}
}
else // If There Are No Messages

{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()

if (active) // Program Active?

{
if (keys[VK_ESCAPE]) // Was ESC Pressed?

{
done=TRUE; // ESC Signalled A Quit

}
else // Not Time To Quit, Update Screen

{
DrawGLScene(cubes); // Draw The Scene

SwapBuffers(hDC); // Swap Buffers (Double Buffering)

}
}
if (keys[VK_F1]) // Is F1 Being Pressed?

{
keys[VK_F1]=FALSE; // If So Make Key FALSE

KillGLWindow(); // Kill Our Current Window

fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode

// Recreate Our OpenGL Window

if (!CreateGLWindow("Dan Carroll's Final Project",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created

}
}
}
}
// Shutdown

KillGLWindow(); // Kill The Window

return (msg.wParam); // Exit The Program

}


Edit: Some of the formatting got messed up, but the code is all there. And for some reason it treats a large portion of the code as commented out, but trust me, it is not!

[edited by - Erunama on May 3, 2002 4:26:38 PM]

Share this post


Link to post
Share on other sites
I'll squeeze two header files into one here.

My Cube class header file (cube.h):

    
#ifndef _CUBE_H
#define _CUBE_H

#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
#include "apvector.h"


class Cube
{
public:

/////////////////////////////////////////////////////////////////////

// constructors


Cube();
Cube(GLfloat length, GLfloat width, GLfloat height);

/////////////////////////////////////////////////////////////////////

// destructor


~Cube();

/////////////////////////////////////////////////////////////////////

// modifying functions


void SetDimensions(GLfloat length, GLfloat width, GLfloat height);
void SetColor(GLfloat red, GLfloat green, GLfloat blue);
void ShowDepth(BOOL depth);
void IsRotation(BOOL rotation);
void SetRotation(GLfloat change, GLfloat x, GLfloat y, GLfloat z);
void SetPosition(GLfloat x, GLfloat y, GLfloat z);

void Draw();
// uses private data members to draw cube on the screen


private:

// cube size variables

GLfloat myHeight; // height of the cube (along y axis)

GLfloat myLength; // length of the cube (along z axis)

GLfloat myWidth; // width of the cube (along x axis)


// cube state variables

BOOL myDepth; // shade the cube?

BOOL myRotate; // rotate the cube?

BOOL amIDefined; // draw the cube?


// rotation variables

apvector<GLfloat> myRot; // vector holding the rotational axis

GLfloat myAngle; // the cube's current angle

GLfloat myChange; // the rate that the cube spins


apvector<GLfloat> myPosition; // vector holding the position values

apvector<GLfloat> myColor; // vector holding the color values (R,G,B)


};

#endif



And the apvector header file (apvector.h):

#ifndef _APVECTOR_H
#define _APVECTOR_H

// *******************************************************************

// Last Revised: 8/14/98, abort changed to exit

//

// January 13,1998, added explicit to int constructor

// APCS vector class template

//

// implements "safe" (range-checked) arrays

// examples are given at the end of this file

// *******************************************************************


// If your compiler supports the keyword explicit, comment out the

// #define explicit line below, leaving the #define means explicit
// is ignored, but doesn't generate an error

//

// This will disallow a typically erroneous implicit type-conversion:

// vector<int> v( 10 );

// v = 0; // Oops!! Allowed because of implicit type-con2lversion.


#define explicit



template <class itemType>
class apvector
{
public:

// constructors/destructor

apvector( ); // default constructor (size==0)

explicit apvector( int size ); // initial size of vector is size

apvector( int size, const itemType & fillValue ); // all entries == fillValue

apvector( const apvector & vec ); // copy constructor

~apvector( ); // destructor


// assignment

const apvector & operator = ( const apvector & vec );

// accessors

int length( ) const; // capacity of vector


// indexing

itemType & operator [ ] ( int index ); // indexing with range checking

const itemType & operator [ ] ( int index ) const; // indexing with range checking


// modifiers

void resize( int newSize ); // change size dynamically;

// can result in losing values

private:

int mySize; // # elements in array

itemType * myList; // array used for storage

};

// *******************************************************************

// Specifications for vector functions

//

// The template parameter itemType must satisfy the following two conditions:

// (1) itemType has a 0-argument constructor

// (2) operator = is defined for itemType

// Any violation of these conditions may result in compilation failure.

//

// Any violation of a function's precondition will result in an error message

// followed by a call to exit.

//

// constructors/destructor

//

// apvector( )

// postcondition: vector has a capacity of 0 items, and therefore it will

// need to be resized

//

// apvector( int size )

// precondition: size >= 0

// postcondition: vector has a capacity of size items

//

// apvector( int size, const itemType & fillValue )

// precondition: size >= 0

// postcondition: vector has a capacity of size items, all of which are set

// by assignment to fillValue after default construction

//

// apvector( const apvector & vec )

// postcondition: vector is a copy of vec

//

// ~apvector( )

// postcondition: vector is destroyed

//

// assignment

//

// const apvector & operator = ( const apvector & rhs )

// postcondition: normal assignment via copying has been performed;

// if vector and rhs were different sizes, vector

// has been resized to match the size of rhs

//

// accessor

//

// int length( ) const

// postcondition: returns vector's size (number of memory cells

// allocated for vector)

//

// indexing

//

// itemType & operator [ ] ( int k ) -- index into nonconst vector

// const itemType & operator [ ] ( int k ) const -- index into const vector

// description: range-checked indexing, returning kth item

// precondition: 0 <= k < length()

// postcondition: returns the kth item

//

// modifier

//

// void resize( int newSize )

// description: resizes the vector to newSize elements

// precondition: the current capacity of vector is length; newSize >= 0

//

// postcondition: the current capacity of vector is newSize; for each k

// such that 0 <= k <= min(length, newSize), vector[k]

// is a copy of the original; other elements of vector are

// initialized using the 0-argument itemType constructor

// Note: if newSize < length, elements may be lost

//

// examples of use

// apvector<int> v1; // 0-element vector

// apvector<int> v2(4); // 4-element vector

// apvector<int> v3(4, 22); // 4-element vector, all elements == 22.


#include "apvector.cpp"
#endif


Edit: Some weird green font stuff going on here...


[edited by - Erunama on May 3, 2002 4:32:46 PM]

Share this post


Link to post
Share on other sites
And finally, my Cube class source code (cube.cpp):

        
#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
#include "cube.h" // Header file for the Cube class
#include "apvector.h"


// constructors


Cube::Cube()
: amIDefined(FALSE)
{

}

Cube::Cube(GLfloat x, GLfloat y, GLfloat z)
: amIDefined(TRUE),
myLength(z),
myHeight(y),
myWidth(x),
myDepth(FALSE),
myRotate(FALSE),
myAngle(0.0f),
myChange(0.0f),
myRot(3),
myPosition(3),
myColor(3)
{

// set default position to center of screen

myPosition[0] = 0.0f;
myPosition[1] = 0.0f;
myPosition[2] = 0.0f;

// set default color to white

myColor[0] = 1.0f;
myColor[1] = 1.0f;
myColor[2] = 1.0f;

}

Cube::~Cube()
{

}

// modifying functions


void Cube::SetDimensions(GLfloat x, GLfloat y, GLfloat z)
{
myLength = z;
myWidth = x;
myHeight = y;
}

void Cube::SetColor(GLfloat red, GLfloat green, GLfloat blue)
{
myColor[0] = red;
myColor[1] = green;
myColor[2] = blue;
}

void Cube::ShowDepth(BOOL depth)
{
myDepth = depth;
}

void Cube::IsRotation(BOOL rotation)
{
myRotate = rotation;
}

void Cube::SetRotation(GLfloat change, GLfloat x, GLfloat y, GLfloat z)
{
myChange = change;
myRot[0] = x;
myRot[1] = y;
myRot[2] = z;
}

void Cube::SetPosition(GLfloat x, GLfloat y, GLfloat z)
{
myPosition[0] = x;
myPosition[1] = y;
myPosition[2] = z;
}

void Cube::Draw()
{
if(amIDefined)
{
glTranslatef(myPosition[0],myPosition[1],myPosition[2]);

if(myRotate)
{
glRotatef(myAngle,myRot[0],myRot[1],myRot[2]);
myAngle += myChange;
}

//Start drawing the cube

glBegin(GL_QUADS);
glColor3f(myColor[0],myColor[1],myColor[2]);

// Draw the left side of the cube

glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
if(myDepth)
glColor3f(myColor[0] - 0.15f,myColor[1] - 0.15f,myColor[2] - 0.15f);
glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));

glColor3f(myColor[0],myColor[1],myColor[2]);
// Draw the right side of the cube

glVertex3f((myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
if(myDepth)
glColor3f(myColor[0] - 0.15f,myColor[1] - 0.15f,myColor[2] - 0.15f);
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));
glVertex3f((myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));

// Draw the back of the cube

glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));
glVertex3f((myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));

glColor3f(myColor[0],myColor[1],myColor[2]);
// Draw the front of the cube

glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
glVertex3f((myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));

if(myDepth)
glColor3f(myColor[0] - 0.2f,myColor[1] - 0.2f,myColor[2] - 0.2f);
// Draw the top of the cube

glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));
glVertex3f((myWidth/2.0f),(myHeight/2.0f),(myLength/2.0f));
if(myDepth)
glColor3f(myColor[0] - 0.25f,myColor[1] - 0.25f,myColor[2] - 0.25f);
glVertex3f((myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),(myHeight/2.0f),-(myLength/2.0f));

// Draw the bottom of the cube

glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),(myLength/2.0f));
if(myDepth)
glColor3f(myColor[0] - 0.25f,myColor[1] - 0.25f,myColor[2] - 0.25f);
glVertex3f((myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));
glVertex3f(-(myWidth/2.0f),-(myHeight/2.0f),-(myLength/2.0f));

glEnd();

}
}


Feel free to use this class in your own projects. The shading technique is really primitive, but I actually think it looks kind of decent. It took me a long time to figure out how to do the Draw function by using just three variables, but it works great!


Here is the apvector.cpp file:
[source]
// *******************************************************************

// Last Revised: 8/14/98

// changed abort to exit

//

// APCS vector class IMPLEMENTATION

//

// see vector.h for complete documentation of functions

//

// vector class consistent with a subset of the standard C++ vector class

// as defined in the draft ANSI standard (part of standard template library)

// *******************************************************************



#include <stdlib.h>
#include <assert.h>
#include <iostream.h>
#include "apvector.h"

template <class itemType>
apvector<itemType>::apvector()
//postcondition: vector has a capacity of 0 items, and therefore it will

// need to be resized

: mySize(0),
myList(0)
{

}

template <class itemType>
apvector<itemType>::apvector(int size)
// precondition: size >= 0

// postcondition: vector has a capacity of size items

: mySize(size),
myList(new itemType[size])
{

}

template <class itemType>
apvector<itemType>::apvector(int size, const itemType & fillValue)
// precondition: size >= 0

// postcondition: vector has a capacity of size items, all of which are set

// by assignment to fillValue after default construction

: mySize(size),
myList(new itemType[size])
{
int k;
for(k = 0; k < size; k++)
{
myList[k] = fillValue;
}
}

template <class itemType>
apvector<itemType>::apvector(const apvector<itemType> & vec)
// postcondition: vector is a copy of vec

: mySize(vec.length()),
myList(new itemType[mySize])
{
int k;
// copy elements

for(k = 0; k < mySize; k++){
myList[k] = vec.myList[k];
}
}

template <class itemType>
apvector<itemType>::~apvector ()
// postcondition: vector is destroyed

{
delete [] myList;
}

template <class itemType>
const apvector<itemType> &
apvector<itemType>::operator = (const apvector<itemType> & rhs)
// postcondition: normal assignment via copying has been performed;

// if vector and rhs were different sizes, vector

// has been resized to match the size of rhs

{
if (this != &rhs) // don't assign to self!

{
delete [] myList; // get rid of old storage

mySize = rhs.length();
myList = new itemType [mySize]; // allocate new storage


// copy rhs

int k;
for(k=0; k < mySize; k++)
{
myList[k] = rhs.myList[k];
}
}
return *this; // permit a = b = c = d

}

template <class itemType>
int apvector<itemType>::length() const
// postcondition: returns vector's size (number of memory cells

// allocated for vector)

{
return mySize;
}

template <class itemType>
itemType & apvector<itemType>::operator [] (int k)
// description: range-checked indexing, returning kth item

// precondition: 0 <= k < length()

// postcondition: returns the kth item

{

if (k < 0 || mySize <= k)
{
cerr << "Illegal vector index: " << k << " max index = ";
cerr << (mySize-1) << endl;
exit(1);
}
return myList[k];
}

template <class itemType>
const itemType & apvector<itemType>::operator [] (int k) const
// safe indexing, returning const reference to avoid modification

// precondition: 0 <= index < length

// postcondition: return index-th item

// exception: exits if index is out-of-bounds

{
if (k < 0 || mySize <= k)
{
cerr << "Illegal vector index: " << k << " max index = ";
cerr << (mySize-1) << endl;
exit(1);
}
return myList[k];
}

template <class itemType>
void apvector<itemType>::resize(int newSize)
// description: resizes the vector to newSize elements

// precondition: the current capacity of vector is length(); newSize >= 0

// postcondition: the current capacity of vector is newSize; for each k

// such that 0 <= k <= min(length, newSize), vector[k]

// is a copy of the original; other elements of vector are

// initialized using the 0-argument itemType constructor

// Note: if newSize < length, elements may be lost

{
int k;
int numToCopy = newSize < mySize ? newSize : mySize;

// allocate new storage and copy element into new storage


itemType * newList = new itemType[newSize];
for(k=0; k < numToCopy; k++)
{
newList[k] = myList[k];
}
delete [] myList; // de-allocate old storage

mySize = newSize; // assign new storage/size

myList = newList;
}



Ok! Now that there are no questions about exactly what my code is, can anyone figure out my problem?


Edit: Tried to fix some errors, but there seems to be a problem with the 'source' tags. Before you ask about missing header files or the like, make sure you scroll over because cut-and-paste seems to have screwed with things like the carriage returns

Edit #2: Hrmmmm, now the apvector.cpp code has disappeared. Hopefully, it will come back now. If not, I don't think you really need it to analyze my code.


[edited by - Erunama on May 3, 2002 4:42:42 PM]

[edited by - Erunama on May 3, 2002 4:44:51 PM]

Share this post


Link to post
Share on other sites
Since you posted the code, can you do us all a favor and zip your whole project and put it up somewhere so that we won''t have to mess with files, project settings and the such?

Share this post


Link to post
Share on other sites
Enurama, the code above is not for you to use in your project. It was just to demonstrate the use of glPushMatrix() and glPopMatrix().

And, definatelly, you WILL NEED to use them, as you want some vertices to be rotated (the cube) and others to be static (the room).

The For loop just gives an increasing number... this way you could copy/past that code in a OpenGL basecode and see what I mean.

Definatelly, LEARN glPushMatrix() and glPopMatrix().

Bye!

Share this post


Link to post
Share on other sites
Ok, for anyone who wanted the project files, here you go:
http://opengl.0catch.com/final_project.zip

(I just registered for a ZeroCatch account... I am surprised that the opengl username was not taken). Just a note, I am using Microsoft Visual C++ version 4. I am not sure whether or not the project files will work on the newer versions, but at the very least, you''ll get the necessary source and header files (if the workspace does not work, just go in and link to the OGL libraries, then include apvector.cpp and cube.cpp to your workspace).

ChacaL: I will learn Push and Pop eventually, but I have no need for them yet. This program can work without them (I know because I did it without classes). I don''t see the reason of putting something in there that I do not need and do not fully understand. If you want proof that this scenario works without glPushMatrix and glPopMatrix, check out my old code:


  
#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library
#include "cube.h" // Header file for the Cube class
#include "apvector.h" // Header file for the AP vector class


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

BOOL keys[256]; // Array Used For The Keyboard Routine

BOOL active=TRUE; // Window Active Flag Set To TRUE By Default

BOOL fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default


GLfloat cuberot; // Rotation angle for the spinning cube


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc


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


glTranslatef(0.0f,-3.0f,-10.0f); // Move into the screen a down a little bit


// Draw the room

glBegin(GL_QUADS);
glColor3f(0.5f,0.5f,0.5f); // Set color for walls (grey)


// Draw left wall first

glVertex3f(-3.0f,5.0f,6.0f);
glVertex3f(-3.0f,0.0f,6.0f);
glVertex3f(-3.0f,0.0f,-5.0f);
glVertex3f(-3.0f,5.0f,-5.0f);

// Draw right wall next

glVertex3f(3.0f,5.0f,6.0f);
glVertex3f(3.0f,0.0f,6.0f);
glVertex3f(3.0f,0.0f,-5.0f);
glVertex3f(3.0f,5.0f,-5.0f);

// Draw back wall next

glVertex3f(-3.0f,5.0f,-5.0f);
glVertex3f(-3.0f,0.0f,-5.0f);
glVertex3f(3.0f,0.0f,-5.0f);
glVertex3f(3.0f,5.0f,-5.0f);

// Fourth wall is not needed (behind screen)


glColor3f(0.3f,0.3f,0.3f); // Set color for ceiling and floor (dark grey)


// Draw ceiling

glVertex3f(-3.0f,5.0f,6.0f);
glVertex3f(-3.0f,5.0f,-5.0f);
glVertex3f(3.0f,5.0f,-5.0f);
glVertex3f(3.0f,5.0f,6.0f);

// Draw floor

glVertex3f(-3.0f,0.0f,6.0f);
glVertex3f(-3.0f,0.0f,-5.0f);
glVertex3f(3.0f,0.0f,-5.0f);
glVertex3f(3.0f,0.0f,6.0f);

glEnd();

glLoadIdentity(); // Move to the center of the screen and reset the axis

glTranslatef(0.0f,-0.5f,-5.0f); // Move to the center of the room

glRotatef(cuberot,1.0f,1.0f,0.0f); // Rotate the cube along the X and Y axis


// After the room, draw the rotating cube

glBegin(GL_QUADS);
glColor3f(0.1f,0.1f,1.0f); // Make the cube blue


// Draw the left side of the cube

glVertex3f(0.5f,0.5f,0.5f);
glVertex3f(0.5f,-0.5f,0.5f);
glVertex3f(0.5f,-0.5f,-0.5f);
glVertex3f(0.5f,0.5f,-0.5f);

// Draw the right side of the cube

glVertex3f(-0.5f,0.5f,0.5f);
glVertex3f(-0.5f,-0.5f,0.5f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,0.5f,-0.5f);

// Draw the back of the cube

glVertex3f(0.5f,0.5f,-0.5f);
glVertex3f(0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,0.5f,-0.5f);

// Draw the front of the cube

glVertex3f(0.5f,0.5f,0.5f);
glVertex3f(0.5f,-0.5f,0.5f);
glVertex3f(-0.5f,-0.5f,0.5f);
glVertex3f(-0.5f,0.5f,0.5f);

// Draw the top of the cube

glVertex3f(0.5f,0.5f,0.5f);
glVertex3f(0.5f,0.5f,-0.5f);
glVertex3f(-0.5f,0.5f,-0.5f);
glVertex3f(-0.5f,0.5f,0.5f);

// Draw the bottom of the cube

glVertex3f(0.5f,-0.5f,0.5f);
glVertex3f(0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,-0.5f,-0.5f);
glVertex3f(-0.5f,-0.5f,0.5f);

glEnd();

cuberot += 0.2f; // Change the angle of rotation (so that the cube actually rotates)

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)
{
GLuint PixelFormat; // Holds The Results After Searching For A Match

WNDCLASS wc; // Windows Class Structure

DWORD dwExStyle; // Window Extended Style

DWORD dwStyle; // 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

}
static PIXELFORMATDESCRIPTOR 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( HWND hWnd, // Handle For This Window

UINT uMsg, // Message For This Window

WPARAM wParam, // Additional Message Information

LPARAM lParam) // 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);
}

int WINAPI WinMain( HINSTANCE hInstance, // Instance

HINSTANCE hPrevInstance, // Previous Instance

LPSTR lpCmdLine, // Command Line Parameters

int nCmdShow) // Window Show State

{
MSG msg; // Windows Message Structure

BOOL done=FALSE; // Bool Variable To Exit Loop


// Ask The User Which Screen Mode They Prefer

if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE; // Windowed Mode

}
// Create Our OpenGL Window

if (!CreateGLWindow("Dan Carroll''s Final Project",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created

}

while(!done) // Loop That Runs Until done=TRUE

{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?

{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?

{
done=TRUE; // If So done=TRUE

}
else // If Not, Deal With Window Messages

{
TranslateMessage(&msg); // Translate The Message

DispatchMessage(&msg); // Dispatch The Message

}
}
else // If There Are No Messages

{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()

if (active) // Program Active?

{
if (keys[VK_ESCAPE]) // Was ESC Pressed?

{
done=TRUE; // ESC Signalled A Quit

}
else // Not Time To Quit, Update Screen

{
DrawGLScene(); // Draw The Scene

SwapBuffers(hDC); // Swap Buffers (Double Buffering)

}
}
if (keys[VK_F1]) // Is F1 Being Pressed?

{
keys[VK_F1]=FALSE; // If So Make Key FALSE

KillGLWindow(); // Kill Our Current Window

fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode

// Recreate Our OpenGL Window

if (!CreateGLWindow("Dan Carroll''s Final Project",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created

}
}
}
}
// Shutdown

KillGLWindow(); // Kill The Window

return (msg.wParam); // Exit The Program

}

Share this post


Link to post
Share on other sites
Well, I solved it for you. It turned out that myAngle in Cube::Draw was 0 on every iteration, indicating that something reset your data structures. After some tracing, the problem is in this line:

        
int DrawGLScene(apvector <Cube> cubes) // Here's Where We Do All The Drawing


You are passing cubes by value. Aside from performance penalty involved in copying the array, whatever your drawing function changed (myAngle, in this case) was changed in the local copy of the array. The "real" cubes array wasn't modified, and next time you drew it, you got the original array, instead of modified one. Changing the function declaration to

  
int DrawGLScene(apvector <Cube>& cubes) // Here's Where We Do All The Drawing


solves the problem.

How did I find this bug? I noticed that myAngle is zero. I got its address and set data breakpoint on (float *)0x1234, where 0x1234 is the address of myAngle. The breakpoint was hit from debug free memory routine that was overwriting the container, which was called from apvector destructor. Naturally, I didn't expect vector destructor to be called in your render loop, and after some looking around I noticed that you were passing it by value instead of by reference.

Edit: gl[Push|Pop]Matrix wouldn't help in this case, because geometry modifications made during drawing weren't saved. Heh.

[edited by - IndirectX on May 4, 2002 5:19:35 PM]


[edited by - IndirectX on May 5, 2002 9:01:06 PM]

Share this post


Link to post
Share on other sites
I knew it would be something simple! Thank you for finding the error, IndirectX. I knew all along it would be some little error like that, which is why I was annoyed with everyone suggesting glPush and PopMatrix, because I was sure I didn''t need them.

Thanks again! It works great know (just got to fool around with the rotation values to make it look good).

Share this post


Link to post
Share on other sites