Advertisement

Request OpenGL Basics Clarifications (Based on NeHe's tutorial)

Started by December 19, 2004 01:53 AM
8 comments, last by Steve132 19 years, 11 months ago
It's amazing how much traffic this forum receives.. wow. Anywho, I was pointed to NeHe's tutorials to begin learning OpenGL, and so, I have started in the beginning with how to set up an OpenGL window. I am quite serious about learning this, and I have, in fact, read through the code and comments in its entirety and taken 5 pages of notes on the process for my own reference. I do have a few questions about some of the coding techniques and openGL techniques, so if anybody has the answers i'd greatly appreciate the clarification! Also, if you have a resource you could point me to for definitions or something that may also help. 1. Rendering Context and Device Context. I don't quite understand exactly what each of these does. I understand their level of significance, but not their raw functionality. 2. OpenGL Functions..( or not? ) A. GLvoid type, how is this different than a regular void return type? B. ReSizeGLScene(), InitGL(), KillGLWindow() ... are these all predefined functions? If so, why are we writing code for them? Are they more like events that we are defining? I assume so because they have no prototypes? C. WndProc() function ... is this an arbitrary name chosen or is this a predefined function? It appears to be one he made since there is a prototype and the function is at the end, but i just want to make sure since it sounds .. uhh "official" 3. Pixel Format Descriptor is a bit hazy ... i seem to understand the reason for it, just not the "raw functionality" of it. 4. Window messages are very hazy. While I understand that there are messages for closing the window, screen saver, system commands, etc. I don't really understand the process here. For instance, NeHe's check for the window state (WM_Activate) is confusing to me. Also, when is the WM_CLOSE message received? Why is it necessary to Post a request to close? Also, the Return for the WndProc function is confusing. Why would "returning DefWindowProc()" allow for windows to take over any nonaddressed messages, and what does he mean by "Return 0" in the switch statement when he says "Jumps Back"? Jump back where? 5. At the very end of the program he return's (msg.wParam); ... what exactly is this saying/doing? Thanks, that is all I have on this subject to ask for now... I suppose part of it may be due to me just being a little rusty with C++ (i went to stupid Visual Basic for a while and it has corrupted my brain), regardless.. if anybody can answer these questions i'd really appreciate it.. i'd have a lot better grasp on the material when moving on to the next tutorials. -Kevin
If you want to understand OpenGL better before trying to program it, try reading the redbook. ***CLICKY***

As fo Windows, you can try reading these. ***CLICKY***

The WndProc() is the window procedure that handles the messages the OS sends to your window. WM_Activate is sent to your window when the user activates/de-actives the application(ie: toggling it from being the active window).
Advertisement
Thanks those both look like good refences and I will definitely read them tomorrow hopefully. I thought I was starting at the beginning, but apparently I skipped Lesson #0, the prequel to programming opengl ;)

And i can recall using WndProc now, actually, in a VB application I did... I think. VB wasn't nearly powerful enough to perform what the program I was making was designed to do so I ended up using a lot of API Functions.. and then the VB code started to look ugly.. real ugly.. and VB dumbs things down so much it numbs the brain when you move to a language like C, C++, or C#

Thanks for the reply
-Kevin
1) I'm not a great Win32 programmer, so take what I say with a grain of salt. As far as I know, a Device Context is an abstraction for an area on which you can draw using Win32 functions (those draw rectangle, draw ellipse... kind of functions). I assume a Rendering Context build on a Device Context to allow you to use OpenGL functions.

2)
2A) OpenGL has a number of typedefs intended to insulate it from type variability on various platforms. That way, if some system has a different-sized, say, int type, GL vendors will simply modify the GLint typedef so that the function prototypes remain the same as on other platforms (i.e. keep a uniform GLint size).

2B) If it's not prefixed by gl, glu or wgl (at least on windows platforms), it's not an OpenGL function.

2C) WndProc is the customary name for the core function of your program. You'll notice that, in the setup code (in WinMain, which is an official entry point), you store a pointer to WndProc in some data structure (window class registration, I believe). This is how the operating system knows which function to call; unlike main() or WinMain(), it doesn't rely on the function's name.

3) AFAIK it's intended to allocate the, say, 16 or 32, bits of your color depth to the various color channels. Unless you have good reasons to change it, just use whatever recommended values are given (like Red 5, Green 6, Blue 5 for 16 bits, or Red 8, Green 8, Blue 8, Alpha 8 for 32 bits); Green got an extra bit in 16-bit mode because the human eye is most sensitive to green - indeed it is the major component of the luminance; how bright a color looks.

4) I can't really help you there, I'm not much of a Win32 programmer.

