Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Suggestions ➜ Miniwindow image rotation

Miniwindow image rotation

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1  2 3  

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #15 on Thu 26 Aug 2010 04:09 PM (UTC)

Amended on Thu 26 Aug 2010 04:11 PM (UTC) by David Haley

Message
Twisol: I was referring to the fact that you were given a solution but deemed it "overkill". I was asking what about it was unacceptable to you.

Regarding matrices, I agree that transformations should not be stored on the images themselves. If you look at OpenGL, for instance, that's not how they do it either. You set up transformations, you draw some stuff, you might add more transformations, draw more stuff, etc. But you don't attach a transformation to an image, and then draw the image without knowing about its transformation.

If you need images to store their own transformation information, such that when rendered they apply it before drawing, then reverse it for subsequent operations, then I would suggest making that a feature of your API, with a sprite object of some sort that stores its own transformation for when it is rendered.

What you said about composing transformations does not appear to be relevant to storing transformations on images -- in fact, as you said, OpenGL composes transformations and this is useful, but it doesn't do it by storing them on images!

If anything, the conclusion of your argument is that there should be an independent transform function that you use to set up a drawing context, not that there should be transformations stored on images.



I don't really understand the comments about not seeing the resulting image. If you transformed it such that it doesn't appear in the view anymore, don't you expect to not see it? Isn't that exactly the desired behavior?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #16 on Thu 26 Aug 2010 04:37 PM (UTC)

Amended on Thu 26 Aug 2010 06:13 PM (UTC) by Twisol

Message
David Haley said:
Twisol: I was referring to the fact that you were given a solution but deemed it "overkill". I was asking what about it was unacceptable to you.

Sprite maps work in some instances. Only effectively for static data. I don't know why I said "overkill", I think I was thinking of the effort involved to duplicate the image and rotate it, and the size of the image involved. If you have a very long base image, managing the sprite map would be verrry interesting.

David Haley said:
Regarding matrices, I agree that transformations should not be stored on the images themselves. If you look at OpenGL, for instance, that's not how they do it either. You set up transformations, you draw some stuff, you might add more transformations, draw more stuff, etc. But you don't attach a transformation to an image, and then draw the image without knowing about its transformation.

But you do apply a transformation separately from drawing. With OpenGL, it's stored as the transformation matrix of the current context. I -would- like to have a transformation matrix stored with the window itself, but I'm just a little worried about possible confusion. It feels like it could be too easy to think the window itself is stretched/squashed/rotated, rather than the content. ([EDIT] And also easy to think it affects stuff drawn already.)

Hmm... Yeah, storing the matrix with the window would be better.

David Haley said:
If you need images to store their own transformation information, such that when rendered they apply it before drawing, then reverse it for subsequent operations, then I would suggest making that a feature of your API, with a sprite object of some sort that stores its own transformation for when it is rendered.

Just to be clear here, you're talking about a sprite map image, where multiple "frames" of a sprite are stored in the same file?

David Haley said:
What you said about composing transformations does not appear to be relevant to storing transformations on images -- in fact, as you said, OpenGL composes transformations and this is useful, but it doesn't do it by storing them on images!

I'm not sure why it's not relevant. The same thing happens; the difference is that a different matrix is applied to each image. Now though, I do agree it's better stored with the miniwindow. I realized there would be an annoying problem passing around Images with my API, because when it came time to draw it, I'd have to load the image into the target window and reconstruct the matrix somehow (probably through a hackish WindowImageInfo call). Applying transformations to the window's transformation matrix just works.

David Haley said:
If anything, the conclusion of your argument is that there should be an independent transform function that you use to set up a drawing context, not that there should be transformations stored on images.

I figure that each miniwindow would effectively be its own context. I'm not sure when it would be useful to have multiple contexts for the same miniwindow?


David Haley said:
I don't really understand the comments about not seeing the resulting image. If you transformed it such that it doesn't appear in the view anymore, don't you expect to not see it? Isn't that exactly the desired behavior?

I can't remember what I said that you're referring to, a quote would be appreciated. But I think(?) I was talking about how the transformation stored with an image isn't applied until the image is actually drawn. Otherwise, I don't know, because I agree with you.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #17 on Thu 26 Aug 2010 06:19 PM (UTC)

