Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Check if the mouse is over irregular shapes

This thread is locked; no one can reply to it. rss feed Print
Check if the mouse is over irregular shapes
shadyvillian
Member #12,426
December 2010

I'm trying to fancy up my ui in one of my programs and wanted to use other shapes than just squares and rectangles. But I'm having problems with the code crashing. Does this look like a good way to do it?

#SelectExpand
1void Framework_SelectableButton::RegisterIrregularShape() 2{ 3 IrregularShape = true; 4 vector<vector<ALLEGRO_COLOR>> Pixels(al_get_bitmap_height(UpImage), vector<ALLEGRO_COLOR>(al_get_bitmap_width(UpImage))); 5 al_lock_bitmap(UpImage, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); 6 7 for(int i = 0; i < al_get_bitmap_height(UpImage); i++) 8 { 9 for(int j = 0; j < al_get_bitmap_width(UpImage); j++) 10 { 11 Pixels[i][j] = al_get_pixel(UpImage, i, j); 12 } 13 } 14 15 al_unlock_bitmap(UpImage); 16 ImagePixels = Pixels; 17}

#SelectExpand
1void Framework_SelectableButton::IsMouseOver(int MouseX, int MouseY) 2{ 3 if(IrregularShape == false) 4 { 5 if((MouseX >= x1) && (MouseX <= x2) && (MouseY >= y1) && (MouseY <= y2)) 6 { 7 Over = true; 8 } 9 10 else 11 { 12 Over = false; 13 } 14 } 15 16 else if(IrregularShape == true) 17 { 18 if((MouseX >= x1) && (MouseX <= x2) && (MouseY >= y1) && (MouseY <= y2)) //check if the mouse is over the image at all 19 { 20 unsigned char r, g, b, alpha; 21 al_unmap_rgba(ImagePixels[MouseX-x1][MouseY-y1], &r, &g, &b, &alpha); 22 23 if(alpha == 0) 24 { 25 Over = false; 26 } 27 28 else // if the pixel that the mouse is over isnt completly transparent then over is true 29 { 30 Over = true; 31 } 32 } 33 34 else 35 { 36 Over = false; 37 } 38 } 39}

Heres

EDIT: I've attached what one of the images look like. Its pretty much looks like a quarter part of an o.

Software Engineer by day, hacker by night.

Arthur Kalliokoski
Second in Command
February 2005
avatar

It seems to me that the active area for a mouse is still rectangular even if the widget is oval or whatever. It'd be rather hard to notice this unless your OCD or something.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

jmasterx
Member #11,410
October 2009

It probably crashes because:

    for(int i = 0; i < al_get_bitmap_height(UpImage); i++)
    {
        for(int j = 0; j < al_get_bitmap_width(UpImage); j++)
        {
            Pixels[i][j] = al_get_pixel(UpImage, i, j);
        }
    }

should probably be:

    for(int j = 0; j < al_get_bitmap_height(UpImage); j++)
    {
        for(int i = 0; i < al_get_bitmap_width(UpImage); i++)
        {
            Pixels[i][j] = al_get_pixel(UpImage, i, j);
        }
    }

But really, why store every pixel?

Just translate the mouse so that it is relative to the bitmap eg: if bitmap is at 50,50 subtract 50,50 from mouse position.
Then do bounds check on your mouse so mouseX >= 0 && mouseX < width ... same for height. Then just make 1 call to al_get_pixel(mouseX,mouseY).

But if you want to do it your way, remember c++ is row major so [width][height]

shadyvillian
Member #12,426
December 2010

Yeah thats what I figured was causing the crash. I just wanted to store all the pixels because I thought that if the mouse is moved alot over the image that all the al_get_pixel calls would cause lag.

EDIT: The code seems to work fine. Its pixel perfect precision. But after I click on one button and then click on another on it crashes on al_unmap_rgba(ImagePixels[x][y], &r, &g, &b, &alpha);

EDIT2: Changing the code to this stops the crashes

            unsigned char r, g, b, alpha;
            al_unmap_rgba(al_get_pixel(UpImage, MouseX-x1, MouseY-y1), &r, &g, &b, &alpha);
            Over = true;

            if(alpha == 0) // if the pixel that the mouse is over is completly transparent then over is false
            {
                Over = false;
            }

Will locking the bitmap in this situation increase performance?(between the unmap_rgba)

Software Engineer by day, hacker by night.

jmasterx
Member #11,410
October 2009

I don't think so. I think the cost of locking it so often would outweigh the performance boost.

Trent Gamblin
Member #261
April 2000
avatar

Locking would probably help unless you're only doing a few pixels. Just make sure to only lock the region you need if it's not the whole bitmap. Sorry, I didn't really read your code so I don't know what's best for you, just that locking helps if you're accessing more than a few pixels and they're all adjacent.

shadyvillian
Member #12,426
December 2010

Well al_get_pixel is called everytime an allegro_event_mouse_axes event occurs and the mouse is over the bitmap.

Software Engineer by day, hacker by night.

Trent Gamblin
Member #261
April 2000
avatar

If it's just called once then it doesn't matter if you lock the bitmap.

The way it works is, al_get_pixel will lock a 1x1 pixel region of the bitmap for you if the bitmap isn't locked already. Then it will unlock it.

If it is already locked, it just reads from the lock data and doesn't unlock the bitmap. If you get a pixel outside of the locked region it will return 0s for the pixel data.

So for 1 pixel the behaviour is identical. For more than 1 pixel you can avoid locking operatings in al_get_pixel by locking yourself which will be faster, because locking is slow.

Go to: