Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Patch to smooth KDE minimize/unminimize animation
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Unsupported Software
View previous topic :: View next topic  
Author Message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Sun Aug 08, 2010 8:11 am    Post subject: Patch to smooth KDE minimize/unminimize animation Reply with quote

Edit - for updated patch, see my post below at Wed Dec 07, 2011 10:38 pm.

Hi. I've made the following patch which seems to make the KDE4 minimize/unminimize animations a little smoother - i.e., less "linear" - when the windows are unminimized, the animation slows down as the windows approach their target size. I remember compiz doing this, and it seemed overall smoother.

Code:
--- a/kwin/lib/kwineffects.h.old   2010-08-07 22:56:43.000000000 -0700
+++ b/kwin/lib/kwineffects.h   2010-08-07 23:01:02.000000000 -0700
@@ -460,6 +461,7 @@
          **/
         static double interpolate(double x, double y, double a)
             {
+            a = a * a;
             return x * (1 - a) + y * a;
             }
         /** Helper to set WindowPaintData and QRegion to necessary transformations so that


I'm not a programmer, so this patch may very well break stuff. So far I've had no problems.

The patch can be tweaked, as well, by altering the number of times 'a' is multiplied by itself.

If someone can work out the math to make this even smoother, that would be cool.

The patch applies against kwin of the 4.4.5 variety. You would need to add the following single line (without the '+') to /usr/portage/kde-base/kwin/kwin-4.4.5.ebuild:

Code:
PATCHES=(
   "${FILESDIR}/${PN}-4.4.2-xinerama_cmake_automagic.patch"
+   "${FILESDIR}/kwineffects.h.patch"
)


To be consistent the patch would be saved as kwineffects.h.patch in the /usr/portage/kde-base/kwin/files directory.

And then, of course,
Code:
ebuild kwin-4.4.5.ebuild manifest


Last edited by piwacet on Thu Dec 08, 2011 3:40 am; edited 2 times in total
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Mon Aug 09, 2010 9:42 pm    Post subject: Reply with quote

Reading the comments of kwineffects.h, I am not sure if this function is what you would want to patch. In order to make the window animation smoother, what you would want to do is modify the code to scale the area according to some function. Ideally, this probably should be a linear function to bring the area from some upper limit to some lower limit within the allowed time for the effect, but I imagine that you could use a non-linear function as well.

If time u is the start of the effect, time v is the end of the effect and t is the current time, then the area should scale according to the function f(t) = ((v - t) / (v - u))^k. Consequently, each dimension of the window will need to be scaled according g(t) = (f(t))^(1/2) or g(t) = ((v - t) / (v - u))^(k/2). This is where k is a tuning variable that can be used to get a linear effect when k = 1, an effect where the transition is slow when the window is large and quick when the window is small when k < 1 and an effect where the transition is quick when the window is small and slow when the window is large when k > 1.

Thinking about it some more, the right place to make this kind of change would be where the value of a is generated, because that is what you would want to replace with the equation g(t) that I provided above. How did you come upon the function that you modified in your patch? kwin is such a large piece of software that I am not sure where I would begin if I wanted to make a change, much less find a spot related to the area like it appears that you have done here.
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Mon Aug 09, 2010 10:37 pm    Post subject: Reply with quote

I found the spot where interpolate() is being called. It is in ./kwin/effects/minimizeanimation/minimizeanimation.cpp. Although I am not quite certain where it is being computed, it appears that a = (v - t) / (v - u). Unfortunately, it appears that each time kwin scales the window, it scales it from the current size, rather than the original size. Unless the value of a is not what I think it is and is being specially changed to counteract this effect, the window scaling will be smooth or laggy depending on the behavior of the kernel scheduler, which in my opinion is a bad way of doing things. To make matters worse, I am not sure where or if the original size of the window is stored and without either that information or how what the scaling factor was used previously on the window coordinates, doing proper window scaling seems impossible. Perhaps this is why KDE's minimization effect always seemed strange to me.

Anyway, I probably could fix this myself if I studied kwin's code more closely, but I think it would be best to file a bug report with upstream. I already described in my previous post how the window scaling should be done. It would probably best if upstream implemented it, because then the k constant could be soft-coded to give the user the ability to tune over how the window scaling works from KDE's control panel. I have my own things to do, so I will look into filing a bug report about this later, although it would probably be better if the original poster filed it, because he is the one who pointed out this issue.
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Tue Aug 10, 2010 3:07 am    Post subject: Reply with quote

Thanks so much for looking at this. For anyone who is interested, here are the relevant chunks of code, I believe this is current HEAD (not 4.4.5):

The interpolate() function, in kwineffects.h, at line 513:

http://lxr.kde.org/source/KDE/kdebase/workspace/kwin/lib/kwineffects.h#513

Code:
513         static double interpolate(double x, double y, double a)
514             {
515             return x * (1 - a) + y * a;
516             }


And the place where this function is called, in minimizeanimation.cpp, at/after line 81:

http://lxr.kde.org/source/KDE/kdebase/workspace/kwin/effects/minimizeanimation/minimizeanimation.cpp#81

Code:
81 void MinimizeAnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
82     {
83     QHash< EffectWindow*, TimeLine >::const_iterator entry = mTimeLineWindows.constFind(w);
84     if( entry != mTimeLineWindows.constEnd() )
85     {
86         // 0 = not minimized, 1 = fully minimized
87         double progress = entry->value();
88
89         QRect geo = w->geometry();
90         QRect icon = w->iconGeometry();
91         // If there's no icon geometry, minimize to the center of the screen
92         if( !icon.isValid() )
93             icon = QRect( displayWidth() / 2, displayHeight() / 2, 0, 0 );
94
95         data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress);
96         data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress);
97         data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress);
98         data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress);
99         data.opacity *= 0.1 + (1-progress)*0.9;
100     }
101
102     // Call the next effect.
103     effects->paintWindow( w, mask, region, data );
104     }


My understanding of the interpolate() function is that it takes 3 arguments, x, y, and a, and returns a value between x and y. 'a' is a value from 0 - 1 and represents how far between x and y the return value will be; if a=0 it returns x, if a=1 it returns y, if a=0.5 it returns a value half way between x and y, etc. It seems that 'a' would be the same as 'a = (v - t) / (v - u)' as you have said - based on the linearity of the minimize/unminimize animations as I watch them happen.

In minimizeanimation.cpp, the variable 'progess' is passed to the interpolate() function as the value 'a'. Therefore, 'progress' seems to represent how far along the animation is progressing.

What I observe is that the minimize/unminimize animation is very 'linear.' If a minimized window is unminimized, it expands on the screen at a constant speed, until it appears to stop abruptly when it reaches its target size - it's as if the expanding window "bumps into" the edge of the screen and has to stop expanding. I liked the way I remember compiz doing this - more "parabolic" - i.e., as the window expanded, the animation speed would slow as the window reached it's target size, this seemed smoother.

That's the reason I made the patch to square the variable 'a'. Since 'a' is a number that appears to range from 0 to 1, the square of 'a' will be more parabolic, and still behave correctly for a value of 0 or 1 (still equal 0 or 1). Of course, this may break any other stuff that calls the interpolate() function, if something else does.

I would be much happier with a more proper implementation, ideally with even better math to make the animation even more smooth than squaring 'a' does. Unfortunately I don't understand the code in minimizeanimation.cpp well enough to do this. One thought would be to patch this portion of minimizeanimation.cpp so that it calls an entirely new function to generate the interpolate() value with the mathematical behavior that I would like; this would keep the original interpolate() function intact for any other part of the code that may call it. Perhaps I'll keep plucking away.

Again, thanks so much for taking the time to look at this.
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Thu Aug 26, 2010 2:25 am    Post subject: Reply with quote

piwacet, I did not see your response to this thread until today. I just reread my post and what I said regarding k != 1 makes no sense. When k < 1, the effect will be slow when the window is large and quick when the window is small. When k > 1, the effect will be slow when the window is small and quick when the window is large. With what you are saying, I think you would want k > 1 in the equations I posted above.

Anyway, your patch will likely affect much more than just the minimization animation. It would probably be a good idea for you to inline your changes into the minimizeanimation.cpp file until someone comes up with a better solution. I am somewhat hesitant to do much with this because I do not know if this is still a problem in KDE 4.5.0. Did you ever file a bug report regarding this with upstream?
Back to top
View user's profile Send private message
Akkara
Bodhisattva
Bodhisattva


Joined: 28 Mar 2006
Posts: 6702
Location: &akkara

PostPosted: Thu Aug 26, 2010 3:08 am    Post subject: Reply with quote

Just to toss some ideas into the mix:

Here's some other functions that take a parameter from 0..1 that have zero slope at one end or the other (or both):

Zero slope at the a == 0 end:
  • a*a /* this is the formula suggested above */
  • 1 - cos(Pi/2 * a)