Amended on Thu 26 Aug 2010 06:22 PM (UTC) by Twisol

Message
Twisol said:
David Haley said:
If anything, the conclusion of your argument is that there should be an independent transform function that you use to set up a drawing context, not that there should be transformations stored on images.

I figure that each miniwindow would effectively be its own context. I'm not sure when it would be useful to have multiple contexts for the same miniwindow?

Actually, now that I think about it, that would be really useful. One of the things I'm already doing in my API is this:

w = Window.new(50, 50)

c = Context.new(w)
c.Pen("blue", "solid", 1)

c.MoveTo(25, 25)
c.DrawPie(20, 25, -- xradius, yradius
    90, 0) -- angle of slice, rotation of the whole pie

w.Show()


I'm basically separating the window drawing/content from the window's presence, and supporting multiple contexts. And I realized, if each window had just the one transformation context, I'm not sure how I could do this cleanly.

Funny how hypocritical that quote was. I said I don't see where multiple contexts would be useful, yet here I'd already done it...

[EDIT] Hah, and I realized I could implement MoveTo() using affine transforms too. This would actually be really, really clean using separate contexts.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #18 on Thu 26 Aug 2010 07:15 PM (UTC)
Message
Quote:
And I realized, if each window had just the one transformation context, I'm not sure how I could do this cleanly.

It seems that your idea of doing something cleanly is that other people do it for you. :-)

It's easy to do this cleanly: just keep track of the transformations that have been applied, and do the math on your end to pop or push transformations.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #19 on Thu 26 Aug 2010 07:24 PM (UTC)

Amended on Thu 26 Aug 2010 07:25 PM (UTC) by Twisol

Message
David Haley said:
Quote:
And I realized, if each window had just the one transformation context, I'm not sure how I could do this cleanly.

It seems that your idea of doing something cleanly is that other people do it for you. :-)

It's easy to do this cleanly: just keep track of the transformations that have been applied, and do the math on your end to pop or push transformations.

Whatever form the new function(s) take, I can deal with it. But I'd rather get as many issues on the table and out of the way as possible before the API is finalized, thanks. This is a discussion, after all. I'm not making any demands.

Oh, and we're already getting way more than I expected originally. We've gone from simple rotations to full-on affine transformations. Obviously, solutions I considered for rotations may not be completely applicable to managing matrices. But that is the point of a discussion: to come up with solutions and work out the kinks.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #20 on Thu 26 Aug 2010 08:41 PM (UTC)
Message
Come up with solutions, yes, but to which problems?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #21 on Thu 26 Aug 2010 09:29 PM (UTC)
Message
Twisol said:

At any rate, I still think orthogonality of an API is a really good thing to shoot for.


If we are going to shoot for it, we better know what it is...

http://en.wikipedia.org/wiki/Orthogonality

http://en.wiktionary.org/wiki/orthogonal


I think you are probably using the meaning:


4. (software engineering) Able to be treated separately.

The content of the message should be orthogonal to the means of its delivery.


And I presume in the current context you are meaning that it would be nice if you could rotate/scale/shear everything, not just an image, even though you initially requested "a way to rotate an image as you draw it to another window."

The trouble is, that although doing what you initially asked for was quite simple, due to the existence of a transformation routine in the GDI library, making it "just work" for all the miniwindow functions is somewhat harder. One of the main reasons is that a lot of it (like blending images) works directly on the underlying pixel data (the R, G, B codes as bytes), as for example here:


#define Blend_It(Op) \
   do \
      if (Opacity < 1.0) \
        for (i = 0; i < count; i++) \
          pB [i]     = Blend_Opacity (pA [i], pB [i], Op, Opacity);\
      else\
        for (i = 0; i < count; i ++)\
          pB [i]      = Op (pA [i], pB [i]);\
   while (false)


Now to make that apply the transformations of the original x and y to the new x and y, inside this loop which is applying a function to each byte, could not only be complex to code, but slow to run.

