001    /**
002    * @author Václav Mikolášek
003    * nicklaus@students.zcu.cz
004    */
005    
006    package animace;
007    
008    import java.util.*;
009    
010    /**
011     * Tato třída slouží ke kontrole kreslení různých objektů, může měrit jak
012     * často jsou tyto objekty překreslovány (fps).
013     * Metody <tt>objectMoved</tt> a <tt>objectPainted</tt> jsou synchronizované, protože se
014     * předpokláda, že pohyb objektu a jeho vykreslování jsou řízeny různými vlákny.
015     * Potom PaintControl zařídí, že se s objektem nepohne dříve, dokud není jeho 
016     * pozice také nakreslena.
017     */
018    
019    public class PaintControl {
020    
021            /**
022             * painted, kontrolní podmínková proměnná. Z vnějšku by se neměla měnit
023             * jinak, než přes metody <tt>objectMoved</tt> a <tt>objectPainted</tt>,
024             * Není důvod porč by nemohla být <b><tt>private</tt></b>. :-)
025             */
026            public boolean painted = false;
027            /**
028             * Počet snímků = počet zavolání metody <tt>objectPainted</tt>.
029             */
030            public int framesCount = 0;
031            /**
032             *  počet pohybů  = počet zavolání metody <tt>objectMoved</tt>,
033             */
034            public int movesCount = 0;
035    
036            private boolean fpsOn = false;
037            private double fps = 0;
038            private double averageFps = 0;
039            private long timeLast = 0;
040            private long timeFirst = 0;
041            private long timeFirstMillis = 0;
042            private long timeStopedMillis = 0;
043            private double maxFps = 0;
044            private double minFps = Double.MAX_VALUE;
045                    
046            /**
047             * Když se s objektem pohne a je zavolána tato metoda, pozastaví se vlákno a čeká,
048             * než vlákno které se stará o vykreslování zavolá metodu objectPainted().
049             */
050            public synchronized void objectMoved() {
051                    movesCount++;
052                    while (!painted)
053                            try {
054                                    wait();
055                            }
056                            catch (InterruptedException e) {;}
057                    painted = false;
058            }
059    
060            /**
061             * Tato metoda vzbudí případné vlákno, které čekalo, než
062             * je objekt znovu překereslen.
063             */
064            public synchronized void objectPainted() {
065                    if (fpsOn) {
066                            countFps();
067                    }
068                    if (!painted){
069                            painted = true;
070                            notifyAll();
071                    }
072            }
073            
074            /**
075             * Počítá FPS, jak aktuální, tak i průměrné. Pro akutální FPS je nutné použít metodu
076             * System.nanoTime(), která je v SDK od verze SDK 1.5 odkomentujte text, v případe, že
077             * pouzivate tuto verzi nebo vyšší.
078             */
079            public double countFps() {
080                    if (timeFirstMillis == 0)
081                            timeFirstMillis = System.currentTimeMillis();   
082                    /* od verze SDK 1.5
083                    if (timeLast == 0)
084                            timeLast = System.nanoTime();   
085                    if (timeFirst == 0)
086                            timeFirst = System.nanoTime();  
087                    */
088                    else {
089                            averageFps = (1000d*framesCount/(System.currentTimeMillis() - timeFirstMillis));
090                            /* od verze SDK 1.5
091                            long timeNow = System.nanoTime();
092                            fps = 1000000000d / (timeNow - timeLast);
093                                    maxFps = fps > maxFps ? fps : maxFps;
094                            minFps = fps < minFps ? fps : minFps;
095                            timeLast = timeNow;
096                            */
097                            framesCount++;
098                    }
099                    return fps;
100            }
101            
102            /**
103             * Nastaví, zda bude PaintControl počítat, jak často je objekt překreslován
104             */
105            public void fps(boolean val) {
106                    fpsOn = val;
107                    /// jestlize bylo pocitani rozbehnuto, resetuj stav
108                    if (fpsOn) {
109                            timeLast        = 0;
110                            timeFirst       = 0;
111                            timeFirstMillis = System.currentTimeMillis();
112                            framesCount     = 0;
113                            movesCount      = 0;
114                    }
115            }
116            /**
117             * Vrací aktuální FPS
118             */
119            public double getFps() {
120                    return fps;
121            }
122    
123            /**
124             * Vrací průměrné FPS od doby kdy bylo zapnuto počítání metodou
125             * <tt>fps(true)</tt> do doby než je opět vypnuto.
126             */
127            public double getAverageFps() {
128                    return averageFps;
129            }
130            /**
131             * Vrací maximální FPS
132             */
133            public double getMaxFps() {
134                    return maxFps;
135            }
136            /**
137             * Vrací minimální FPS
138             */
139            public double getMinFps() {
140                    return minFps;
141            }
142    }