Zero slope at the a == 1 end:
  • a * (2 - a)
  • sin(Pi/2 * a)

Zero slope at both ends:
  • a * a * (3 - 2*a)
  • a = sin(Pi/2 * a); a = a * a; /* this one is so close to the one just above it's hardly worthwhile to use */

Also, sometimes things look nicer visually when they follow a power law. Use one of the formulas above and then follow it up with:
  • a = (pow(2,a) - 1) / (2 - 1);
See if you like that better. Change the 2 to other numbers to push the effect faster toward one end or the other. If the fast end is not at the end it needs to be, use:
  • a = 1 - a; a = (pow(2,a) - 1) / (2 - 1); a = 1 - a;
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Thu Aug 26, 2010 4:05 am    Post subject: Reply with quote

The source has two issues in it at the moment. One is that the original window size is not saved between repaints, so each time it repaints, a new window size is calculated from the previous size, which is not the original size. That is a problem because it prevents the animation from behaving according to a specific mathematical formula and gives the animation a bit of randomness that in most cases will make the animation look worse than it should look. It also means that this effect is done slightly differently every time it is executed. The second is that the window animation does not appear to be mathematically defined, but doing that is impossible unless the animation obeys the formulae employed.

I have produced a patch that addresses the first issue. I would have had it address the second issue as well, but when I tried to change the code, I could not understand how the existing code functioned unless data.xScale and data.yScale varied between 0 and 1, which suggested to me that the code determining the calculation of the window's dimensions was elsewhere. While I can likely work around that, that would require a bit of trial and error on my part to verify my assumptions and it is late, so I am only patching the first issue.