5) The return at the end of a program determines the program's return code. When writing shell scripts (or, on MS platforms, .BAT batch files), it is possible to check the value thus returned, and to have the script behave differently - much like you would return an error code from a function, except for whole programs. 0 is the standard return value for "no error", non-zero for error (with the actual value indicating the nature of the error, though those error codes are entirely program-specific).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Awesome, thanks again.

I always thought Return 1 meant it was successful.. i.e. the program returned TRUE. For example...

if(someFunction) { blah blah }

Would perform the 'blah blah' code if someFunction had returned TRUE (or nonzero). I guess I really need to read up on the program flow after the "return" statement because its always been a hangup to me. I understand how it can be used.. like .. "err=anotherFunction()" would set 'err' to be the return value of anotherFunction()... but when not used in a situation like that, i don't understand the results of a specific return value.. for instance when return 0 is used on the WndProc example.

Just for my own double clarification, i could have named WndProc something like... WindowProc in the prototype and definition and all other occurances and it would have done exactly the same thing? It is just common practice (much like prefixing variables) to name it that, yes?

Thanks,
Kevin

p.s. i'm just now realizing after browsing the forums some more that i could have placed this post in NeHe's forums... my bad. Hopefully it is fine here, too.
Quote: Original post by Kevin071586
I always thought Return 1 meant it was successful.. i.e. the program returned TRUE. For example...


You only need one value to show success (0), but a program can fail in many ways. Incidentally, any non-zero value is considered true in a boolean context.

Quote: i don't understand the results of a specific return value.. for instance when return 0 is used on the WndProc example.


I believe, the return value on WndProc is intended to tell the OS whether you have handled the even or not, but I'm probably wrong. I strongly suggest you check out the appropriate help page on MSDN (or in your compiler's help files).

Quote: Just for my own double clarification, i could have named WndProc something like... WindowProc in the prototype and definition and all other occurances and it would have done exactly the same thing?


I believe this is correct, yes.

Quote: It is just common practice (much like prefixing variables) to name it that, yes?


Hungarian notation have many flaws - Take for example wParam; it is not a WORD (16-bit integral type, see windows.h) anymore, but a DWORD. Which means it should have been renamed dwParam. I suggest you read this article and generally refrain from using Hungarian notation.

Note: prefixing your member variables with, say m_ is OK (because it avoids shadowing problem between non-member variables and member variables), but warts like lpsz, dw and even the C you see many people put in front of their classes (ironically, the trend got started by MFC, which did that so as to avoid clashing with names chosen by programmers for their own symbols...), should be avoided - instead give your variables a name that will reflect how it'll get used.

Quote: p.s. i'm just now realizing after browsing the forums some more that i could have placed this post in NeHe's forums... my bad. Hopefully it is fine here, too.


You'd probably have gotten better help over there. I''ll move the thread.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Advertisement
Quote: Original post by Kevin071586
Just for my own double clarification, i could have named WndProc something like... WindowProc in the prototype and definition and all other occurances and it would have done exactly the same thing? It is just common practice (much like prefixing variables) to name it that, yes?


You can call those functions whatever you want. You can have different window procedures for different windows, such as buttons, text entry boxes etc... and you make your own function, then tell the window structures about it.

Basically, everytime you do something, windows sends a message to your program, and the receiving window calls it's custom procedure function to handle those messages. You can then call the default message handler to handle all the other messages you don't want to handle.
Quote: Original post by Kevin071586
...snip...
2. B. ReSizeGLScene(), InitGL(), KillGLWindow() ... are these all predefined functions? If so, why are we writing code for them? Are they more like events that we are defining? I assume so because they have no prototypes?
...snip...
-Kevin


Since I don't think anyone has answered this yet:
No, these are not predefined functions. They have no prototype (forward declaration) because they don't need one. A prototype (forward declaration) is only required if a function is to be used before it is defined:
int doSomething(); // forward declarationint function()	// function does not require a forward declaration		// it is defined here and nothing previously has tried		// to call it{	return doSomething();	// doSomething has not been defined, but the				// forward declaration allows us to call it}int doSomething() // definition for doSomthing{	// do something	return 1;}int main(){	function();}


Fruny: You left your Hungarian Notation link blank. Did you mean this article?

Enigma
Quote: Original post by Enigma
Fruny: You left your Hungarian Notation link blank. Did you mean this article?


Yes, thanks.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote: #4) Window messages are very hazy. While I understand that there are messages for closing the window, screen saver, system commands, etc. I don't really understand the process here. For instance, NeHe's check for the window state (WM_Activate) is confusing to me. Also, when is the WM_CLOSE message received? Why is it necessary to Post a request to close? Also, the Return for the WndProc function is confusing. Why would "returning DefWindowProc()" allow for windows to take over any nonaddressed messages, and what does he mean by "Return 0" in the switch statement when he says "Jumps Back"? Jump back where?


