Part of my code is running twice, how?
Blitz3D Forums/Blitz3D Programming/Part of my code is running twice, how?
| ||
Hello there, I have a simple-ish program which is basically a start on a menu system. However part of the code is running twice and creating double the amount of graphical buttons. I made an error effect to stop the code, with a counter for the number of "error stops" which increases every time there is an error. Whilst the error portion runs twice, it only counts to one, but it does indeed run twice. additionally, the counter is only changed by adding to it each time the error routine runs, and is a global. Why then is it both running twice, and denying its running twice? Global settings_file$="setup.txt" SeedRnd MilliSecs() Graphics 1024,768,32,2 SetBuffer BackBuffer() init_button_list() Global menu_setup=0 Global menu$="MAIN_MENU" Global mouse_timeout=0 Global ERROR_COUNT=0 Global xpos ; pre setup stuff init_button_list() ;main stuff While KeyDown(1)=0 If menu_setup=0 init_menu() ; load all menu bits EndIf draw_mouse() draw_buttons() buts=0 For bl.blist=Each blist buts=buts+1 Next Color 255,255,255 Text 20,20,buts Flip Cls Wend ;functions Function draw_mouse() Color 255,255,255 Rect MouseX(),MouseY(),5,5 End Function Type but Field img,click_cmd End Type Function draw_buttons() If menu="MAIN_MENU" Then xpos=160 For b.but = Each but DrawImage b\img,GraphicsWidth()/2,xpos xpos=xpos+100 Next EndIf End Function Function errorpoint() ERROR_COUNT=ERROR_COUNT+1 For t = 1 To 100 If Rnd(1,100)>85 Then Color Rnd(255,155),Rnd(255,155),Rnd(255,155) Rect 0+t,0+t,GraphicsWidth(),GraphicsHeight(),0 Next Color 0,0,0 Text 20,20,"BREAKPOINT REACHED! TIME="+MilliSecs() Text 20,35,"WE HAVE REACHED THE POINT YOU WANTED ME TO STOP AND TELL YOU WE HAD REACHED. Text 20+1,35,"WE HAVE REACHED THE POINT YOU WANTED ME TO STOP AND TELL YOU WE HAD REACHED. Text 20,50,"RESUMING IN 5 SECONDS..." Text 20+1,50,"RESUMING IN 5 SECONDS..." Color 0,0,0 Rect 10,72,200,22 Color 255,255,255 Text 20,75,"ERROR NUMBER="+ERROR_COUNT Flip Delay 3000 End Function Function gen_menu_but(txt$,action$,colour$) b.but = New but tempimage=CreateImage(Len(txt$)*12,16,2) frame=0 SetBuffer ImageBuffer(tempimage,frame) Color 0,0,0 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(tempimage)-1,ImageHeight(tempimage)-1,0 getcolour(colour$) Text ImageWidth(tempimage)/2,ImageHeight(tempimage)/2,txt$,1,1 frame=1 SetBuffer ImageBuffer(tempimage,frame) Color 200,150,75 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(tempimage)-1,ImageHeight(tempimage)-1,0 getcolour(colour$) Text ImageWidth(tempimage)/2,ImageHeight(tempimage)/2,txt$,1,1 MidHandle tempimage b\img=CopyImage(tempimage) b\click_cmd=action$ FreeImage tempimage End Function Function init_menu() For b.but = Each but ; clear old menu's buttons FreeImage b\img Delete b Next For bl.blist = Each blist ; scan button list for this menu's buttons If bl\menu$=menu$ Then gen_menu_but(bl\txt$,bl\action,bl\colour) EndIf Next menu_setup=1 End Function Type BLIST Field txt$,menu$,action$,colour$ End Type Function init_button_list() new_blist("THIS IS THE GO BUTTON","MAIN_MENU","menu EDIT_MAIN","yellow") End Function Function new_blist(txt$,menu$,action$,colour$) bl.blist = New blist bl\txt$=txt$ bl\menu$=menu$ bl\action$=action$ bl\colour$=colour$ errorpoint() End Function Function getcolour(colour$) If colour$="red" Then Color 255,0,0 If colour$="green" Then Color 0,255,0 If colour$="blue" Then Color 0,0,255 If colour$="yellow" Then Color 255,255,0 If colour$="purple" Then Color 255,0,255 If colour$="cyan" Then Color 0,255,255 If colour$="grey" Then Color 155,155,155 End Function |
| ||
You call init_button_list() in two places (I assume this is intentional?). Note that you call it the first time above the point where the global variables are declared and initialised. Since the global ERROR_COUNT is "initialised" to zero, this means it is being reset to zero after the first time errorpoint() modifies it. This is an odd consequence of the fact that Blitz3D both allows block-scoped functions (which can usually see all global declarations outside them at all times) and a linear "outer level" that the program tries to run in-sequence - global "initialisation" is actually just any old assignment statement, that also happens to be on the same line that declares the variable. If you want your globals initialised in the "outer level", you should make sure it happens ahead of all other code, to avoid this confusion. You could also note that Blitz3D automatically initialises all variables to zero or Null on entering their scope (unlike, say, C), so in many cases you can just drop the assignment altogether. Last edited 2011 |
| ||
It's always the simple things that stump me. Why did i not see that! |
| ||
I dont suppose anyone can solve the terrible framerate issue can they? I'm only getting about 5 frames a second for some reason? (after removing all delay commans) |
| ||
(Update: see end of post) Well, I've narrowed it down, but I still don't understand why this happens... These lines cause the slowdown: If menu_setup=0 init_menu() ; load all menu bits EndIf Commenting these three lines solves the slowness problem. However, since the test in the first line returns false every frame after the first frame, it takes essentially zero time. And indeed, a time counter placed around the lines shows it takes 0 millisecs, 1 at most. Nevertheless, commenting these lines speeds things to normal. So, creating the menu itself is not slow, but it somehow triggers the subsequent slowness each frame, even though everything else in the main loop is also fast. I realize this makes no sense. Something's very odd here. millisecs from Flip() to Flip() (i.e. between flips) is basically zero. And Flip takes the correct amount of time, 16-17 ms at 60fps. This means that nothing in the main loop is unusually slow. Nevertheless, screen updates are way slower. The screen update is called every frame and just puts a rect at mousex, mousey, and runs predictably fast. So, the main loop runs at 60 fps, but the screen visibly updates at more like 10 fps. How is that possible? The only thing I can figure is that mousex() and mousey() are returning old data for up to 1/10 sec for some reason. UPDATE: Ok, got it I think. You need a SetBuffer(BackBuffer()) at the end of gen_menu_but(). I put one in and it speeds things back to normal. What doesn't make sense now is why it was writing to the screen at all, given SetBuffer() was left on the last button image created. Any ideas why this might happen? |
| ||
Alright Crinkle. Have a look at your button creation code here.Function gen_menu_but(txt$,action$,colour$) b.but = New but tempimage=CreateImage(Len(txt$)*12,16,2) frame=0 SetBuffer ImageBuffer(tempimage,frame) Color 0,0,0 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(tempimage)-1,ImageHeight(tempimage)-1,0 getcolour(colour$) Text ImageWidth(tempimage)/2,ImageHeight(tempimage)/2,txt$,1,1 frame=1 SetBuffer ImageBuffer(tempimage,frame) Color 200,150,75 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(tempimage)-1,ImageHeight(tempimage)-1,0 getcolour(colour$) Text ImageWidth(tempimage)/2,ImageHeight(tempimage)/2,txt$,1,1 MidHandle tempimage b\img=CopyImage(tempimage) b\click_cmd=action$ FreeImage tempimage End FunctionFirst, you create a temporary image. This is actually unnecessary; you can simply create b\img right off the bat and work on that, there's no need to create a temporary image, make a copy, and then delete the original. Next, you grab the first frame of the temp image for drawing, by using frame=0. This is completely unneeded, because the variable frame is local to gen_menu_but(), which means that each time the function is used, frame is already equal to zero by default. Not only that, but using SetBuffer ImageBuffer(tempimage,frame) is also a waste, because the frame parameter of ImageBuffer() is optional, and 0 by default. You can ignore the line frame=0 entirely, and just use SetBuffer ImageBuffer(tempimage). Your code works, it just includes a lot of unnecessary steps that serve no purpose except to add more work for you to type and more clutter for you to read. All your drawing goes fine for the first frame, then you change to the second frame with frame=1. This is also unnecessary; you could simply use SetBuffer ImageBuffer(tempimage,1) and save a line of code. Again, your drawing goes fine, and then we hit the big problem zone. After you're done drawing to tempimage, you finally copy it into b\img, and then delete the temp with FreeImage tempimage. This is fine and good; then you lose it completely, because you exit the function without returning focus to the back buffer. You grabbed the back buffer for drawing at the beginning of your program, which is fine, by using SetBuffer BackBuffer(). By the time you finish with gen_menu_but(), however, you have already changed that twice with SetBuffer ImageBuffer() calls. This means that the active buffer is no longer the back buffer, but still the temporary image you've created. Then, to make it worse, you free the image that the program is still trying to draw to. The result is that the buffer Blitz wants to draw to no longer exists, so to avoid crashing, it returns to the default: the FRONT buffer. Flip() becomes useless, the back buffer is ignored, and the program slows because it's once again trying to draw directly to the monitor itself. Here's a rewrite of gen_menu_but() that solves all of these issues. The code itself is simpler and more compact, but I've added some spacing and comments so you can easily see what's going on. Function gen_menu_but(txt$,action$,colour$) b.but = New but ; Make the button, same as before b\img=CreateImage(Len(txt$)*12,16,2) ; Make the button's image SetBuffer ImageBuffer(b\img) ; Go directly to the first frame ; All the usual drawing stuff Color 0,0,0 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(b\img)-1,ImageHeight(b\img)-1,0 getcolour(colour$) Text ImageWidth(b\img)/2,ImageHeight(b\img)/2,txt$,1,1 SetBuffer ImageBuffer(b\img,1) ; Get the second frame ; Drawing stuff again Color 200,150,75 Rect 0,0,1024,1024,1 Color 155,155,155 Rect 0,0,ImageWidth(b\img)-1,ImageHeight(b\img)-1,0 getcolour(colour$) Text ImageWidth(b\img)/2,ImageHeight(b\img)/2,txt$,1,1 MidHandle b\img b\click_cmd=action$ ; All done - return focus to the back buffer SetBuffer BackBuffer() End FunctionHope this all helps! :D Last edited 2011 |
| ||
I think the frame=1 stuff was so that he could extend it into many more frames with a loop. But for the first two he just hard coded the commands twice. But the fact that Blitz defaults to frontbuffer (if that's what you mean by monitor) when the buffer in SetBuffer() does not exist is interesting. |