Here is the patch for anyone interested:

http://paste.pocoo.org/show/254569/

The first issue I described at the top of this post meant that the animation had an annoying inconsistent jerkiness to it. This patch fixes that. At the same time, it does not address the original poster's issue, which is what I outlined as the second issue at the top of this post.

Akkara, although I have not checked your math, functions that have zero slopes at both ends are ideal for this kind of animation. I will look into implementing such a function tomorrow provided that I find time.
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Sat Aug 28, 2010 12:12 am    Post subject: Reply with quote

I spent several hours today trying to modify the behavior of this effect and my theory as to what various variables meant was incorrect. While I now think that it is possible that my above patch does nothing, I am not able to say that for certain because the documentation on the return value of KWin::EffectWindow::geometry() is nonexistent. The return value could be the geometry before the effect or the geometry during the effect and it is not clear to me which of the two it is. I knew no quick and dirty way of saving messages to a log file, so I tried doing things without logging variable values and with what I know now, that is the first thing I should have done.

I filed a bug report with upstream regarding the documentation issues I encountered:

https://bugs.kde.org/show_bug.cgi?id=249288

I am still waiting for piwacet to file a bug report with upstream regarding the effect, because this is his complaint.
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Sat Aug 28, 2010 9:07 pm    Post subject: Reply with quote

Wow, this thread got resurrected. Thanks everyone for looking at this and for the suggestions.

I would like to try out the new math to see how it runs, and to spend some time reasonably soon playing with this.

I have hesitated to file an upstream bug report because I'm not a computer programmer, and feel like my input would be more on the level of "feature request" as opposed to bug report. Although if a patch that works well does come out of this, maybe I should rethink that.

Let me try to work out a slightly improved or better patch and I'll post back here if I have any success.

Thanks!
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Sat Aug 28, 2010 11:03 pm    Post subject: Reply with quote

Edit - consider just skipping this post and going to my next post with the updated patch.

OK, just a quick update. First of all, in order to not break other things that might call interpolate(), I created a new function interpolate_nonlinear() and added it to kwineffects.h, and then updated minimizeanimation.cpp to call this new function instead. An on-line search of the current KDE codebase does not reveal any hits for "interpolate_nonlinear" so I think this has successfully isolated this change to this specific place in the code. These are all against KDE-4.4.5.

Here are the patches:
Code:

cat minimizeanimation.cpp.patch
--- a/kwin/effects/minimizeanimation/minimizeanimation.cpp.old   2010-08-28 14:54:27.000000000 -0700
+++ b/kwin/effects/minimizeanimation/minimizeanimation.cpp   2010-08-28 15:07:06.000000000 -0700
@@ -92,10 +92,10 @@
         if( !icon.isValid() )
             icon = QRect( displayWidth() / 2, displayHeight() / 2, 0, 0 );
 
-        data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress);
-        data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress);
-        data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress);
-        data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress);
+        data.xScale *= interpolate_nonlinear(1.0, icon.width() / (double)geo.width(), progress);
+        data.yScale *= interpolate_nonlinear(1.0, icon.height() / (double)geo.height(), progress);
+        data.xTranslate = (int)interpolate_nonlinear(data.xTranslate, icon.x() - geo.x(), progress);
+        data.yTranslate = (int)interpolate_nonlinear(data.yTranslate, icon.y() - geo.y(), progress);
         data.opacity *= 0.1 + (1-progress)*0.9;
     }



Code:
cat kwineffects.h.patch
--- a/kwin/lib/kwineffects.h.old   2010-08-28 15:13:03.000000000 -0700
+++ b/kwin/lib/kwineffects.h   2010-08-28 15:18:57.000000000 -0700
@@ -462,6 +462,16 @@
             {
             return x * (1 - a) + y * a;
             }
+        /**
+         * Non-linearly interpolates between @p x and @p y.
+         *
+         * Returns @p x when @p a = 0; returns @p y when @p a = 1.
+         **/


+        static double interpolate_nonlinear(double x, double y, double a)
+            {
+            a = a * a;
+            return x * (1 - a) + y * a;
+            }
         /** Helper to set WindowPaintData and QRegion to necessary transformations so that
          * a following drawWindow() would put the window at the requested geometry (useful for thumbnails)
          **/


As above, these patches will need to be saved in the /usr/portage/kde-base/kwin/files directory, and then the following change to the ebuild (without the '+') /usr/portage/kde-base/kwin/kwin-4.4.5.ebuild:

Code:
PATCHES=(
   "${FILESDIR}/${PN}-4.4.2-xinerama_cmake_automagic.patch"
+   "${FILESDIR}/minimizeanimation.cpp.patch"
+   "${FILESDIR}/kwineffects.h.patch"
)


And finally:

Code:
ebuild kwin-4.4.5.ebuild manifest
emerge --oneshot kwin


And then log out and back in again.

Now to play with the math.


Last edited by piwacet on Sun Aug 29, 2010 5:31 am; edited 1 time in total
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Sun Aug 29, 2010 4:20 am    Post subject: Reply with quote

OK, well, a new approach. I think this approach will not break anything, as it only creates two new variables "progress_nonlinear_geometry" and "progress_nonlinear_opacity," and an on-line search of the KDE code shows these terms are not used anywhere else. The patch works by computing the values "progress_nonlinear_geometry" and "progress_nonlinear_opacity" from the original "progress" variable in a non-linear way, and then uses these new variables in place of the "progress" variable. This approach only involves patching one file, and although I'm not a programmer, this patch may actually be technically correct.

It uses math from Akkara's post above. I noticed that the animation's linear change in opacity was distracting with the non-linear geometry changes, so the patch also provides math to tweak the way the opacity changes as the animation progresses. The opacity can be tweaked independently of the geometry.

These functions behave correctly in that they will return 1 if given 1, return 0 if given 0, and if given a value between 0 and 1, they will return a value between 0 and 1. My understanding is that the original "progress" variable is a variable that ranges from 0 to 1. The math can be tweaked as per Akkara's descriptions above. Replacing "progress" with the product "progress*progress" or vice-versa in the pow() functions can further tweak the math. Specifically, you would tweak 'n,' and the second parameter of the pow() function. The higher the value of 'n,' the more "non-linear" the animation will be.

Code:
(pow(n, progress) - 1) / (n-1)

or

Code:
(pow(n, progress*progress) - 1) / (n-1)


Code:
cat minimizeanimation.cpp.patch
--- a/kwin/effects/minimizeanimation/minimizeanimation.cpp.old   2010-08-28 16:57:32.000000000 -0700
+++ b/kwin/effects/minimizeanimation/minimizeanimation.cpp   2010-08-28 20:03:54.000000000 -0700
@@ -19,6 +19,7 @@
 *********************************************************************/
 
 #include "minimizeanimation.h"
+#include <math.h>
 
 namespace KWin
 {
@@ -85,6 +86,8 @@
     {
         // 0 = not minimized, 1 = fully minimized
         double progress = entry->value();
+        double progress_nonlinear_geometry;
+        double progress_nonlinear_opacity;
 
         QRect geo = w->geometry();
         QRect icon = w->iconGeometry();
@@ -92,11 +95,16 @@
         if( !icon.isValid() )
             icon = QRect( displayWidth() / 2, displayHeight() / 2, 0, 0 );
 
-        data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress);
-        data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress);
-        data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress);
-        data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress);
-        data.opacity *= 0.1 + (1-progress)*0.9;
+        progress_nonlinear_geometry = (pow(50, progress*progress) - 1) / 49;
+
+        data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress_nonlinear_geometry);
+        data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress_nonlinear_geometry);
+        data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress_nonlinear_geometry);
+        data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress_nonlinear_geometry);
+
+        progress_nonlinear_opacity = (pow(3, progress) - 1) / 2;
+
+        data.opacity *= 0.1 + (1-progress_nonlinear_opacity)*0.9;
     }
 
     // Call the next effect.



Minimize/unminimize is smoother now; perhaps not as smooth as I recall compiz being, but this is the best it's been for me so far.

Again, for anyone who is interested, this is what the original file currently looks like in the 4.4 branch:

http://lxr.kde.org/source/KDE/kdebase/workspace/kwin/effects/minimizeanimation/minimizeanimation.cpp?v=4.4-branch

Thanks everybody for your help!
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Sun Aug 29, 2010 9:02 pm    Post subject: Reply with quote

Actually, cubing the variable "progress" instead of squaring it has worthwhile effect as well, i.e changing:

Code:
+        progress_nonlinear_geometry = (pow(50, progress*progress) - 1) / 49;


to

Code:
+        progress_nonlinear_geometry = (pow(50, progress*progress*progress) - 1) / 49;


not sure which I like better.
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Tue Sep 07, 2010 2:15 am    Post subject: Reply with quote

I'm thinking I may submit this patch upstream, see if there is any interest. I'll link this thread.
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Tue Sep 07, 2010 4:42 am    Post subject: Reply with quote

You are computing (50^(progress^3) - 1) / 49. Are you sure that is what you want?
Back to top
View user's profile Send private message
ppurka
Advocate
Advocate


Joined: 26 Dec 2004
Posts: 3256