Lets start with the first part:
The windows messaging system used by NeHe is using a CALLBACK function. What happens is this: Whenever the system has something that it can tell our opengl window, windows calls this function with the nessecary information. Think of winproc as sort of the "Mailbox" of the appliction, so to speak. Mesages come through this function from windows to communicate with the application and tell it about things that are going on. The way that windows Recieves messages from the application in reply, is through the return type of this function. So, if we consider "WinProc()" as the point of communication between our app and windows, the meaning of the messages becomes more clear. For example, our app might recieve the WM_ACTIVATE flag when what happens? When winows is telling our application window that it needs to ACTIVATE! thus, the code in WinProc says: "If the window is told to activate, if it is maximized (read: already active) make it deactivate. if it is minimized, make it activate; then, return a value that the system understands to mean "all activations ok"" This sort of message is typically sent by windows when the minimize or maximize buttons are clicked.

With this in mind. what do you think a message from windows to the app of "WM_CLOSE" is requesting? What button click or start menu command do you think would send this sort of message?

Now, lets just say you wanted to specify in your program another way to run the close program code you specified as what the the reaction to WM_CLOSE should be; (like, for example, a close if( KeyEscape == true)). You could just copy and paste the code, but a simpler and perhaps better way might be just to send the WM_CLOSE message yourself! Think of the PostMessage() call as the application mailing a letter to itself. NeHe's Code is actually saying, "Since I want to close the app when the escape key is pressed, and I already have all this code for what to do if I recieve a Close message in the mail, I will just mail myself a close request if the escape key is pressed!" It looks complicated at first, but the idea isnt really that hard.

Now, here is my interpretation of what goes on in your last question: Remember what I said about it being a mailbox to your App? Well, the reason why you return DefWindowProc() is kinda related to that. Windows sends the app all of the messages it thinks the app MIGHT want, even if they arent really needed by the app at all.

Windows sends information about drawing and moving, about mouse data and keyboard data, networking, going into sleep mode, you name it. The reason for this is that Windows doesn't know what kind of app you are trying to write. In an openGL app, we are concerned with moving and drawing, and preventing the screen saver, but what if you were making something like a disk defragmenter. You would want a way to know if windows was going asleep, and you would want a way to tell windows what to do if that happened (or not to do). If you recieved a sleep message, you would probably display a dialog or some thing, and return a code for "Abort Sleep Mode" to windows, telling it to NOT go into sleep mode. for the sake of argument, lets say that that response code is 0;

But what if you Aren't writing a code that needs to respond to sleep mode? If the computer is going into sleep mode, it will send that message to your openGL app, and it better know how to respond! One solution might be to make a response in your switch statement for every possible windows message, but there are potentially hundreds of them, and researching the appropriate response codes for every single one of them for your program would be rediculous.

You could also put in a default statement that returns 0 (or some other response code) for all unspecified codes. This would save you typing out hundreds of codes inside your switch statements, but what would happen if your app got sent the "System shutting down" message, and, since it got caught by your 'default' switch statement, it returned 0? You dont know what this means to windows...maybe it means "Abort The Shutdown", or maybe it means "Continue with this shutdown and shutdown all LAN connected computers" or whatever (I made those up) my point is, using a default return code has unexpected results, because you are not sure what you are really telling windows to do in response to a message that your app was not meant to handle.
It is like opening up someone else's mail who lives in your apartment and sending a reply back to the sender.

Ok, so what AM I supposed to do? Well, in this case, what would you do if you got someone elses mail at your house? If you are like most people you would relay the person the envelope, and , if they wrote a reply, relay it back to the postman. In the case of windows messages and WinProc, you do the same thing, except the person you are relaying it to is DefWindowProc.

DefWindowProc() always returns the result code with the least effect on the system. if you send it the message you got that was unhandled by you: "System going into sleep mode" it returns "go ahead and do that." if you send it "Window Closing" it sends back "sweet, tell me when its over" etc, etc. You get the idea. So, as opposed to sending a '0' reply on an unhandled message (which could mean anything to windows, even "OMFG FORMAT HARDDRIVE NOW") it is a good idea to pass the unhandled message on to DefWindowProc(), and then use that, slightly more predictable reply.
In short, you "return DefWindowProc(message)" really says "take the best possible reply to message and then return it out of winproc into windows".

Wow, that was long. I hope that if you took the time to read all of that it should be at least a little informative. If it didnt help I am very sorry. Good luck!

-P.S. I am not sure, but I interpret "Jump Back" to mean "Stop processing windows messages now and go back to the game code" (because that is immediatly what happens after the message return code has been interpreted by windows)

This topic is closed to new replies.

Advertisement