Image Manipulation
Image Manipulation
Hey
First I will explain what I want to do. I have multiple cursor images that will change and animate depending on what is under the cursor. I need the GUI image to move around the screen and be set visible and invisible at will.
Correct me if I am wrong, but as far as I know there is no way to move GUI images once they have been created and although it is possible to create an image from the driver and attach it to a moving rectangle it is not possible to then access this image in any way ( setting visible mainly ).
So I am now trying to modify the engine a little to include a setPosition function. What I tried setting was AbsoluteRectangle with this function, and although it does move the image, it crops anything that passes outside the original clipping rectangle.
My question is, how is it possible to add this functionality into the engine? I figure there has to be another rect that stores it's clipping rectangle and removes anything outside it. Anyone got any idea's?
First I will explain what I want to do. I have multiple cursor images that will change and animate depending on what is under the cursor. I need the GUI image to move around the screen and be set visible and invisible at will.
Correct me if I am wrong, but as far as I know there is no way to move GUI images once they have been created and although it is possible to create an image from the driver and attach it to a moving rectangle it is not possible to then access this image in any way ( setting visible mainly ).
So I am now trying to modify the engine a little to include a setPosition function. What I tried setting was AbsoluteRectangle with this function, and although it does move the image, it crops anything that passes outside the original clipping rectangle.
My question is, how is it possible to add this functionality into the engine? I figure there has to be another rect that stores it's clipping rectangle and removes anything outside it. Anyone got any idea's?
I have now figured it out, there is an AbsoluteClippingRect which you also need to change in order to move it. Here are the code changes:
In IGUIImage.h:
Add inside the public declaration:
In CGUIImage.h:
Add inside the public declaration:
In CGUIImage.cpp:
Add:
In IGUIImage.h:
Add inside the public declaration:
Code: Select all
//! sets the absolute rectangle position
virtual void setPosition(core::rect<s32> rect) = 0;
In CGUIImage.h:
Add inside the public declaration:
Code: Select all
//! sets the absolute rectangle position
virtual void setPosition(core::rect<s32> rect);
In CGUIImage.cpp:
Add:
Code: Select all
void CGUIImage::setPosition(core::rect<s32> rect)
{
AbsoluteRect = rect;
AbsoluteClippingRect = AbsoluteRect;
}Well, there is a setRelativePosition() function (from IGUIElement). It does exacly what you want (exept expecting relative coordinates which doesn't make any difference if it has no parent). Plus it takes the parent clipping into account. Plus it updates also the children.
If you really would want to add this it would probably be good to:
1. Name it "setAbsolutePostion()"
2. Add it to IGUIElement
3. make the parameters "const core::rect<s32>&"
4. take the parent clipping into account
5. update also the children
If you really would want to add this it would probably be good to:
1. Name it "setAbsolutePostion()"
2. Add it to IGUIElement
3. make the parameters "const core::rect<s32>&"
4. take the parent clipping into account
5. update also the children
I took that in to account and changed the way it works. It now works exactly like the relative position function but changes the absolute coordinate into relative coordinates and updates the children in the same way. It seems OK with a child element, behaves correctly as far as I can see.
In IGUIElement.h
In IGUIElement.h
Code: Select all
//! Sets the absolute rectangle of this element.
void setAbsolutePosition(const core::rect<s32>& r)
{
RelativeRect.UpperLeftCorner += irr::core::position2d<s32>(
r.UpperLeftCorner.X - AbsoluteRect.UpperLeftCorner.X,
r.UpperLeftCorner.Y - AbsoluteRect.UpperLeftCorner.Y);
RelativeRect.LowerRightCorner += irr::core::position2d<s32>(
r.LowerRightCorner.X - AbsoluteRect.LowerRightCorner.X,
r.LowerRightCorner.Y - AbsoluteRect.LowerRightCorner.Y);
updateAbsolutePosition();
}Nope, sorry... nice try though 
1. The '+=' doesn't work...
2. When calculating the RelativeRect.LowerRightCorner you also need to use the AbsoluteRect.UpperLeftCorner
So correct would be:
But then you could just say:
But unfortunately there is no operator- (and also operator-=) in the rect class... might be a reason to add it though!

1. The '+=' doesn't work...
2. When calculating the RelativeRect.LowerRightCorner you also need to use the AbsoluteRect.UpperLeftCorner
So correct would be:
Code: Select all
void setAbsolutePosition(const core::rect<s32>& r)
{
RelativeRect.UpperLeftCorner = irr::core::position2d<s32>(
r.UpperLeftCorner.X - AbsoluteRect.UpperLeftCorner.X,
r.UpperLeftCorner.Y - AbsoluteRect.UpperLeftCorner.Y);
RelativeRect.LowerRightCorner = irr::core::position2d<s32>(
r.LowerRightCorner.X - AbsoluteRect.UpperLeftCorner.X,
r.LowerRightCorner.Y - AbsoluteRect.UpperLeftCorner.Y);
}
Code: Select all
void setAbsolutePosition(const core::rect<s32>& r)
{
RelativeRect = r - AbsoluteRect.UpperLeftCorner;
updateAbsolutePosition();
}
Works fine for me, I'm using it now. Adding two position2d's together is definatly possible, I know because in the IGUIElement constructor the same method is used to set the relative position from the parent. Here:
Your two methods do seem to work but I haven't been able to find any problems with the code I posted before. What would I have to do to make my version of the function behave incorrectly?
Code: Select all
if (Parent)
{
AbsoluteRect += Parent->getAbsolutePosition().UpperLeftCorner;
AbsoluteClippingRect = AbsoluteRect;
AbsoluteClippingRect.clipAgainst(Parent->getAbsoluteClipping());
}It might work for you, but it doesn't mean that it's correct. There might be other situations where it's more obvious and where it will produce problems.
Then, again, you're using '+=' on the RelativeRect. Meaning you're not setting but altering it. So, calling setAbsolutePosition twice or more in a row is gonna mess up the rect more and more.
Example: Imagine a gui element 16x16 at 100,100. I has absolute rect(100,100,116,116). Now if you use your method to position it to 200,200 with setAbsolutePosition(200,200,216,216) then the result of the RelativeRect will be (100,100,100,100). But you would expect (100,100,116,116) which is also what you would get with my example.
Now call setAbsolutePosition(200,200,216,216) twice
With my method you get still (100,100,116,116). Which is no surprise. But yours will produce (200,200,200,200)...
Can you follow this? Test it!
Also In your case it would be most effective to use the present setRelativePosition(). because with this kind of implementation of setAbsolutePosition() it is a waste because youre converting stuff from absolute to relative and back to absolute...
Look closely! It's adding one rect with one position2d (in that order). This - internaly - adds the position2d to both the upplerLeft and the lowerRight of the rect. This is what I was doing as well in the first code two posts ago.Tyn wrote: I know because in the IGUIElement constructor the same method is used to set the relative position from the parent.
Then, again, you're using '+=' on the RelativeRect. Meaning you're not setting but altering it. So, calling setAbsolutePosition twice or more in a row is gonna mess up the rect more and more.
Example: Imagine a gui element 16x16 at 100,100. I has absolute rect(100,100,116,116). Now if you use your method to position it to 200,200 with setAbsolutePosition(200,200,216,216) then the result of the RelativeRect will be (100,100,100,100). But you would expect (100,100,116,116) which is also what you would get with my example.
Now call setAbsolutePosition(200,200,216,216) twice
With my method you get still (100,100,116,116). Which is no surprise. But yours will produce (200,200,200,200)...
Can you follow this? Test it!
Also In your case it would be most effective to use the present setRelativePosition(). because with this kind of implementation of setAbsolutePosition() it is a waste because youre converting stuff from absolute to relative and back to absolute...
Actually not quite correct. One aspect is wrong... You have to substract not the AbsoluteRect of the element, but the one of its parent... duh.
So logically it should be this:
This doesn't change my points! (But the results of my examples, sorry...)
So logically it should be this:
Code: Select all
void setAbsolutePosition(const core::rect<s32>& r)
{
core::rect<s32> parentAbsolute(0,0,0,0);
if (Parent)
parentAbsolute = Parent->AbsoluteRect;
RelativeRect = r - parentAbsoluteRect.UpperLeftCorner;
updateAbsolutePosition();
}
It's effective for me because it put the cursor position straight into it and can see and change the position of the image in relation to this. I could do this with absolute but I would rather calculations are done behind the scene's wherever possible as it is easier to read the code then.
I can't see where you are getting your figures from. If I called my function the first time then it works out the difference from my absolute position and the desired position, adds this to the current relative position and then updates everything.
If I then called the same function with the same figures then the absolute position would have already been updated ( at the end of the function ) and so the difference between the requested and current position would be nothing therefore the position wouldn't be changed. It would not simply add the same figure to the position, the position is always correct in every test I have done and I can't see where this would not happen. I also have a child node and it also works fine with this.
I can't see where you are getting your figures from. If I called my function the first time then it works out the difference from my absolute position and the desired position, adds this to the current relative position and then updates everything.
If I then called the same function with the same figures then the absolute position would have already been updated ( at the end of the function ) and so the difference between the requested and current position would be nothing therefore the position wouldn't be changed. It would not simply add the same figure to the position, the position is always correct in every test I have done and I can't see where this would not happen. I also have a child node and it also works fine with this.
Tyn, you are right! I apologize! But I am also right! :P
It's two different approaches that both work. I have made some more tests under more appropriate conditions and all parameters look ok with your code (with mine too).
Before I was testing not within ISceneNode so I had weird results, dunno... Sorry again.
But I still think using the setRelativePosition() will produce less overhead. If your images have no parent (they might have children, doesn't matter) then relative = absolute and you can omit the calculations in setAbsoluteRect().
It's two different approaches that both work. I have made some more tests under more appropriate conditions and all parameters look ok with your code (with mine too).
Before I was testing not within ISceneNode so I had weird results, dunno... Sorry again.
But I still think using the setRelativePosition() will produce less overhead. If your images have no parent (they might have children, doesn't matter) then relative = absolute and you can omit the calculations in setAbsoluteRect().
I know what you are saying, yeah both ways work fine. I do think that being able to set a position knowing that the position is absolute whether connected to a node or not is useful, although using them for this use may well provide a little overhead ( can't imagine the math causing too much damage to speed tho ).
You had me worried for a while, I thought my math was completely out the window
You had me worried for a while, I thought my math was completely out the window