PostPosted: Tue Sep 07, 2010 5:23 am    Post subject: Reply with quote

Shining Arcanine wrote:
You are computing (50^(progress^3) - 1) / 49. Are you sure that is what you want?
Here progress is between 0 and 1, so it is not computing really large numbers.
_________________
emerge --quiet redefined | E17 vids: I, II | Now using kde5 | e is unstable :-/
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Tue Sep 07, 2010 6:46 am    Post subject: Reply with quote

Actually the version of the formula that I'm currently using (and like) is:

(50^(progress^2)-1)/49

But yes, the math may be too compute intensive and I could easily see developers not liking that.
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Tue Sep 07, 2010 10:46 am    Post subject: Reply with quote

piwacet wrote:
Actually the version of the formula that I'm currently using (and like) is:

(50^(progress^2)-1)/49

But yes, the math may be too compute intensive and I could easily see developers not liking that.


Actually, pow() has O(log(n)) time, so it is not an issue. It uses a method called square and multiply:

http://en.wikipedia.org/wiki/Exponentiation_by_squaring
Back to top
View user's profile Send private message
Akkara
Bodhisattva
Bodhisattva


Joined: 28 Mar 2006
Posts: 6702
Location: &akkara

PostPosted: Tue Sep 07, 2010 12:31 pm    Post subject: Reply with quote

Shining Arcanine wrote:
Actually, pow() has O(log(n)) time, so it is not an issue. It uses a method called square and multiply:

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

This is only true when calculating integer powers using that particular algorithm.

The pow() function is a floating-point power: both variables are doubles. It is actually constant time, albeit a relatively large constant. The way it works internally is using logs and exponentials. But it doesn't just call the log() function. More precision is needed to compute an accurate power this way, so there's actually a independent special-purpose log and exponential in there.

How many distinct values does progress take on? If it is less than 100 or so, it might be best to do this with table lookup. For example, if progress increments by 1/NINCR:
Code:
double lookup[NINCR+1]; /* <=== note the "+1": this is important */
....
    int idx = round(progress * NINCR);
    if(idx < 0 || idx > NINCR) {
        /* this shouldn't happen - log a diagnostic somehow */
        idx = (idx < 0) ? 0 : NINCR;
    }
    return lookup[idx];
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Tue Sep 07, 2010 8:03 pm    Post subject: Reply with quote

Thanks. I don't know how many distinct values 'progress' takes on; I really don't understand the code that well. I suppose with a look-up-table we could make the animation do exactly as we want, but I wonder if the number of values that 'progress' takes is a constant, or if it is a function of screen size or other settings.

I wonder how this patch would work on an older, slower machine. I wonder what KDE regards as the "minimum requirements" that they are coding for.

I've noticed that other animations include the math.h headers, so there must be somewhat complicated math in those, but perhaps these are the animations not meant to be used on older hardware.

Thanks everybody!
Back to top
View user's profile Send private message
Shining Arcanine
Veteran
Veteran


Joined: 24 Sep 2009
Posts: 1110

PostPosted: Wed Sep 08, 2010 12:12 am    Post subject: Reply with quote

Akkara wrote:
Shining Arcanine wrote:
Actually, pow() has O(log(n)) time, so it is not an issue. It uses a method called square and multiply:

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

This is only true when calculating integer powers using that particular algorithm.

The pow() function is a floating-point power: both variables are doubles. It is actually constant time, albeit a relatively large constant. The way it works internally is using logs and exponentials. But it doesn't just call the log() function. More precision is needed to compute an accurate power this way, so there's actually a independent special-purpose log and exponential in there.

How many distinct values does progress take on? If it is less than 100 or so, it might be best to do this with table lookup. For example, if progress increments by 1/NINCR:
Code:
double lookup[NINCR+1]; /* <=== note the "+1": this is important */
....
    int idx = round(progress * NINCR);
    if(idx < 0 || idx > NINCR) {
        /* this shouldn't happen - log a diagnostic somehow */
        idx = (idx < 0) ? 0 : NINCR;
    }
    return lookup[idx];


