1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.replica.replicaisland;
18
19import android.os.SystemClock;
20import android.view.KeyEvent;
21
22
23/**
24 * The GameThread contains the main loop for the game engine logic.  It invokes the game graph,
25 * manages synchronization of input events, and handles the draw queue swap with the rendering
26 * thread.
27 */
28public class GameThread implements Runnable {
29    private long mLastTime;
30
31    private ObjectManager mGameRoot;
32    private GameRenderer mRenderer;
33    private Object mPauseLock;
34    private boolean mFinished;
35    private boolean mPaused = false;
36    private int mProfileFrames;
37    private long mProfileTime;
38
39    private static final float PROFILE_REPORT_DELAY = 3.0f;
40
41    public GameThread(GameRenderer renderer) {
42        mLastTime = SystemClock.uptimeMillis();
43        mRenderer = renderer;
44        mPauseLock = new Object();
45        mFinished = false;
46        mPaused = false;
47    }
48
49    public void run() {
50        mLastTime = SystemClock.uptimeMillis();
51        mFinished = false;
52        while (!mFinished) {
53            if (mGameRoot != null) {
54                mRenderer.waitDrawingComplete();
55
56                final long time = SystemClock.uptimeMillis();
57                final long timeDelta = time - mLastTime;
58                long finalDelta = timeDelta;
59                if (timeDelta > 12) {
60                    float secondsDelta = (time - mLastTime) * 0.001f;
61                    if (secondsDelta > 0.1f) {
62                        secondsDelta = 0.1f;
63                    }
64                    mLastTime = time;
65
66                    mGameRoot.update(secondsDelta, null);
67
68                    CameraSystem camera = mGameRoot.sSystemRegistry.cameraSystem;
69                    float x = 0.0f;
70                    float y = 0.0f;
71                    if (camera != null) {
72                    	x = camera.getFocusPositionX();
73                    	y = camera.getFocusPositionY();
74                    }
75                    BaseObject.sSystemRegistry.renderSystem.swap(mRenderer, x, y);
76
77                    final long endTime = SystemClock.uptimeMillis();
78
79                    finalDelta = endTime - time;
80
81                    mProfileTime += finalDelta;
82                    mProfileFrames++;
83                    if (mProfileTime > PROFILE_REPORT_DELAY * 1000) {
84                        final long averageFrameTime = mProfileTime / mProfileFrames;
85                        DebugLog.d("Game Profile", "Average: " + averageFrameTime);
86                        mGameRoot.sSystemRegistry.hudSystem.setFPS((int)(1000 * mProfileFrames / mProfileTime));
87                        mProfileTime = 0;
88                        mProfileFrames = 0;
89                    }
90                }
91                // If the game logic completed in less than 16ms, that means it's running
92                // faster than 60fps, which is our target frame rate.  In that case we should
93                // yield to the rendering thread, at least for the remaining frame.
94
95                if (finalDelta < 16) {
96                    try {
97                        Thread.sleep(16 - finalDelta);
98                    } catch (InterruptedException e) {
99                        // Interruptions here are no big deal.
100                    }
101                }
102
103                synchronized(mPauseLock) {
104                    if (mPaused) {
105                    	SoundSystem sound = BaseObject.sSystemRegistry.soundSystem;
106                    	if (sound != null) {
107                    		sound.pauseAll();
108                    		BaseObject.sSystemRegistry.inputSystem.releaseAllKeys();
109                    	}
110                        while (mPaused) {
111                            try {
112                            	mPauseLock.wait();
113                            } catch (InterruptedException e) {
114                                // No big deal if this wait is interrupted.
115                            }
116                        }
117                    }
118                }
119            }
120        }
121        // Make sure our dependence on the render system is cleaned up.
122        BaseObject.sSystemRegistry.renderSystem.emptyQueues(mRenderer);
123    }
124
125    public void stopGame() {
126    	synchronized (mPauseLock) {
127            mPaused = false;
128            mFinished = true;
129            mPauseLock.notifyAll();
130    	}
131    }
132
133    public void pauseGame() {
134        synchronized (mPauseLock) {
135            mPaused = true;
136        }
137    }
138
139    public void resumeGame() {
140        synchronized (mPauseLock) {
141            mPaused = false;
142            mPauseLock.notifyAll();
143        }
144    }
145
146    public boolean getPaused() {
147        return mPaused;
148    }
149
150    public void setGameRoot(ObjectManager gameRoot) {
151        mGameRoot = gameRoot;
152    }
153
154}
155