Now it would be "nice" if it was all totally consistent, but I think we are shooting at "hey it would be nice if everything was orthogonal" just a nice design objective, rather than with any concrete example in mind for its use.

With its current implementation (and I will be testing today if it works with at least the on/off transparency) then you can make most of the rest of it work just by making a temporary copy. For example, instead of blurring and rotating at the same time, you could rotate first, and then blur.

Twisol said:

You can compose multiple transformations together by multiplying the matrices, so theoretically you could apply a scaling operation in one part of the code, then a rotational operation elsewhere.


Subject to testing, I think a single operation would achieve this much, because by doing something like reversing the sign (eg. -cosine rather than cosine) you could reflect and rotate at the same time.

After all, multiplying matrices is effectively accumulating various operations, and in OpenGL the final transformation matrix would be the product of individual transformations.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #22 on Fri 27 Aug 2010 02:51 AM (UTC)

Amended on Fri 27 Aug 2010 02:53 AM (UTC) by Twisol

Message
Nick Gammon said:
Now to make that apply the transformations of the original x and y to the new x and y, inside this loop which is applying a function to each byte, could not only be complex to code, but slow to run.

It would add an extra calculation per point in that case, yes... In the case of WindowBlendImage, what if you drew the image to a temporary bitmap first, with the target window's transformation matrix applied, and then use the newly transformed image to blend with the target window?

WindowFilter probably isn't a big deal: it isn't drawing objects per se, it's just manipulating already-drawn pixels.

Nick Gammon said:
Now it would be "nice" if it was all totally consistent, but I think we are shooting at "hey it would be nice if everything was orthogonal" just a nice design objective, rather than with any concrete example in mind for its use.

If we're just talking about pushing features out the door - the "as long as it works" method - sure, go ahead. But orthogonality makes it both easier to use and easier to maintain.

I found an interesting page on the orthogonality of a page here: http://www.faqs.org/docs/artu/ch04s02.html - Here's a quote that caught my eye:

Quote:
[...] As they point out, orthogonality reduces test and development time, because it's easier to verify code that neither causes side effects nor depends on side effects from other code - there are fewer combinations to test. If it breaks, orthogonal code is more easily replaced without disturbance to the rest of the system. Finally, orthogonal code is easier to document and reuse.

The concept of refactoring, which first emerged as an explicit idea from the 'Extreme Programming' school, is closely related to orthogonality. To refactor code is to change its structure and organization without changing its observable behavior. [...]


Nick Gammon said:
With its current implementation (and I will be testing today if it works with at least the on/off transparency) then you can make most of the rest of it work just by making a temporary copy. For example, instead of blurring and rotating at the same time, you could rotate first, and then blur.

By using intermediate renderings? When you can multiply matrices together and get a unified matrix that does both at once? That's one of the lovely things I saw that ModifyWorldTransform() does (as well as allow you to reset to the identity matrix).

Nick Gammon said:
Twisol said:

You can compose multiple transformations together by multiplying the matrices, so theoretically you could apply a scaling operation in one part of the code, then a rotational operation elsewhere.

Subject to testing, I think a single operation would achieve this much, because by doing something like reversing the sign (eg. -cosine rather than cosine) you could reflect and rotate at the same time.

After all, multiplying matrices is effectively accumulating various operations, and in OpenGL the final transformation matrix would be the product of individual transformations.

That's what I mean. One part of the code can multiply in one matrix, to effect a rotation, and another part can add some scaling, and then somewhere else it can be drawn.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #23 on Fri 27 Aug 2010 03:00 AM (UTC)
Message
Template:post=10527 Please see the forum thread: http://gammon.com.au/forum/?id=10527.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #24 on Fri 27 Aug 2010 03:01 AM (UTC)
Message
Twisol said:

In the case of WindowBlendImage, what if you drew the image to a temporary bitmap first, with the target window's transformation matrix applied, and then use the newly transformed image to blend with the target window?


Ah, no. You would blend with the wrong (untranslated) pixels.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #25 on Fri 27 Aug 2010 03:04 AM (UTC)

Amended on Fri 27 Aug 2010 03:07 AM (UTC) by Twisol

Message
Nick Gammon said:

(post=10527)