That is only true in C. In C++, pow() is overloaded. Since the exponent being passed to the function is an integer, the integer exponent version is called, which has O(log(n)) time:

http://www.cplusplus.com/reference/clibrary/cmath/pow/

I believe that KDE is written in C++, so these distinctions are important.
Back to top
View user's profile Send private message
Akkara
Bodhisattva
Bodhisattva


Joined: 28 Mar 2006
Posts: 6702
Location: &akkara

PostPosted: Wed Sep 08, 2010 1:15 am    Post subject: Reply with quote

Shining Arcanine wrote:
In C++, pow() is overloaded. Since the exponent being passed to the function is an integer, the integer exponent version is called, which has O(log(n)) time:

http://www.cplusplus.com/reference/clibrary/cmath/pow/

I believe that KDE is written in C++, so these distinctions are important.

It is a good point to bring up.

But in piwacet's expression,
Code:
progress_nonlinear_geometry = (pow(50, progress*progress*progress) - 1) / 49;
or
Code:
progress_nonlinear_geometry = (pow(50, progress*progress) - 1) / 49;

the call to pow is receiving a floating-point argument for the exponent. The power-by-repeated squaring algorithm needs a integer exponent, which this is not. The base is integer but that doesn't help here. I'm quite sure this one's using the internal higher-precision log and exponentiation algorithm.
Back to top
View user's profile Send private message
piwacet
Guru
Guru


Joined: 30 Dec 2004
Posts: 486

PostPosted: Thu Dec 08, 2011 3:38 am    Post subject: Reply with quote

Here's an updated patch for 4.7.3. (I built it using 4.7.4 sources, but it applied to my 4.7.3 without problem - I'm using gentoo stable.) Again, I'm not a programmer, but is working so far:

Code:
cat minimizeanimation.cpp.patch
--- kde-workspace-4.7.4/kwin/effects/minimizeanimation/minimizeanimation.cpp   2011-05-20 13:32:07.000000000 -0700
+++ kde-workspace-4.7.4/kwin/effects/minimizeanimation/minimizeanimation.cpp.new   2011-12-07 19:08:47.004001054 -0800
@@ -20,6 +20,7 @@
 
 #include "minimizeanimation.h"
 #include <QtCore/QTimeLine>
+#include <math.h>
 
 namespace KWin
 {
@@ -84,6 +85,8 @@
     if (entry != mTimeLineWindows.constEnd()) {
         // 0 = not minimized, 1 = fully minimized
         double progress = entry.value()->currentValue();
+        double progress_nonlinear_geometry;
+        double progress_nonlinear_opacity;
 
         QRect geo = w->geometry();
         QRect icon = w->iconGeometry();
@@ -91,12 +94,17 @@
         if (!icon.isValid())
             icon = QRect(displayWidth() / 2, displayHeight() / 2, 0, 0);
 
-        data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress);
-        data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress);
-        data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress);
-        data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress);
-        data.opacity *= 0.1 + (1 - progress) * 0.9;
-    }
+         progress_nonlinear_geometry = (pow(50, progress*progress) - 1) / 49;
+
+         data.xScale *= interpolate(1.0, icon.width() / (double)geo.width(), progress_nonlinear_geometry);
+         data.yScale *= interpolate(1.0, icon.height() / (double)geo.height(), progress_nonlinear_geometry);
+         data.xTranslate = (int)interpolate(data.xTranslate, icon.x() - geo.x(), progress_nonlinear_geometry);
+         data.yTranslate = (int)interpolate(data.yTranslate, icon.y() - geo.y(), progress_nonlinear_geometry);
+
+         progress_nonlinear_opacity = (pow(3, progress) - 1) / 2;
+
+         data.opacity *= 0.1 + (1-progress_nonlinear_opacity)*0.9;
+}
 
     // Call the next effect.
     effects->paintWindow(w, mask, region, data);
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Unsupported Software All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum