Well, I'm trying to make the day/night cycle in a scene using opengl with c++. I've tried glutTimerFunc. Although I 've bounded the time slice to be 10000 ms = 10 s, it gave me a very fast flipping effect.
Here is what I have done.
void turn (int value){
if(night)
{
glDisable(GL_LIGHT0);
glEnable(GL_LIGHT1);
night=!night;
}
else
{
glDisable(GL_LIGHT1);
glEnable(GL_LIGHT0);
night=!night;
}
//glutPostRedisplay();
glutTimerFunc(10000,&turn,2);
}
And in DrawGLScene function I 've called that function. And here is the WinMain function:
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("day night",700,500,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
glutTimerFunc(10000,&turn,2);
//turn(1);
while(!done) // Loop That Runs While done=FALSE
{
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("day night",700,500,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
}
}
}
// Shutdown
KillGLWindow(); // Kill The Window
return (msg.wParam); // Exit The Program
}
If your DrawGLScene has been registered using glutDisplayFunc and is therefore called to draw each frame then you'll also be (re)registering your timer function every time you redraw the frame, i.e. every time you call glutPostRedisplay().
To start the timer sequence you should just call glutTimerFunc once, before you call glutMainLoop, and not call it in DrawGLScene.
It's still necessary to call glutTimerFunc within the timer function to initiate the next flip.
EDIT I see you're not even using glutMainLoop. This means that your call to glutTimerFunc isn't doing anything. GLUT based handlers only work when they're dispatched by the glutMainLoop function.
The only reason your code is doing anything at all is because you're calling DrawGLScene within a Windows event loop which then directly calls your timer function in each pass through the Windows event loop. This is the source of the unexpectedly high frequency.
If you intend to stick with using the Windows event model then you'd be better off just using standard Windows timer events (i.e. SetTimer) to handle the flips.
Alternatively rewrite your code to use glutMainLoop and have all of the keypresses and other events handled by GLUT.
This is because real day/night is not a boolean, it is a gradual change between day and night. In addition, only 10 seconds is a very short day/night cycle- you usually want a few minutes at least.
Related
So I've created a basic program with a blocking message event loop (to use little to no CPU while waiting) and waits for a user to change the foreground window, then executes some code:
#include <Windows.h>
VOID ExitFunction()
{
// Do Something
}
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_SHUTDOWN_EVENT:
ExitFunction();
return TRUE;
case CTRL_LOGOFF_EVENT:
ExitFunction();
return TRUE;
//default:
//We don't care about this event
//Default handler is used
}
return FALSE;
}
VOID CALLBACK WinEventProcCallback(HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
if (dwEvent == EVENT_SYSTEM_FOREGROUND)
{
// Do Stuff
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWINEVENTHOOK WindowChangeEvent;
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
WindowChangeEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
while (GetMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ExitFunction();
return 0;
}
I also want to incorporate checking if the user has been inactive for a certain amount of time (no mouse/keyboard input) but keep resource usage low. There are a couple of ways to approach this that I can think of:
Have the blocking event loop check if there has been mouse or keyboard input which resets some kind of timer back to zero and also checks within the same loop if the mouse input resulted in a foreground window change (which may cause issues if there is a delay between the mouse click event and the foreground window change (meaning the foreground window change won't be captured). Have an event triggered when the user input timer has completed the specified time.
Run the mouse & keyboard activity event timer on a separate thread or asynchronously to the foreground window change event. When the timer has completed fire off an event (run on separate thread or asynchronously to make sure a foreground window change event isn't missed).
On a separate thread or asynchronously, check every couple seconds the GetLastInputInfo() function to see if the inactivity threshold time has elapsed.
It can be called like so:
LASTINPUTINFO li;
li.cbSize = sizeof(LASTINPUTINFO);
GetLastInputInfo(&li);
Keeping in mind lowest resource usage, what way is best to implement the mouse/keyboard inactivity checking while also checking for foreground window changes.
You can set up a timer (see SetTimer) to have a user-defined callback called when an arbitrary timeout expires. This allows you to break out of the blocking GetMessage loop.
The callback can check the timestamp of the last input, and compare it to the current timestamp. If that time interval exceeds the desired inactivity timeout, it can perform the necessary steps. Otherwise it restarts the timer with the remainder of the timeout.
The following code illustrates this:
#include <Windows.h>
#include <iostream>
static const DWORD timeout_in_ms { 5 * 1000 };
void TimeoutExpired() { std::wcout << L"Timeout elapsed" << std::endl; }
void CALLBACK TimerProc(HWND, UINT, UINT_PTR id, DWORD current_time)
{
// Timers are periodic, but we want it to fire only once.
KillTimer(nullptr, id);
LASTINPUTINFO lii { sizeof(lii) };
GetLastInputInfo(&lii);
auto const time_since_input { current_time - lii.dwTime };
if (time_since_input < timeout_in_ms)
{
// User input was recorded inside the timeout interval -> restart timer.
auto const remaining_time { timeout_in_ms - time_since_input };
SetTimer(nullptr, 0, remaining_time, &TimerProc);
}
else
{
TimeoutExpired();
}
}
void StartInactivityTimer()
{
// Start a timer that expires immediately;
// the TimerProc will do the required adjustments and
// restart the timer if necessary.
SetTimer(nullptr, 0, 0, &TimerProc);
}
int wmain()
{
StartInactivityTimer();
MSG msg {};
while (GetMessageW(&msg, nullptr, 0, 0) > 0)
{
DispatchMessageW(&msg);
}
}
The entire logic is contained within TimerProc. To trigger the inactivity timer, StartInactivityTimer starts a timer that expires immediately. When TimerProc takes control it does the required calculations, and either restarts the timer, or calls the timeout procedure, TimeoutExpired.
This implementation has two advantages: For one, the entire timer restart logic is in a single place. More importantly, the inactivity condition is evaluated on first call. If StartInactivityTimer is called without any user input in the inactivity interval, it instantly executes TimeoutExpired.
Also note that the interval calculations use unsigned integer arithmetic, specifically subtraction. With unsigned integer 'underflow' being well defined in both C and C++, this solution is immune to GetTickCount's return value wrapping around to 0 after approximately 49.7 days.
I'm trying to learn WTL / Win32 programming, and I don't quite understand the design of the CIdleHandler mixin class.
For WTL 9.1, The CMessageLoop code is as follows (from atlapp.h):
for(;;)
{
while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
The actual call to idle handlers is very straightforward.
// override to change idle processing
virtual BOOL OnIdle(int /*nIdleCount*/)
{
for(int i = 0; i < m_aIdleHandler.GetSize(); i++)
{
CIdleHandler* pIdleHandler = m_aIdleHandler[i];
if(pIdleHandler != NULL)
pIdleHandler->OnIdle();
}
return FALSE; // don't continue
}
As is the call to IsIdleMessage
static BOOL IsIdleMessage(MSG* pMsg)
{
// These messages should NOT cause idle processing
switch(pMsg->message)
{
case WM_MOUSEMOVE:
#ifndef _WIN32_WCE
case WM_NCMOUSEMOVE:
#endif // !_WIN32_WCE
case WM_PAINT:
case 0x0118: // WM_SYSTIMER (caret blink)
return FALSE;
}
return TRUE;
}
My analysis is as follows: it seems like once per "PeekMessage Drought" (a period of time where no messages are sent to the Win32 Application), the OnIdle handlers are called.
But why just once? Wouldn't you want background idle tasks to continuously be called over and over again in the case when PeekMessage ? Furthermore, it seems strange to me that WM_LBUTTONDOWN (User has left-clicked something on the Window) would activate idle processing (bDoIdle = True), but WM_MOUSEMOVE is explicitly called out to prevent reactivation of idle processing.
Can anyone give me the "proper" use scenario of WTL Idle Loops (or more specifically: CIdleHandler)? I guess my expectation was that Idle-processing functions would be small, incremental tasks that take no more than say... 100ms to complete. And then they'd be called repeatedly in the background.
But it seems like this is not the case in WTL. Or maybe I'm not fully understanding Idle loops? Because if I had an incremental background task registered as a CIdleHandler... then if the user stepped away from the window, the task would get run only once! Without any messages pumped into the system (such as WM_LBUTTONDOWN), the bDoIdle variable would remain false for all time!
Does anyone have a good explanation for all this?
As said in the comments, OnIdle handler is supposed to be called when idling starts after certain activity, esp. in order to update UI. This explains "once" calling of the handlers: something happened and then you have a chance to once update the UI elements. If you need ongoing background processing, you are supposed to use timers or worker threads.
WTL samples suggest the use of idle handlers, e.g. in \Samples\Alpha\mainfrm.h.
Window class picks up message loop of the thread and requests idleness updates:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
Later on after message processing and user interaction, the idleness handler updates toolbar to reflect possible state changes:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
I am just learning to create a gui using the winapi, but i have run into an issue. I can create a window like this
#include "stdafx.h"
#include <windows.h>
int main()
{
HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_gettch();
}
But the windows will not close when the close button is clicked, and the window can not be dragged around or moved. I was wondering how i would enable these features of the window.
Static windows are not there for normal windows, you should try and look up how to register and handle your own class with RegisterWindowEx then use the same class name to create a window. You have to have your own window procedure in order to handle messages.
All window classes registered by the system run their own default window procudure and as far as I know none of them handle WM_CLOSE ( that is the close button ) this is why you can't close it.
For you main windows always use something like WS_OVERLAPPEDWINDOW so it'll be clear if it's okay or not and from that eliminate the flags you don't need.
How you set it up :
WNDCLASSEX wndcls;
HWND hMainWnd;
// Register your own window class
ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
wndcls.cbSize=sizeof(WNDCLASSEX);
wndcls.style=CS_VREDRAW+CS_HREDRAW;
wndcls.lpfnWndProc=&appWndFunc;
wndcls.hInstance=hInstance;
wndcls.hIcon=hMainIcon; // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
wndcls.hIconSm=hMainIcon;
wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
wndcls.lpszClassName="myWndClass";
if (RegisterClassEx(&wndcls)==0)
{
// failed to register class name
return false;
}
// Create window with your own class
hMainWnd=CreateWindowEx(0,\
"myWndClass","widnow title",\
WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
0,\
0,\
250,\
250,\
hMainWnd,NULL,hInstance,NULL);
if (hMainWnd==(HWND)NULL)
{
// failed to create main window
return false;
}
Then your main loop :
bool bAppMainLoop=false
while(!bAppMainLoop)
{
WaitMessage();
while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
{
if(GetMessage(&emsg,NULL,0,0)==0)
{
bAppMainLoop=true;
break;
}
TranslateMessage(&emsg);
DispatchMessage(&emsg);
}
}
This is a bit more than usual setup, so let me explain , in order to not burn CPU, you wait for a message with WaitMessage, it'll block until something happens, like move window, click, paint etc. PeekMessage will return true if there is a message so calling it in a while loop will make sure it drains the message quene, GetMessage will obtain the message if it returns 0 it means that your app called the PostQuitMessage(0) so a WM_QUIT arrived was found in the message loop that means it's time to break out from the message loop. The rest Translate and Dispatch does what it name says.
Finally you need your own window procedure :
LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (uMsg==WM_CLOSE)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
DefWindowProc is essential that handles all commonly occurring messages from the system, thus you don't need to handle those here. You simply respond to the WM_CLOSE message which is sent when you want to close the window and post a quit message into the message loop that you will catch and exit.
Additional info :
It's not required to release your stuff since windows does that for you so it wont be locked the next time you start your program , but it's a good practice to at least Unregister your window class after your main loop.
Btw that is the wrong main function : WinMain that is the correct one. Plus to avoid even more bugs make sure you compile a windows GUI application.
I am doing a measurement system and I have got a do while loop in my program. In the loop, it is checking if any motor is moving before it could take measurement as it require it to reach the target position before doing anything.
While doing the measurement, it is suppose to tell me how long does it took to do this measurement.
However, whenever it runs in the do while loop, all my timer function stop as if they are put to Sleep mode.
Is there any other method where I could implement this? If there is, please help me.
Any help would be much appreciated.
SetTimer(TIMERECHO, 1000, NULL);
BOOL bMoving = FALSE;
do
{
if (IsMoving(ID, NULL, &bMoving))
GetPosition();
} while (bMoving);
void CLHMDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case TIMERECHO:
UpdateData(FALSE);
m_Seconds++;
m_TimerEcho.Format(_T("Total time: %ds"), m_Seconds);
break;
}
CDialogEx::OnTimer(nIDEvent);
}
MFC has a message loop that gets and dispatches messages such as WM_TIMER. If you do a while loop that message loop is not running. It's not sleeping, it's just waiting until you stop hogging the processor.
You have two options: (1) Get rid of the lengthy loop and do whatever it does periodically on a WM_TIMER message. (2) Use a second thread to do the lengthy operation. This has numerous difficulties for a beginner.
It's because your loop isn't processing messages. onTimer is called as a result of a windows message. You need to keep processing messages in the loop or use a callback based timer.
One method is using CreateTimerQueueTimer
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682485%28v=vs.85%29.aspx
A very simple solution (but not perfect) to get you running is to move your IsMoving to the timer as below:
void CLHMDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case TIMERECHO:
if (IsMoving(ID, NULL, &bMoving))
GetPosition();
UpdateData(FALSE);
m_Seconds++;
m_TimerEcho.Format(_T("Total time: %ds"), m_Seconds);
break;
}
CDialogEx::OnTimer(nIDEvent);
}
However for a proper solution you have to use threads for this, the complexity of that will vary for simple to better solutions there as well. I have written some code on the fly for you, it may not compile but you get the idea.
AfxBeginThread(monitor_motor, this);
UINT monitor_motor(LPVOId lParam)
{
CMyDlg * dlg = (CMyDlg *) lParam;
HWND hWnd = (HWND) dlg->m_hWnd;
do
{
if (IsMoving(ID, NULL, &dlg->bMoving))
GetPosition();
Sleep(100); // maybe you don't have to poll too hard and give other hardware chance to communicate?..that's upto you
PostMessage( hWnd, UPDATE_TIMER_AND_STUFF );
} while (dlg->bMoving);
PostMessage( hWnd, UPDATE_MOTOR_MOVED_COMPLETELY );
}
I have been messing around with OpenGL lately, and I noticed that the windows message pump is blocking whenever i attempt to resize my window, so as a result rendering is halted whenever i click on the menu bar or resize the window.
To fix this, I am looking into multithreading.
I have the following:
_beginthread(RenderEntryPoint, 0, 0);
while (!done)
{
PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void RenderEntryPoint(void *args)
{
while (1)
{
//render code
}
}
However, my scene isn't being rendered, and I'm not sure why.
You need to make the OpenGL rendering context current in the rendering thread, and make sure it's not current in the windowing thread. This also means that you can't call any OpenGL functions from the windowing thread.