Eliminating Lag in a Loop

General FreeBASIC programming questions.
Post Reply
MSMatt
Posts: 8
Joined: May 08, 2010 20:21
Contact:

Eliminating Lag in a Loop

Post by MSMatt »

Hello, I'm trying to make a program in FreeBASIC that is kind of a very basic version of MS Paint. However, I have the algorithm for writing to the image buffer, but it lags terribly, and I can't draw a straight line quickly.

Any help for trying to reduce lag?

Code: Select all

        do
            getmouse (mX, mY, , mB)
            if mB = 1 and mY < 292 then
                pset (mX, mY), RGB(redValue, greenValue, blueValue)
            end if
            cC = inkey$
            if cC = "X" or cC = "x" then
                programStatus = 4
                draw string (1,291), "Would you like to save the image? (Y/N)", RGB(255,255,0)
                do
                cC = inkey$
                loop until cC = "Y" or cC = "y" or cC = "N" or cC = "n"
                if cC = "Y" or cC = "y" then
                    if fileName <> "0" then
                        draw string (1, 291), "Would you like to save the image? (Y/N)", RGB(0,0,0)
                        draw string (1, 291), "Image saved.", RGB(0, 255, 255)
                        sleep 3000
                        end
                    end if
                    if fileName = "0" then
                        draw string (1, 291), "Would you like to save the image? (Y/N)", RGB(0,0,0)
                        draw string (1, 291), "Enter the name of the image (no extension required):", RGB(0,255,255)
                        sleep 10500
                    end if
                end if
                if cC = "N" or cC = "n" then
                    sleep 12000
                    end
                end if
                
            end if
            if cC = "R" or cC = "r" then
                redValue = redValue + 5
            end if
            if cC = "P" or cC = "p" then
                redValue = redValue - 5
            end if
            if cC = "B" or cC = "b" then
                blueValue = blueValue + 5
            end if
            if cC = "D" or cC = "d" then
                blueValue = blueValue - 5
            end if
        loop
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

By design on most/all computers, the mouse pointer is allowed to "jump" - i.e. move from one position to any other on the screen without hitting all the pixels in between. This will be regardless of the frame rate of your program. In order to fill in the gaps, you can draw a line between each point the cursor hits, and this is what Paint does.

To see the simple effect of this, change 'pset (mX, mY), ...' to 'line -(mX, mY), ...'. You will then just face the challenge of making the line start in the right position when the button is pressed.

By the way, instead of doing comparisons like (s = "a" or s = "A"), it is simpler to do (lcase(s) = "a") instead.
MSMatt
Posts: 8
Joined: May 08, 2010 20:21
Contact:

Post by MSMatt »

Thank you, counting_pine! It worked, and I also figured out a way to keep the separate lines from connecting each other.

I'll be sure to list you in the credits!
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Post by BasicCoder2 »

counting_pine wrote:By design on most/all computers, the mouse pointer is allowed to "jump" - i.e. move from one position to any other on the screen without hitting all the pixels in between.
I found this strange when I using a high speed computer. On my old 7Hz Amiga I could set the pixels as fast as I could move the mouse once I turned off the OS and programmed directly in assembler.

BC
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Post by fxm »

counting_pine wrote:You will then just face the challenge of making the line start in the right position when the button is pressed.
Simplest principle of pencil drawing:

Code: Select all

dim as integer mX, mY, mB

screen 18, 32
do
  getmouse (mX, mY, , mB)
  if mB = 1 then
    line -(mX, mY), rgb(&h80, &hc0, &hf0)
  elseif mB = 0 then
    pset (mX, mY), point(mX, mY)
  end if
loop until inkey = chr(27)
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Post by counting_pine »

BasicCoder2 wrote:I found this strange when I using a high speed computer. On my old 7Hz Amiga I could set the pixels as fast as I could move the mouse once I turned off the OS and programmed directly in assembler.

BC
Seven Hertz? You must be really good.
I think the jumping probably has more to do with the timing resolution of the communication of the mouse device. I think, historically speaking, at a few kilobaud you might struggle to physically communicate the movement data over every pixel, particularly since the mouse can move arbitrarily fast.

But I guess you don't really need any finer timing than the refresh rate of the screen. The user's not consciously selecting an exact path between two points, and if you want some interim data, you can always fake it by interpolating between known points, and that of course, is essentially what you're doing when you're drawing lines.

@fxm: oh yes, the pset-point trick. I think I mentioned it not long ago as well. Still makes me cringe a bit though..

Oh, just thought of a new hack:

Code: Select all

line -(x, y),,, 0
Passing 0 as the style parameter ensures noline is drawn. Still pretty horrible. But at least this way doesn't involve poking to the screen or parsing a string. It does have the drawback of having to redraw all the screen rows it "touches" though.
MSMatt
Posts: 8
Joined: May 08, 2010 20:21
Contact:

Post by MSMatt »

fxm wrote:
counting_pine wrote:You will then just face the challenge of making the line start in the right position when the button is pressed.
Simplest principle of pencil drawing:

Code: Select all

dim as integer mX, mY, mB

screen 18, 32
do
  getmouse (mX, mY, , mB)
  if mB = 1 then
    line -(mX, mY), rgb(&h80, &hc0, &hf0)
  elseif mB = 0 then
    pset (mX, mY), point(mX, mY)
  end if
loop until inkey = chr(27)
I did something like that on my own, but I made an image buffer, then whenever the mouse key was up, wrote to that image buffer using "line".
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Post by fxm »

counting_pine wrote:Oh, just thought of a new hack:

Code: Select all

line -(x, y),,, 0
Passing 0 as the style parameter ensures noline is drawn. Still pretty horrible. But at least this way doesn't involve poking to the screen or parsing a string. It does have the drawback of having to redraw all the screen rows it "touches" though.
Very good idea!
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Post by fxm »

fxm wrote:
counting_pine wrote:Oh, just thought of a new hack:

Code: Select all

line -(x, y),,, 0
Passing 0 as the style parameter ensures noline is drawn. Still pretty horrible. But at least this way doesn't involve poking to the screen or parsing a string. It does have the drawback of having to redraw all the screen rows it "touches" though.
Very good idea!
Current graphics cursor position setting only:
  • I add 4 other solutions.
  • The 6 solutions found, from the fastest to the slowest:
    (1) scope : dim as byte img(0 to 31) : put (x, y), img : end scope
    (2) line -(x, y), , , 0
    (3) draw string (x, y), ""
    (4) dim as integer ptr img = allocate(32) : img[0] = 0 : put (x, y), img : deallocate img
    (5) pset (x, y), point(x, y)
    (6) draw "bm" & str(x) & "," & str(y)

    Solution (1) and (4) are very ugly, but efficient!
    Speed of (6) is far behind the other 5.
Other idea?
Post Reply