Is there any difference between calling glutPostRedisplay() at the end of my display function and using an idle function callback that does nothing but call my display function? I have seen both ways used in examples and cannot tell the difference by observation.
A main loop generally looks like this:
Process and handle events
calling stuff like glutKeyboardFunc/glutMouseFunc.
Advance/update 3D state (physics/animation etc)
typically in glutIdleFunc
Re-draw the scene if needed
use glutDisplayFunc
glutPostRedisplay simply sets a flag, that tells glut to call the display callback on the next loop iteration. It doesn't actually call display [1] [2].
If you have a game, which always updates every frame this might not be that useful. Maybe if you're alt-tabbed or dragging the window you don't need to be calling display. Or you might be frame limiting by dropping frames (although I'd suggest this).
void idle()
{
...
animatedThing.value += deltaTime
glutPostRedisplay(); //scene is always changing. always call display
}
Having a "dirty" flag becomes more useful when you don't need to re-render continuously. Maybe in something like a 3D modelling package where there isn't any animation and you only move the camera occasionally. Or a GUI where you only need to update when you hover and click on stuff.
void mousedown(int button, int state, int x, int y)
{
if (clickedGUI(x, y))
glutPostRedisplay();
}
void idle()
{
...
if (myKeys[MOVE_VIEW_FORWARD])
{
view.z -= deltaTime;
glutPostRedisplay();
}
}
Anyway, to answer your question, no, there's probably not much difference. However...
I'd put the glutPostRedisplay in idle as above. Calling from within display works but gives up some control you might want later. It's essentially this:
bool shouldDraw = true;
while (1)
{
// check events, input etc
// idle/update state
if (shouldDraw)
{
shouldDraw = false;
// draw
shouldDraw = true;
}
}
I also wouldn't call display from idle from a design perspective as it removes some control from glut. For example if there's a case where glut needs to override the post-redisplay (not that I know of one) it won't be able to.
Related
I made a function to move an borderless SDL window. I use SDL_MOUSEBUTTONDOWN to 'activate' the window movement and SDL_MOUSEBUTTONUP to 'deactivate' it. For some reason it does not just move like it should but instead moves way slower than my mouse and flickers if I moved it by a good distance.
I use SDL2, and I'm on windows 10.
My loop always updates my mouse position, and the function takes the mouse position reduces it by the last mouse position and then moves the window by that distance.
sPos moveClock(int event){
sPos temPos = setPos(0,0);
if(tempMoveVar==1){
temPos = setPos(gvMousePos.x-mPos.x,gvMousePos.y-mPos.y);
mPos = setPos(gvMousePos.x,gvMousePos.y);
}else if(event==-1){ //Mouse Down
mPos = setPos(gvMousePos.x,gvMousePos.y);
tempMoveVar=1;
}
if(event==-65){ //Mouse Up
tempMoveVar=0;
}
return temPos;
}
I just want the window to move 'with' the mouse while my mouse button is down, like you normally can move windows.
Rather than moving the window manually, I suggest using SDL_SetWindowHitTest:
int SDL_SetWindowHitTest(SDL_Window* window, SDL_HitTest callback, void* callback_data);
This function lets you specify what dragging specific pixels of a window does (possible actions are moving the window, resizing it, or doing nothing).
You should probably call this function once, after creating your window.
Parameters are:
SDL_Window* window speaks for itself.
SDL_HitTest callback receives a function that, when given coordinates of a pixel, determines what dragging this pixel does.
void* callback_data is described below.
You need to write a function to pass to callback. It has to have following return type and parameter types:
SDL_HitTestResult MyCallback(SDL_Window* win, const SDL_Point* area, void* data)
{
...
}
area->x and area->y are the coordinates of the pixel that's being checked. win is the window.
data will receive the same pointer you passed to callback_data when calling SDL_SetWindowHitTest. You can use this pointer to pass arbitrary data to your callback; or, if you don't need it, simply set it to 0.
Your callback should return one of the following:
SDL_HITTEST_NORMAL - no action.
SDL_HITTEST_DRAGGABLE - dragging this pixel moves the window.
SDL_HITTEST_RESIZE_* - dragging this pixel resizes a specific edge (or edges) of the window. (Here * is one of: TOPLEFT, TOP, TOPRIGHT, RIGHT, BOTTOMRIGHT, BOTTOM, BOTTOMLEFT, LEFT).
I am using wxwidgets and I have a code like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
wxYield();
}
The wxYeild doesn't update guauge. I am wondering why it is not working?
Looking at wxYield, I noted that it returns a bool but there is no documentation on what it returns.
Why my guauge is not update and how I can fix it?
what wxYield returns?
You do not say what gaugeProgressFolders is. Perhaps it is wxGauge?
In any case, why do you expect wxYield to magically update the display?
You have to write code to update the display.
Assuming various things about your code, you could write something like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
// wxYield(); Don't call this, it does nothing
// force the window to be repainted RIGHT NOW.
Refresh();
Update();
}
You might also try the following, for the sake of efficency and less flicker
// force the gauge to be repainted.
gaugeProgressFolders->Refresh();
gaugeProgressFolders->Update();
Perhaps this is a little late to respond, but I don't think wxYield() is the right call for your purpose of updating a gauge. Perhaps try:
gaugeProgressFolders->SetRange(folderList.size());
for (int i = 0; i < folderList.size(); i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
this->Layout(); //this being your window/dialog/frame
}
Layout() forces the layout to redraw. It has been effective for me in the past.
I have a main layer that should get touch events. But on that layer there is a navigation bar, which has buttons and other sprites in it and is a subclass of cocos2d::Sprite. Now I need that all touches on navigation bar were not interpreted as touches on main layer. The buttons work correctly, but navigation bar sprite passes touches to main layer. I have done this to prevent passing events:
auto touchListenerOneByOne = EventListenerTouchOneByOne::create();
touchListenerOneByOne->setSwallowTouches(true);
touchListenerOneByOne->onTouchBegan = CC_CALLBACK_2(NavigationBar::onBoardTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListenerOneByOne, this);
bool NavigationBar::onBoardTouchBegan(Touch* touch, Event* event)
{
CCLOG("Navigation sprite is touched......!");
return true;
}
This prevents passing, but it blocks - swallows all touches. Now I cannot pass any touch to the main layer, even if I don't touch the navigation bar. I have tried to use setContentSize but it does not help. Where is the solution?
Answer is here: http://www.cocos2d-x.org/wiki/How_To_Subclass_Sprite_And_Add_Event_Listeners
I have changed here the follwing things:
Vector2 to Vec2,
removed second argument in void touchEvent(cocos2d::Touch* touch, cocos2d::Vector2 _p);
MySprite::touchEvent(touch); to touchEvent(touch);
cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener, 30); to _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
It turns that the sprite should check if the touch is on it, than swallow but returning truein the onTouchBeganlistener, otherwise false.
I have a code that continuously draws lines. The problem is that the lines keep flickering every time form is refreshed. I heard I should use double buffering, but how to do it? I'm using c++ builder 2010. Here is my code:
void __fastcall TForm2::PaintBox1Paint(TObject *Sender)
{
Form2->Refresh();
TPoint P;
::GetCursorPos( &P );
P = ScreenToClient( P );
int XX;
int YY;
if (P.x<240)
{
XX=15;
YY= ((445-P.y)*(XX-P.x)/(240-P.x)+P.y);
}
else if(P.x==240)
{
XX=240;YY=-5;
}
else
{
XX=465;
YY= ((445-P.y)*(XX-P.x)/(240-P.x)+P.y);
}
int delta=2*(445-YY);
this->Canvas->MoveTo(241,445);
this->Canvas->LineTo(XX,YY);
while(0<YY&&YY<480&&YY!=445)
{
XX=abs(480-XX);
YY-=delta;
this->Canvas->LineTo(XX,YY);
}
}
Certainly you need to remove the call to Form2->Refresh. That asks the form to repaint itself immediately. That cannot help.
Secondly, your code handles the OnPaint event of a TPaintBox control. You are expected to paint on the canvas of TPaintBox rather than the form's canvas. Change all references to this->Canvas to instead refer to PaintBox1->Canvas. You may also need to correct the coordinates used to when painting.
Alternatively you could keep your existing code, and remove the paint box altogether. In which case take your current code and attach it to the form's OnPaint handler instead.
As for double buffering, you could let the VCL do it for you. Set the form's DoubleBuffered property to true. That is all you need to do, although be warned that it can have undesirable consequences on the visual appearance of certain control in certain themes. Be alert for any problems.
If you want to do the double buffering your self it is easy enough. Create a TBitmap. Set its size appropriately. Draw your lines to the Canvas of the bitmap. Then draw the bitmap onto the paint box canvas, or the form's canvas.
i have many sprites and i want to move them in screen sequentially. for example 'A' moves to (x1,y1) place then 'B' goes to (x2,y2). i want to run these actions sequentially means first 'A' finishes it's job then 'B' starts.
i have a function that when i call it, returns a sprite and a place and i should send the sprite to that place. in the move function i have somthing like this:
void move(){
for(int i=0;i<10;i++){
pair<CCSprite,CCPoint> x=get();
CCFinitTimeAction* act=CCMoveTo::actionWithDuration(DIST/SPEED,x.second);
x.first->runAction(act)
}
}
now how can i make a delay until a motion finishes. i had put this line after runAction but it didn't work:
while(!act->isDone());
Assuming that get() can be called to fetch sprite 2 right when sprite 1 finishes, you could implement this using a callback that calls get() and starts the next sprite's movement. For this, you need to create a callback method. Assuming you are doing this in a scene, the following code should do it
void YourSceneClass::move() {
moveNext();
}
void YourSceneClass::moveNext() {
pair<CCSprite,CCPoint> x=get();
CCFinitTimeAction* move=CCMoveTo::actionWithDuration(DIST/SPEED,x.second);
CCCallFunc* startNext=CCCallFunc::create( this,
callfunc_selector(YourSceneClass::moveNext) );
CCSequence* act=CCSequence::create(move, startNext, NULL);
x.first->runAction(act);
}
With this code in your scene, you should be able to call move and have the first sprite start moving with the second one moving after that and so on. To make it stop, you have to add an appropriate condition in moveNext().