http://www.nullterminator.net/opengl32.html
I have been able to get that to work, but near the bottom of the page
he says:
"In my experience, trying to create or destroy stuff like DirectX
interfaces inside of a WM_CREATE or WM_DESTROY function tends to be
rather destructive to one's health: the program, the operating
system (namely Windows 95), and the poor soul debugging it."
But it seems to me that putting the startup code under WM_CREATE
is the logical place, and many web pages seem to get satisfactory
results with this layout. However, I don't. In my code by
changing WHERE_IT_GOES to UNDER_WM_TIMER (where the startup
sequence executes when the first WM_TIMER message is processed)
or to IN_WINMAIN (where it executes right after the invocation
of CreateWindowEx), the program draws OK. If WHERE_IT_GOES =
UNDER_WM_CREATE so that the startup sequence executes when
the WM_CREATE message is processed, all I get is a black screen.
Does Windows do something in CreateWindowEx after instructing
the Window Procedure to process the WM_CREATE message that
allows the OpenGL startup code to function properly after
CreateWindowEx returns but not before?
The code is visible at:
http://home.comcast.net/~kmbtib/Fortran_stuff/example2.zip
After compiling it (the compilers at http://www.equation.com
work) with the build2.bat batch file, one gets an example2.exe
executable. The easy way to stop that program is to hit
the <ESC> key.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
> trying to get OpenGL to work in Windows
Hi James,
I wrote several OpenGL apps under Windows XP
and Windows 7 and everything works just fine,
including threads for continuous OpenGL animation
even when the program receives no system message.
I used Visual C/C++ in C langage, not Fortran,
however if the problem you are experiencing
is related to Window programming then
I hope that the following will be helpul,
by checking these sequences against yours.
// global variable ----------------------------------
HWND hWnd = NULL; // window handle
HDC hDC = NULL; // device context
HDC hRC = NULL; // ressource context
//- main window proc ---------------------------------
int APIENTRY WinMain( ... )
{
int ok; // flag
// ... your initializations ...
// window creation
hWnd = CreateWindow( ... );
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
// message loop processing - including screen refresh
for( ok=1; ok; )
{ if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
{ TranslateMessage(&msg);
DispatchMessage(&msg);
if(msg.message == WM_QUIT) ok=0; // quit
}
// refresh screen even when the window receives no message
fctRendering(0); // call your OpenGL rendering function
Sleep(dwMainDelay); // optional loop delay
}
// window closing : cleanup time
fctCleanupRC(); // clean-up OpenGL
ReleaseDC( hWnd, hDC ); // release device context
return msg.wParam; // done
}
//- window messages ---------------------------------
LRESULT CALLBACK WndProc( ... )
{
switch (message)
{
case WM_CREATE : // create window
glob_hDC = GetDC(hWnd); // store window's device context
fctSetupRC(hDC); // call your custom OpenGL device context
initialization
// ...
return 0;
case WM_ERASEBKGND : // screen update
return 1; // prevent background erase
case WM_PAINT : // screen refresh
fctRendering(1); // call your OPenGL render function
return 0;
case WM_SIZE: // window position/size changed
case WM_MOVE:
ResetViewport(); // call your window's viewport update
return 0;
case WM_DESTROY: // close window
PostQuitMessage(0);
return 0;
case WM_CLOSE: // close window
DestroyWindow(hWnd);
return 0;
// ... your message handlers ...
default: break;
} // switch msg
return DefWindowProc( ... );
}
//- OpenGL initialization ---------------------------------
int fctSetupRC(HDC h)
{
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = { // cutomize to your format
descriptor
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
PFD_DOUBLEBUFFER, // Double buffered mode
PFD_TYPE_RGBA, // RGBA Color mode
32, // Want 32 bit color
0,0,0,0,0,0, // Not used to select mode
0,0, // Not used to select mode
0,0,0,0,0, // Not used to select mode
16, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
0, // Not used to select mode
0, // Not used to select mode
0,0,0 }; // Not used to select mode
// ... your initializations ...
nPixelFormat = ChoosePixelFormat(h, &pfd);
SetPixelFormat(h, nPixelFormat, &pfd);
hRC = wglCreateContext(h);
wglMakeCurrent( h, hRC );
// ... your initializations ...
return 0; // done
}
//- OpenGL clean-up ---------------------------------
void fctCleanupRC(void)
{
gluDeleteQuadric(...);
wglMakeCurrent( hDC, NULL );
wglDeleteContext( hRC );
}
//- OpenGL rendering funtion ---------------------------------
void fctRendering(char how)
{
// ... cutomize your own ...
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// OpenGL rendering
RenderScene();
// done
SwapBuffers(glob_hDC);
// update
if(how) ValidateRect(hWnd,NULL);
}
// --- EOF ---
a) Are you trying to create DirectX interfaces?
b) I wouldn't pay too much attention to a ten year
old rant on DirectX under Windows 95, a lot has
changed since then.
> But it seems to me that putting the startup code under WM_CREATE
> is the logical place, and many web pages seem to get satisfactory
> results with this layout. However, I don't. In my code by
> changing WHERE_IT_GOES to UNDER_WM_TIMER
I don't know what your code does but you seem
to be using a timer. I'm betting the problem
is with that rather than WM_CREATE.
What's the timer for. Trying to use timers
with OpenGL rarely works out well in my
experience (ie. They're a pain and they
never do what you want).
Try doing it without the timer.
> Trying to use timers with OpenGL
> rarely works out well in my experience
I agree.
Under Windows the timer are low-priority.
A 50 ms timer does not mean that the program
will receive a WM_TIMER message every 50 ms.
Although Messages can be received every 50 ms,
there can be no message sent at all in 200 ms
and suddently 4 messages in less than 50 ms.
> Try doing it without the timer.
If the application needs to call a function()
either time-driven or event-driven,
it is far better to use a thread
with sufficient priority level,
and possibly with a delay in its loop.
If I had to guess, based on replying to
millions of posts here, I'd guess the OP
is thinking "I need to update the image
50 times a second so I'll use a timer to
send a WM_PAINT message" ... which simply
won't work.
Much better is this in your main loop:
if (elapsedTime() > 0.04) {
redrawTheWindow();
}
else {
sleep(1);
}
> If I had to guess, based on replying to
> millions of posts here, I'd guess the OP
> is thinking "I need to update the image
> 50 times a second so I'll use a timer to
> send a WM_PAINT message" ...
> which simply won't work.
Yep. No way relying on MS windows
messages - even for loosy « realtime ».
> Much better is this in your main loop:
> if (elapsedTime() > 0.04) redrawTheWindow();
> else sleep(1);
Agreed - definitely.
> On Dec 29, 10:50 pm, "James Van Buskirk"
>> trying to get OpenGL to work in Windows
> // global variable ----------------------------------
> HWND hWnd = NULL; // window handle
> HDC hDC = NULL; // device context
> HDC hRC = NULL; // ressource context
> //- main window proc ---------------------------------
> int APIENTRY WinMain( ... )
> {
> int ok; // flag
> // ... your initializations ...
> // window creation
> hWnd = CreateWindow( ... );
> ShowWindow(hWnd,SW_SHOW);
> UpdateWindow(hWnd);
The way I do things, ShowWindow and UpdateWindow aren't necessary.
> // message loop processing - including screen refresh
> for( ok=1; ok; )
> { if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
> { TranslateMessage(&msg);
> DispatchMessage(&msg);
> if(msg.message == WM_QUIT) ok=0; // quit
> }
> // refresh screen even when the window receives no message
> fctRendering(0); // call your OpenGL rendering function
> Sleep(dwMainDelay); // optional loop delay
> }
This is the way the example I was following did things, but I
wanted to restructure the code to do everything in the Windows
Procedure.
> //- window messages ---------------------------------
> LRESULT CALLBACK WndProc( ... )
> {
> switch (message)
> {
> case WM_CREATE : // create window
> glob_hDC = GetDC(hWnd); // store window's device context
> fctSetupRC(hDC); // call your custom OpenGL device context
> initialization
> // ...
> return 0;
I think the problem may be that I followed too simple of
an example in the hglrc initialization.
> case WM_ERASEBKGND : // screen update
> return 1; // prevent background erase
Yeah, I saw that in one of my references and put that in.
> case WM_PAINT : // screen refresh
> fctRendering(1); // call your OPenGL render function
> return 0;
The way I am doing things hopefully the screen will get redrawn
soon enough anyway.
> case WM_SIZE: // window position/size changed
> case WM_MOVE:
> ResetViewport(); // call your window's viewport update
> return 0;
Viewport update? What viewport update? :)
Definitely teh next thing I am going to work on, and it may
fix my problem.
> case WM_DESTROY: // close window
> PostQuitMessage(0);
> return 0;
> case WM_CLOSE: // close window
> DestroyWindow(hWnd);
> return 0;
Now I am putting my teardown of the hglrc and hdc under WM_CLOSE
because some of my references advise to do so.
> //- OpenGL initialization ---------------------------------
I am thinking that my problem is here. I intend to keep you
posted.
> Agreed - definitely.
Well... no. I am not trying to write a game and just want some
basic stuff working rather than obsess about exact refresh times.
It's much more desirable for my program to play nice with the
system than to be faithful to a real-time model.
That said, I didn't understand from my reading of MSDN that
Timer() starts a periodic, rather than single-shot, timer.
That is fixed in my sources, among some other rough edges that
I have filed down so far, but not yet uploaded to my web site.
The nature of the problems I was experiencing led me to believe
that there may just be some subtlety of Windows that I was missing
and a quick fix might be in the offing. However I am becoming more
inclined towards the opinion that my problem stems more from a
fundamental lack of understanding of the issues involved, so the
fix is then to educate myself better somehow. I have composed a
bibliography of what I consider to be interesting links:
MSDN Opengl documentation:
http://msdn.microsoft.com/en-us/library/dd374370(v=VS.85).aspx
Windows Opengl example:
http://www.nullterminator.net/opengl32.html
Example of full-screen program:
http://blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx
Joe Molofee's OpenGL Windows Tutorial
http://users.polytech.unice.fr/~buffa/cours/synthese_image/DOCS/Tutoriaux/Nehe/lesson1.htm
Guide to OpenGL on Windows from Silicon Graphics
http://personal.redestb.es/jmovill/opengl/openglonwin-1.html
Time and energy permitting, I will work more on this issue and
let you know if I make any progress. Thanks to both of you
for your efforts.
> http://www.artlum.com/pub/simplegl.zip
But your example also doesn't put the OpenGL initialization code in
the WM_CREATE handler. I have worked another day on this but I have
some ideas about what I may be doing wrong and hopefully will be
able to advance my understanding to the point that I can correct my
code in a day or two.
> Time and energy permitting, I will work more on this issue and
> let you know if I make any progress. Thanks to both of you
> for your efforts.
OK, I found out what my problem was: when Windows processes the
CreateWindowEx function, it sends the WM_CREATE message to the
Window Procedure and at this point the window dimensions are
something like 12 X 0 pixels. Subsequently it sends the WM_SIZE
message to the Window Procedure, still at 12 X 0. Then, if the
WS_VISIBLE flag was passed to the dwStyle argument, it sends the
WM_SIZE message again, this time with the initial window size,
which in this case was 1920 X 1080 because passed the dimensions
of my monitor for the width and height to CreateWindowEx.
My problem was that I got the resource context when processing
the WM_CREATE message, so I got a render context appropriate for
a 12 X 0 window. When using it to draw with it drew to a zero-
sized viewport, which wasn't very useful. The way I had things
set up, if I instead got the render context after CreateWindowEx
had returned, either in WinMain or by processing the first
WM_TIMER message in WndProc, I would be given a render context
with a 1920 X 1080 viewport, so everything worked.
The way I fixed my problem was to process the WM_SIZE message and
set the viewport via glViewPort to give me a square viewport centered
in the window. Also I cleaned up the code a little and reposted
along with a 32-bit executable at:
http://home.comcast.net/~kmbtib/Fortran_stuff/example2.zip
Thanks for all your help. It may not seem like much but it has been
significant progress from my perspective. One problem now is that
while the triangle rotates, you can see about 3 or 4 images are
overlapped. Is this due to my monitor just being slow to change
pixels? Does the multiple image problem show on other monitors, and
should I expect this?
> when Windows processes the CreateWindowEx function,
> it sends the WM_CREATE message to the Window Procedure
> and at this point the window dimensions are something like 12 X 0 pixels.
Sounds strange to me. CreateWindowEx parameters
includes the window's initial width and height.
If you set'em to something like (200,200)
then the window size should be 200x200.
HWND CreateWindowEx( ...
int nWidth, // window width
int nHeight, // window height
... );
> http://home.comcast.net/~kmbtib/Fortran_stuff/example2.zip
> while the triangle rotates, you can see
> about 3 or 4 images are overlapped.
Not on my PC : no overlap at all
and the rotation goes smoothly.
James, you may find interesting ressources here :
http://glprogramming.com/blue/
OpenGL Reference Manual (Silicon Graphics)
Addison-Wesley ( 119 pages )
http://www.opengl.org/documentation/blue_book/
OpenGL Programming Guide 6th Edition 2009
Addison-Wesley ( 910 pages )
http://www.opengl.org/documentation/red_book/
OpenGL Super Bible
Richard S. Wright et al. (769 pages )
w/ about 285 Mb of code example & sample
http://www.starstonesoftware.com/OpenGL/
HTH
> On Dec 31, 10:35 am, "James Van Buskirk"
>> when Windows processes the CreateWindowEx function,
>> it sends the WM_CREATE message to the Window Procedure
>> and at this point the window dimensions are something like 12 X 0 pixels.
> Sounds strange to me. CreateWindowEx parameters
> includes the window's initial width and height.
> If you set'em to something like (200,200)
> then the window size should be 200x200.
> HWND CreateWindowEx( ...
> int nWidth, // window width
> int nHeight, // window height
> ... );
I set them to full screen size. Windows eventually does get
around to changing the window size, but not when it sends the
WM_CREATE message nor even when it sends the first WM_SIZE
message. Here is the output I got from GetClientRect. The
first two lines are when invoked during the WM_CREATE handler,
then the two times WM_SIZE got called, then after CreateWindowEx
returned and values were checked in WinMain, and finally at
the first time the WM_TIMER message was handled.
WM_CREATE: width = 12
WM_CREATE: height = 0
WM_SIZE: width = 12
WM_SIZE: height = 0
WM_SIZE: width = 1920
WM_SIZE: height = 1080
WinMain: width = 1920
WinMain: height = 1080
WM_TIMER: width = 1920
WM_TIMER: height = 1080
Notice that it's only at the second time WM_SIZE is sent,
due to the WS_VISIBLE flag passed to CreateWindowEx, that
the window has been resized from default to the size
specified in the call to CreateWindowEx.
>> http://home.comcast.net/~kmbtib/Fortran_stuff/example2.zip
>> while the triangle rotates, you can see
>> about 3 or 4 images are overlapped.
> Not on my PC : no overlap at all
> and the rotation goes smoothly.
Is your monitor a CRT? I am using an LCD TV, and LCDs are known to
be slow. Thanks for testing my program on your hardware.
> WM_CREATE: width = 12
> WM_CREATE: height = 0
> WM_SIZE: width = 12
> WM_SIZE: height = 0
I never noticed such behaviour - unless by mistake,
if I explicitely set width | height to zero
or the window's visibility status to 'hidden'.
Anyway you can FORCE the window size to whatever you want,
as well as its visibility status, by calling these functions :
SetWindowPos(), MoveWindow(), ShowWindow() ...
// The SetWindowPos function changes the size, position,
// and Z order of a child, pop-up, or top-level window.
BOOL SetWindowPos(
HWND hWnd, // handle to window
HWND hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
UINT uFlags // window-positioning flags
);
// The MoveWindow function changes the position and dimensions of the
specified window.
BOOL MoveWindow(
HWND hWnd, // handle to window
int X, // horizontal position
int Y, // vertical position
int nWidth, // width
int nHeight, // height
BOOL bRepaint // repaint flag
);
// The ShowWindow function sets the specified window's show state.
BOOL ShowWindow(
HWND hWnd, // handle to window
int nCmdShow // show state of window
);
>> you can see about 3 or 4 images are overlapped.
| Not on my PC : no overlap at all
| and the rotation goes smoothly.
> Is your monitor a CRT?
No, it's a laptop LCD.
Intel Core Duo @ 2.13 GHz
NVIDIA GeForce GT 230M.
I also tried on an external CRT
using the PC's standard SVGA output,
and all worked pretty fine too.
I don't think that the problem comes from the software.
It shouldn't make any difference.
Now is the moment to banish any thoughts
along the lines of: "I'm only going to call
glViewport() when I get a window size message
because it's more efficient"
You should call glViewport() _every time_
in your redraw function. You'll never manage
to measure a difference in speed and anything
else just leads to madness in the long term.
Adjust your mindset NOW. Do it.
Why are you obsessed with doing that?
You've already seen that it's harder
to initialize OpenGL on a partially
created window...so why persist?
Easy way to find out: Take a screenshot and
see if what's captured matches what your
eyes were seeing.
> On Dec 30, 10:43 pm, "James Van Buskirk" <not_va...@comcast.net>
> wrote:
> > "fungus" <openglMYSO...@artlum.com> wrote in message
> > But your example also doesn't put the OpenGL initialization code in
> > the WM_CREATE handler.
> Why are you obsessed with doing that?
> You've already seen that it's harder
> to initialize OpenGL on a partially
> created window...so why persist?
You know , obsessions drive you on to attain more knowledge
than purely practical considerations would. I find it is
normal in the process of learning new things in programming
to have seemingly unproductive periods where you seem to be
just banging your head against a brick wall for hours on end.
But then, since brick is a rather flimsy material it starts
to erode significantly and all that TBI also makes it more
possible for you to accept the situation. Of course you have
to use the right tools for the job:
http://www.youtube.com/watch?v=GnKXXRkO1Y4&feature=related
This is the kind of way a newbie acquires enough knowledge to be able
to program in the tools he is trying to become proficient at. Note
that I did figure out the problem in the end.
> On Dec 31, 12:19 pm, "James Van Buskirk"
>> WM_CREATE: width = 12
>> WM_CREATE: height = 0
>> WM_SIZE: width = 12
>> WM_SIZE: height = 0
> I never noticed such behaviour - unless by mistake,
> if I explicitely set width | height to zero
> or the window's visibility status to 'hidden'.
> Anyway you can FORCE the window size to whatever you want,
> as well as its visibility status, by calling these functions :
> SetWindowPos(), MoveWindow(), ShowWindow() ...
Well, go back to your program and have it write to a file the
window size on on the WM_CREATE message, the WM_SIZE messages,
and after returning to WinMain from CreateWindowEx. I think
you'll get similar results to what I did.
>>> you can see about 3 or 4 images are overlapped.
> | Not on my PC : no overlap at all
> | and the rotation goes smoothly.
>> Is your monitor a CRT?
> No, it's a laptop LCD.
> Intel Core Duo @ 2.13 GHz
> NVIDIA GeForce GT 230M.
> I also tried on an external CRT
> using the PC's standard SVGA output,
> and all worked pretty fine too.
> I don't think that the problem comes from the software.
I recall reading an article which showed some images of a square
moving rapidly across a 120 Hz LCD TV, and the square showed obvious
motion artifacts. Sorry I can't find the link any more. On my TV
you can see the multiple images at the vertices of the triangle.
If you don't look too close the vertices seem to be fat but on
close-up examination you can see 3 or 4 copies of each point.
Maybe it's more apparent on a TV than a laptop because the screen
is so much bigger. I think they have the same refresh rate (60 Hz).
> Easy way to find out: Take a screenshot and
> see if what's captured matches what your
> eyes were seeing.
I did try capturing the screen with <CTRL><PrtScn> and then pasting
it into Paint, and there was only one image with obvious jaggies.
However in one screen shot there was tearing. Does that mean I'm
not getting double-buffering or can <CTRL><PrtScn> switch buffers
in the middle of its operation?
I think you'd notice if you didn't have
double-buffer... :-)
Most graphics cards can't swap individual
areas of the screen so SwapBuffers() usually
has to do a copy from back buffer to front
buffer in a window. I guess the screenshot
can interrupt that copy.
There's nothing flimsy about the Windows message
queue bricks, I promise you...