|
This thread is locked; no one can reply to it. |
1
2
|
Section of Code Lagging the Program |
AceBlkwell
Member #13,038
July 2011
|
I've got a program and it runs fine, but I when I added a moving star background the program starts to lag. The stars don't lag and the mouse doesn't hesitate but clicking the blocks in the game lags horribly. The overall while loop seems to run at a constant speed per my std::cout commands. It's just the mouse clicks or keyboard entry. If I commnent the function call out, other than looking strange, it runs and functions fine. If you wouldn't mind, look this over and let me know where I've messed up. Thanks. 1void star_background()
2{
3 static int y1 = 0;
4 static int y2 = -480;
5
6 al_set_target_bitmap(buffer);
7
8 al_clear_to_color(COLOR::BLACK);
9 al_draw_bitmap(still, 0,0,0);
10 al_convert_mask_to_alpha(stars,COLOR::WHITE);
11 al_draw_bitmap(stars, 0,y1, 0);
12 al_draw_bitmap(stars, 0,y2, 0);
13 y1++;
14 y2++;
15 if(y1>480)
16 y1 =-480;
17 if(y2>478)
18 y2 = -480;
19
20} // end of star_background
|
DanielH
Member #934
January 2001
|
1. Huge issue is al_convert_mask_to_alpha. It should be done once right after the bitmap is loaded or created. That function goes through every pixel. Does a comparison to your color and sets alpha to zero if there is a match. EVERY pixel. Very time consuming. My preferred order |
Edgar Reynaldo
Major Reynaldo
May 2007
|
DanielH is right about al_convert_mask_to_alpha, it should only be called once. Other than that, the issue is not in the code you've shown. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
AceBlkwell
Member #13,038
July 2011
|
Thanks guys. I thought I was probably calling a single call over and over. I did the same thing with random number seed. Daniel, |
DanielH
Member #934
January 2001
|
The "target" is the current bitmap ALL drawing is done to. Yes, set it to your buffer. Then set is back to the display's buffer to draw your buffer to the display's buffer. 1// save current target (may or may not be display, depending on game
2ALLEGRO_BITMAP* target = al_get_target_bitmap();
3
4// set to your buffer
5al_set_target_bitmap(buffer);
6
7// do your drawing here (or call drawing function)
8
9// restore back to previous target
10al_set_target_bitmap(target);
11
12// draw your buffer to target
13al_draw_bitmap(buffer, 0, 0, 0);
14//al_draw_scaled_bitmap(buffer, 0, 0, al_get_bitmap_width(buffer), al_get_bitmap_height(buffer), 0, 0, al_get_display_width(display), al_get_display_height(display), 0);
15al_flip_display();
or set your buffer then set to display's buffer. No need to store current target. ALLEGRO_BITMAP *al_get_backbuffer(ALLEGRO_DISPLAY *display); I do the first just in case the display is not my final target. It usually always is. |
AceBlkwell
Member #13,038
July 2011
|
Thx all, So Daniel, I don't necessarily need a "target" bitmap? I'm trying to understand why one would need to write to buffer_one, then write buffer_one to buffer_too, then buffer_too to the display? Seems like buffer_too is an extra step. Can you give me an example of why you would need to do that? |
DanielH
Member #934
January 2001
|
You can do all your drawing to the display or all your drawing to a bitmap then draw that bitmap to the display. Depends on what you want. Personally, I have a buffer bitmap of pre-determined, non-changing size. I do all drawing to it. Then I scale it to whatever size the display is. Why? 1. if the display size never changed then I might draw only to display. 2. I don't want the display to determine my graphics sizes. 16x16 tiles might be too small to display without scaling. Same goes for any fonts I have. I prefer a set size buffer for that reason. Then scale to any size needed at once. 1// option 1
2void draw_to_buffer(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP* buffer)
3{
4 // save current target (may or may not be display, depending on game
5 ALLEGRO_BITMAP* target = al_get_target_bitmap();
6
7 // set to your buffer
8 al_set_target_bitmap(buffer);
9
10 // do your drawing here (or call drawing function)
11
12 // restore back to previous target
13 al_set_target_bitmap(target);
14
15 // draw your buffer to target
16 al_draw_scaled_bitmap(buffer, 0, 0, al_get_bitmap_width(buffer), al_get_bitmap_height(buffer), 0, 0, al_get_display_width(display), al_get_display_height(display), 0);
17 al_flip_display();
18}
19
20// option 2
21void draw_to_display(ALLEGRO_DISPLAY *display)
22{
23 // set target to display's buffer
24 al_set_target_bitmap(al_get_backbuffer(display));
25
26 // do your drawing here (or call drawing function)
27
28 al_flip_display();
29}
30
31// option 3
32void draw_to_display(ALLEGRO_DISPLAY *display)
33{
34 // by default, target is already set to display's buffer.
35 // no need to set target unless you changed it somewhere else
36
37 // do your drawing here (or call drawing function)
38
39 al_flip_display();
40}
|
AceBlkwell
Member #13,038
July 2011
|
Thanks Daniel, One more question concerning buffers. I've been drawing to a buffer bitmap and then flipping it to the display. Are you saying the display already has a buffer by default? Or is drawing to the display literally drawing to the screen directly? Thanks. |
DanielH
Member #934
January 2001
|
Yes, by default, the display has a main bitmap and the back buffer bitmap. You draw to the back buffer then flip them. You can remove the back buffer with an ALLEGRO_SINGLE_BUFFER option. If you set single buffer then you don't need to call al_flip_display as there is nothing to flip. |
AceBlkwell
Member #13,038
July 2011
|
Daniel thanks for the insight. I think I'm going to try Option 2. |
DanielH
Member #934
January 2001
|
Sounds great. If you don't need to change target to another bitmap then you don't need to call al_set_target_bitmap(al_get_backbuffer(display)); |
AceBlkwell
Member #13,038
July 2011
|
All, Ok, I moved my al_convert_mask_to_alpha() to where I initialize the bitmap files. I removed all references of going back and forth with target / buffer bitmaps. The visual aspect of the program looks great. The moving star background works well. However, my lag is still present and it grows longer between clicks. My question is, is there something that would cause the event queue to lag? I’ve put in std::cout print outs at different locations in the program. Granted not scientific or exact, but it does expose variations. At program start, each time through the game loop the timer is checked (timer event) so looking at my output I have a one to one condition, maybe an occasional one to two. “Loop Check” (Loop check is located just underneath the while() statement. The Timer check is the first item in the if(event.type == ALLEGRO_EVENT_TIMER) section) Then as I start clicking as part of the game, the gap between them grows to one Timer Check to five or six Loop Checks. If I stop clicking after 5-10 sec it goes back to one to one. It’s almost like the event queue, which would include key down and mouse clicks slows down or doesn’t samples as fast. I must point out, if you have the patience, the games functions as it should. It's just the mouse click results lag horribly. While the star code earlier in the thread may not be problematic, when I comment it out my lag issue goes away. Maybe it’s the bitmaps being used with in the star code. Any ideas / comments are welcome. If I don’t hear back, have a great 4th holiday. |
DanielH
Member #934
January 2001
|
Is it possible to post the code? At least the loop and event sections? I suspect the issue is there. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
You're likely drawing once for every mouse or keyboard event. That's a no-no. Post your event handling code. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
AceBlkwell
Member #13,038
July 2011
|
I'll send the loop data. First I want to ask a follow up on my original question. I thought I no longer needed a target bitmap and I could work with the buffer bitmap only. But when I commented the target code out, my screen won't change from the title screen. If I choose Setup, the screen changes fine. If I choose Play, it doesn't. Below is the code for drawing the game play itself. Can you tell me why I would still need the target code? I'm thinking I started using it when I started working with the scale command. Maybe it requires it. Let me know what you think. Thanks. 1void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[])
2{
3 target = al_get_target_bitmap();
4 al_set_target_bitmap(buffer);
5 star_background();
6 display_verbiage(nError,nGameOver,nTurnPos,nPlayer);
7 draw_cards(Cards);
8
9 al_set_target_bitmap(target);
10 al_draw_scaled_bitmap(buffer, 0, 0, nBufferWD, nBufferHT, 0, 0, nDispWD, nDispHT, 0);
11 al_flip_display();
12} // end display_print
|
DanielH
Member #934
January 2001
|
ALL drawing functions draw to the target bitmap. What's your target? Is it the display's back buffer or your buffer? If you don't use a buffer and always draw to the display then you don't need to mess with the targeting. If you use a buffer and want to draw to that buffer then you need to change the current target to that buffer. Draw to the buffer. Then change the current target again back to previous target (the display's back buffer). Then draw your buffer to the display. Scaling is tricky if you don't use a buffer. You would have to scale each bitmap drawn to the display and calculate the scaled position. Or use transforms, which is what the scale functions use in the background. I find it so much easier to use a buffer and scale it once after I draw everything to it. |
AceBlkwell
Member #13,038
July 2011
|
This is a situation where I copied the scale code & altered for my needs without understanding what is going on. If I comment out both lines 3 & 9, the program won't run. Or the screen won't change from the title screen. I don't write to target (Line 3)so I'm not sure why it's needed. In line 4 I set the targeted bitmap to buffer. I draw in star background(), display verbiage(), & draw cards() functions. I assume they are drawing to the buffer bitmap since it's the last set as the targeted bitmap. Upon returning I scale the buffer bitmap and flip. The actual target bit map in line 3 isn't used at all. In any case, I vaguely remember when looking into the scale command, someone saying I needed to switch the targeted bitmap to a second bitmap (target bitmap in this case) before scaling the buffer bitmap. It's like they are saying a targeted bitmap can't be scaled. This maybe the case, but I'm not understanding why. Thanks *UPDATE* BTW using names like target and buffer in the program makes sense, but not very helpful when trying to explain your program flow. I think I need to come up with a new naming scheme. |
DanielH
Member #934
January 2001
|
There's a bit of confusion on 'target' especially. It's just a bitmap. By default it is the display's back buffer bitmap. I didn't make the names Target = Destination In allegro 4 and previous, you could specify the target as a parameter in this function dest is the target bitmap of the draw call. In allegro 5, target is implied 1void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[])
2{
3 // get current bitmap target
4 target = al_get_target_bitmap();
5
6 // set current bitmap target to the bitmap buffer
7 al_set_target_bitmap(buffer);
8
9 // draw to target bitmap
10 star_background();
11 display_verbiage(nError,nGameOver,nTurnPos,nPlayer);
12 draw_cards(Cards);
13
14 // set to previous target (probably the display's bitmap buffer)
15 al_set_target_bitmap(target);
16
17 // draw to target bitmap
18 al_draw_scaled_bitmap(buffer, 0, 0, nBufferWD, nBufferHT, 0, 0, nDispWD, nDispHT, 0);
19
20 // swap front and back buffers
21 al_flip_display();
22}
Like I said, you don't need your bitmap if you draw directly to the display back bitmap. void display_print(CARDS Cards[],int nError,int nGameOver,int nTurnPos,int nPlayer[]) { // draw to display's back buffer star_background(); display_verbiage(nError,nGameOver,nTurnPos,nPlayer); draw_cards(Cards); // swap front and back buffers al_flip_display(); }
|
AceBlkwell
Member #13,038
July 2011
|
Thanks Daniel. At some point in this thread you and Edgar asked for my game loop code so you could see the various events. Keep in mind, I didn't write it with the intent of sharing with others. If there are process improvements that I can make, I'm excited to hear them. I'm always open to learn from the more experienced. If your just critiquing my coding technique, I already know it's sloppy . This code is in its own file and function. In main() I show title screen and wait for choice of Play, Setup, & Quit. If Play is chosen, we end up here. 1while (!bQuit)
2{
3 al_wait_for_event(queue, &event);
4
5 if(nTurn == 0) // Alters palyer's turn arrow
6 nTurnPos = 450;
7 if(nTurn == 1)
8 nTurnPos = 480;
9
10 if(nChoiceCount ==2)
11 {
12
13 if(bDraw == false) // clears card flipped status for card choice that didn't match
14 { // bDraw is made false after screen draw and stall of non matching cards.
15 nRest = 38;
16 for(int count = 0;count<CQTY;count++)
17 {
18 if(!Cards[count].bMatched)
19 {
20 Cards[count].bFlipped = false;
21 }
22 } // Card Flip Cleared
23 nChoiceCount=0;
24 } //if bDraw
25 } //end nChoiceCount if
26
27
28 if(event.type == ALLEGRO_EVENT_KEY_DOWN)
29 {
30 nKey = event.keyboard.keycode-1; // nKey is Card array index. Needs to start with zero.
31 if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE && nGameOver == 24) // Checks for Escape key after all 24 cards have been played
32 {
33 return false;
34 }
35 if(event.keyboard.keycode >= ALLEGRO_KEY_A && event.keyboard.keycode <= ALLEGRO_KEY_X && !Cards[nKey].bMatched)
36 { // Loop for keyboard choice A ~ X
37 Cards[nKey].bFlipped = true;
38 if(nChoiceCount == 0) nFirstChoice = nKey;
39 if((nChoiceCount == 1)&& (nKey == nFirstChoice)) nError = 1; // Checking for hitting same key
40
41 else
42 {
43 nSecondChoice = nKey;
44 nError = 0; // clears any previous duplicate choice/
45 nChoiceCount++;
46 }
47
48 } // end if for block choice
49
50 if(nChoiceCount == 2)
51 {
52 if(Cards[nFirstChoice].nValue == Cards[nSecondChoice].nValue ) // Sets matched flag if values match
53 {
54 Cards[nFirstChoice].bMatched = true;
55 Cards[nSecondChoice].bMatched = true;
56 nGameOver+=2; // Adds to more to end of game total
57 nPlayer[nTurn]++;
58 bTurn = true;
59 } // end match if
60 if((Cards[nFirstChoice].bFlipped && Cards[nSecondChoice].bFlipped )&&(Cards[nFirstChoice].nValue != Cards[nSecondChoice].nValue ))
61 { // allows two nonmatching cards to be drawn and stay visible for X.XX secs
62 bDraw = true; // bDraw prevents the resetting of the cards prior to being visible.
63
64 }
65 switch(nTurn) // Switch to alter players back and forth.
66 {
67 case 0:
68 if(!bTurn)
69 nTurn = 1;
70 bTurn = false;
71 break;
72 case 1:
73 if(!bTurn)
74 nTurn = 0;
75 bTurn = false;
76 break;
77 } // end nTurn switch
78 }// end if nChoiceCount == 2 actions
79 }// end if event.type
80
81 if(event.type == ALLEGRO_EVENT_MOUSE_AXES)
82 {
83 nPos_y = event.mouse.y;
84 nPos_x = event.mouse.x;
85 } // end mouse axis
86
87 if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) //Checking to see if mouse location is within Card location
88 {
89
90 for(int count = 0;count<CQTY;count++)
91 {
92 if(nPos_x >= (Cards[count].fTX*fPercent_Diff_WD) && nPos_y >= (Cards[count].fTY*fPercent_Diff_HT))
93 {
94 if(nPos_x <= (Cards[count].fBX*fPercent_Diff_WD) && nPos_y <= (Cards[count].fBY*fPercent_Diff_HT))
95 {
96 if(!Cards[count].bMatched) // Checks to see if choice is already matched or chosen.
97 {
98 Cards[count].bFlipped = true;
99 if(nChoiceCount == 0) nFirstChoice = count;
100 if((nChoiceCount == 1)&& (count == nFirstChoice)) nError = 1;
101 else
102 {
103 nSecondChoice = count;
104 nError = 0;
105 nChoiceCount++;
106 } //end else
107 } //end if for matched card re-click
108 }// end if for bottom corner check
109 } //end if for top corner check
110 }// end for
111 if(nChoiceCount == 2) // Sets matched flag if values match
112 {
113 if(Cards[nFirstChoice].nValue == Cards[nSecondChoice].nValue )
114 {
115 Cards[nFirstChoice].bMatched = true;
116 Cards[nSecondChoice].bMatched = true;
117 nGameOver += 2 ; // adds 2 to game end total
118 nPlayer[nTurn]++;
119 bTurn = true;
120 } // end match if
121
122 if((Cards[nFirstChoice].bFlipped && Cards[nSecondChoice].bFlipped )&&(Cards[nFirstChoice].nValue != Cards[nSecondChoice].nValue ))
123 { // allows two non-matching cards to be drawn and stay visible for X.XX secs
124 bDraw = true; // bDraw prevents the resetting of the cards prior to being visible.
125
126 }
127 switch(nTurn) // Switch to alter players back and forth.
128 {
129 case 0:
130 if(!bTurn)
131 nTurn = 1;
132 bTurn = false;
133 break;
134 case 1:
135 if(!bTurn)
136 nTurn = 0;
137 bTurn = false;
138 break;
139 } // end nTurn switch
140 }// end if nChoiceCount == 2 actions
141 }// end button down
142
143 if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
144 {
145 bQuit = true;
146 }
147 if(event.type == ALLEGRO_EVENT_TIMER)
148 {
149 if(bDraw == true)
150 nRest--;
151 if(bDraw == true && nRest == 0)
152 bDraw = false;
153
154 display_print(Cards,nError,nGameOver,nTurnPos,nPlayer); // After all the changes and checks are made, calls card drawing, screen flipping function.
155
156
157 }// end while()
158
159return true;
160} //end game_play()
Thanks for taking the time to look it over. |
DanielH
Member #934
January 2001
|
Couple things I see I'll preface this by saying this is my opinion. Your braces don't match. The end brace for timer is labeled // end while. That puts the draw call inside the timer code. if(event.type == ALLEGRO_EVENT_TIMER) { if(bDraw == true) nRest--; if(bDraw == true && nRest == 0) bDraw = false; } // end timer // Never link drawing to a timer. NEVER. Timers are for logic. display_print(Cards,nError,nGameOver,nTurnPos,nPlayer); // drawing should happen every time something changes on the screen. // a boolean dirty variable can be used if it's dirty and needs a refresh // that should be set by the logic not the timer. dirty = (did_something_change) That is probably most of your lag problem ... maybe. I don't like waiting for events. the other lag I see is that you are doing a ton of logic during an event. That can't be helped unless you make some variables to store your input. The timer should regulate the logic not your input events. That way the logic is running at the same speed regardless the computer speed. Input events are there to set your keyboard/mouse state variables (if you had them). They should be short and fast. They should not to tie up processing speed by doing logic in the events themselves. All you need is 2 extra variables bool mouse_is_being_pressed = false; bool mouse_was_pressed_since_i_last_did_logic = false; These are set in your mouse button up/down events. if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { mouse_is_being_pressed = mouse_was_pressed_since_i_last did_logic = true; } if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { mouse_is_being_pressed = false; } Your mouse_axes event code is short enough it's fine. Then all the logic code you currently have in your button up/down should be put in the timer. or another function to keep clean. if(event.type == ALLEGRO_EVENT_TIMER) { if (mouse_was_pressed_since_i_last_did_logic) { // do your code that checks } else { } mouse_was_pressed_since_i_last_did_logic = false; } add the same for keyboard if you need to |
AceBlkwell
Member #13,038
July 2011
|
Thanks Daniel. I'll look and see how I can rearrange. However I did find one thing confusing (shock huh?). When I first wrote a small program to test an idea for a moving star background. I notice the stars looks great until I started clicking the mouse. Then it would hang for a split second or speed up. At that time I was told on this site, can't remember by who, to put the drawing in the timer event so it would be uniformed. The thought being the time event is going to be true with each click of the clock. Does this make sense or did I misunderstand? Or is it a personal choice type thing? Thanks again for all the help. |
DanielH
Member #934
January 2001
|
I have heard that too and I've been trying to stop it. They think they can get uniform control by putting the drawing in the timer. The logic handles control not the drawing. The logic should be in the timer if you want uniformity. The drawing should either be done every loop or using the dirty boolean like I said. Try putting the draw call outside of timer for the time being and see if that helps at all. There are a couple other little things: 1 switch(nTurn) // Switch to alter players back and forth.
2 {
3 case 0:
4 if(!bTurn)
5 nTurn = 1;
6 bTurn = false;
7 break;
8 case 1:
9 if(!bTurn)
10 nTurn = 0;
11 bTurn = false;
12 break;
13 } // end nTurn switch
14
15// could be shortened to
16if (!bTurn) {nturn = 1 + -nTurn; bTurn = false;}
That's if it's an int. If it's a bool then you can use: No big deal, but I find it funny you didn't use a switch for the event types, but went with ifs. Then for something small with 2 choices you used a switch. Just a personal thing. --- One thing you could to to decrease processing time. Multiplcation is expensive. Avoid if necessary or do some precalculations. Add a few extra variables to Cards[] and store already calculated values. if(nPos_x >= (Cards[count].fTX*fPercent_Diff_WD) && nPos_y >= (Cards[count].fTY*fPercent_Diff_HT)) { if(nPos_x <= (Cards[count].fBX*fPercent_Diff_WD) && nPos_y <= (Cards[count].fBY*fPercent_Diff_HT))
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
A good event loop is the basis of all allegro programs. 1bool quit = false;
2bool redraw = true;
3
4while (!quit) {
5 if (redraw) {
6 Draw();
7 al_flip_display();
8 redraw = false;
9 }
10 do {
11 ALLEGRO_EVENT ev;
12 al_wait_for_event(queue , &ev);
13 if (ev.type == ALLEGRO_EVENT_TIMER) {
14 redraw = true;
15 }
16 else if (ev.type == ALLEGRO_EVENT_MOUSE_AXES) {
17
18
19 }
20 else if (ev.type == ...) {
21
22 }
23 } while (!al_is_event_queue_empty(queue));
24
25}
26
27return 0;
Really take it to heart, because when you don't follow a proper event loop you get all kinds of problems in your program like drawing lag and input lag. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
AceBlkwell
Member #13,038
July 2011
|
Daniel, I think the program has a larger issue. I moved the draw command but it didn't help, maybe even increased the lag. I'll dig deeper. Edgar, I appreciate the insight. I'll look into it. I wouldn't dream of questioning someone who knows far more than I but someone on here stated part of my original issue was using if else. They suggested using ifs only. Does it really matter either way? Thanks. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
The only difference between if and else if is when you want to chain conditions. Here both will execute. if (a) { } if (b) { }
Here the second is only triggered if !a is true. if (a) { } else if (b) { } if/else if/switch they're all the same pretty much, but the small differences are what separates them. Premature optimization is not good. Even a decade old computer can handle millions of multiplications per second. You're not coming anywhere near a bottleneck in performance, so write the code the way it is easiest to understand. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|
1
2
|