It's anything but orthogonal. I grant that, yes, it's exactly what I originally asked for. But if you agree that something like the below would be better - and after reading what I mentioned about orthogonality - then I would be glad to implement it for you, subject to peer review of course.

My preferred API would be:

WindowAffine(window, mode, m11, m12, m21, m22, dx, dy)
WindowAffineLoadIdentity(window)


where all parameters are self-explanatory, except 'mode' which is:

0 - right-multiply
1 - left-multiply


EDIT: And associated WindowInfo selectors.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #26 on Fri 27 Aug 2010 03:11 AM (UTC)

Amended on Fri 27 Aug 2010 03:12 AM (UTC) by Twisol

Message
Nick Gammon said:

Twisol said:

In the case of WindowBlendImage, what if you drew the image to a temporary bitmap first, with the target window's transformation matrix applied, and then use the newly transformed image to blend with the target window?

Ah, no. You would blend with the wrong (untranslated) pixels.

Huh. Could you please explain that for me? I thought that by translating the image to a scratch window, then blending with the target window, it would have worked.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #27 on Fri 27 Aug 2010 03:30 AM (UTC)
Message
The scratch window would be rotated. The target window (which you blend into) would not be rotated. Thus you are blending the wrong pixels.

Possibly you might rotate the target too, into another scratch window, rotate the source into a scratch window, blend the rotated versions, and then somehow copy the results back (but only the exact pixels that are affected) into the original target window.

Apart from wanting orthogonality, I can't see a huge use for this.

Quote:

If it breaks, orthogonal code is more easily replaced without disturbance to the rest of the system. Finally, orthogonal code is easier to document and reuse.


But the underlying code would not be orthogonal. To do what you suggest is simply moving the problem from where you see it, to inside MUSHclient. You still have the quite probably possibility that some combination of blending, rotation, translation etc. will fail in some unexpected way.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #28 on Fri 27 Aug 2010 03:36 AM (UTC)
Message
Nick Gammon said:
The scratch window would be rotated. The target window (which you blend into) would not be rotated. Thus you are blending the wrong pixels.

Possibly you might rotate the target too, into another scratch window, rotate the source into a scratch window, blend the rotated versions, and then somehow copy the results back (but only the exact pixels that are affected) into the original target window.

But... huh, I don't see any reason why you'd want the target to be rotated. As far as I can see, you'd want the image, say, rotated, and then blended with whatever it matches up to now.

Nick Gammon said:
Quote:

If it breaks, orthogonal code is more easily replaced without disturbance to the rest of the system. Finally, orthogonal code is easier to document and reuse.


But the underlying code would not be orthogonal. To do what you suggest is simply moving the problem from where you see it, to inside MUSHclient. You still have the quite probably possibility that some combination of blending, rotation, translation etc. will fail in some unexpected way.

Still, the problem is isolated to the drawing functions themselves, because we know the matrix functions work.

And yes, I'd rather the client handle it, rather than force the developer to use a limiting API.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #29 on Fri 27 Aug 2010 04:30 AM (UTC)

Amended on Fri 27 Aug 2010 04:31 AM (UTC) by Nick Gammon

Message
Twisol said:

But... huh, I don't see any reason why you'd want the target to be rotated. As far as I can see, you'd want the image, say, rotated, and then blended with whatever it matches up to now.


Oh yeah, good point. But still code like this becomes a lot more complex:


for (i = 0; i < count; i ++)
          pB [i]      = Op (pA [i], pB [i]);


In this case I have two pointers, both to the bitmaps which I think have been normalized to the same size. But now "i" will be jumping all over the place for the source at least, and in some cases at least may well be off-screen. So you then have to define what it means to take (say) the average of two pixels where one doesn't exist because it has been rotated off the bitmap.

Quote:

And yes, I'd rather the client handle it, rather than force the developer to use a limiting API.


Show me a concrete example involving MUD games (eg, player inventory, battle gauges) where this is a "limiting API". Not just for you to write a generic graphical API. Like I said before, I'm not trying to rewrite Photoshop.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


81,347 views.

This is page 2, subject is 3 pages long:  [Previous page]  1  2 3  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.