1cfd74d65d832137e20e193c960802afba73b5d38sm/*
23c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Copyright (C) 2010 The Android Open Source Project
3cfd74d65d832137e20e193c960802afba73b5d38sm *
4cfd74d65d832137e20e193c960802afba73b5d38sm * Licensed under the Apache License, Version 2.0 (the "License");
5cfd74d65d832137e20e193c960802afba73b5d38sm * you may not use this file except in compliance with the License.
6cfd74d65d832137e20e193c960802afba73b5d38sm * You may obtain a copy of the License at
7cfd74d65d832137e20e193c960802afba73b5d38sm *
8cfd74d65d832137e20e193c960802afba73b5d38sm *      http://www.apache.org/licenses/LICENSE-2.0
9cfd74d65d832137e20e193c960802afba73b5d38sm *
10cfd74d65d832137e20e193c960802afba73b5d38sm * Unless required by applicable law or agreed to in writing, software
11cfd74d65d832137e20e193c960802afba73b5d38sm * distributed under the License is distributed on an "AS IS" BASIS,
12cfd74d65d832137e20e193c960802afba73b5d38sm * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cfd74d65d832137e20e193c960802afba73b5d38sm * See the License for the specific language governing permissions and
14cfd74d65d832137e20e193c960802afba73b5d38sm * limitations under the License.
15cfd74d65d832137e20e193c960802afba73b5d38sm */
16cfd74d65d832137e20e193c960802afba73b5d38sm
17cfd74d65d832137e20e193c960802afba73b5d38smpackage com.replica.replicaisland;
18cfd74d65d832137e20e193c960802afba73b5d38sm
19cfd74d65d832137e20e193c960802afba73b5d38smimport android.content.Context;
20cfd74d65d832137e20e193c960802afba73b5d38smimport android.os.Build;
21cfd74d65d832137e20e193c960802afba73b5d38smimport android.os.SystemClock;
22cfd74d65d832137e20e193c960802afba73b5d38sm
23cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.egl.EGLConfig;
24cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.opengles.GL10;
25cfd74d65d832137e20e193c960802afba73b5d38sm
26cfd74d65d832137e20e193c960802afba73b5d38smimport com.replica.replicaisland.RenderSystem.RenderElement;
27cfd74d65d832137e20e193c960802afba73b5d38sm
28cfd74d65d832137e20e193c960802afba73b5d38sm/**
29cfd74d65d832137e20e193c960802afba73b5d38sm * GameRenderer the top-level rendering interface for the game engine.  It is called by
30cfd74d65d832137e20e193c960802afba73b5d38sm * GLSurfaceView and is responsible for submitting commands to OpenGL.  GameRenderer receives a
31cfd74d65d832137e20e193c960802afba73b5d38sm * queue of renderable objects from the thread and uses that to draw the scene every frame.  If
32cfd74d65d832137e20e193c960802afba73b5d38sm * no queue is available then no drawing is performed.  If the queue is not changed from frame to
33cfd74d65d832137e20e193c960802afba73b5d38sm * frame, the same scene will be redrawn every frame.
34cfd74d65d832137e20e193c960802afba73b5d38sm * The GameRenderer also invokes texture loads when it is activated.
35cfd74d65d832137e20e193c960802afba73b5d38sm */
36cfd74d65d832137e20e193c960802afba73b5d38smpublic class GameRenderer implements GLSurfaceView.Renderer {
37cfd74d65d832137e20e193c960802afba73b5d38sm    private static final int PROFILE_REPORT_DELAY = 3 * 1000;
38cfd74d65d832137e20e193c960802afba73b5d38sm
39cfd74d65d832137e20e193c960802afba73b5d38sm    private int mWidth;
40cfd74d65d832137e20e193c960802afba73b5d38sm    private int mHeight;
41cfd74d65d832137e20e193c960802afba73b5d38sm    private int mHalfWidth;
42cfd74d65d832137e20e193c960802afba73b5d38sm    private int mHalfHeight;
43cfd74d65d832137e20e193c960802afba73b5d38sm
44cfd74d65d832137e20e193c960802afba73b5d38sm    private float mScaleX;
45cfd74d65d832137e20e193c960802afba73b5d38sm    private float mScaleY;
46cfd74d65d832137e20e193c960802afba73b5d38sm    private Context mContext;
47cfd74d65d832137e20e193c960802afba73b5d38sm    private long mLastTime;
48cfd74d65d832137e20e193c960802afba73b5d38sm    private int mProfileFrames;
49cfd74d65d832137e20e193c960802afba73b5d38sm    private long mProfileWaitTime;
50cfd74d65d832137e20e193c960802afba73b5d38sm    private long mProfileFrameTime;
51cfd74d65d832137e20e193c960802afba73b5d38sm    private long mProfileSubmitTime;
52cfd74d65d832137e20e193c960802afba73b5d38sm    private int mProfileObjectCount;
53cfd74d65d832137e20e193c960802afba73b5d38sm
54cfd74d65d832137e20e193c960802afba73b5d38sm    private ObjectManager mDrawQueue;
55cfd74d65d832137e20e193c960802afba73b5d38sm    private boolean mDrawQueueChanged;
56cfd74d65d832137e20e193c960802afba73b5d38sm    private Game mGame;
57cfd74d65d832137e20e193c960802afba73b5d38sm    private Object mDrawLock;
58cfd74d65d832137e20e193c960802afba73b5d38sm
59cfd74d65d832137e20e193c960802afba73b5d38sm    float mCameraX;
60cfd74d65d832137e20e193c960802afba73b5d38sm    float mCameraY;
61cfd74d65d832137e20e193c960802afba73b5d38sm
62cfd74d65d832137e20e193c960802afba73b5d38sm    boolean mCallbackRequested;
63cfd74d65d832137e20e193c960802afba73b5d38sm
64cfd74d65d832137e20e193c960802afba73b5d38sm    public GameRenderer(Context context, Game game, int gameWidth, int gameHeight) {
65cfd74d65d832137e20e193c960802afba73b5d38sm        mContext = context;
66cfd74d65d832137e20e193c960802afba73b5d38sm        mGame = game;
67cfd74d65d832137e20e193c960802afba73b5d38sm        mWidth = gameWidth;
68cfd74d65d832137e20e193c960802afba73b5d38sm        mHeight = gameHeight;
69cfd74d65d832137e20e193c960802afba73b5d38sm        mHalfWidth = gameWidth / 2;
70cfd74d65d832137e20e193c960802afba73b5d38sm        mHalfHeight = gameHeight / 2;
71cfd74d65d832137e20e193c960802afba73b5d38sm        mScaleX = 1.0f;
72cfd74d65d832137e20e193c960802afba73b5d38sm        mScaleY = 1.0f;
73cfd74d65d832137e20e193c960802afba73b5d38sm        mDrawQueueChanged = false;
74cfd74d65d832137e20e193c960802afba73b5d38sm        mDrawLock = new Object();
75cfd74d65d832137e20e193c960802afba73b5d38sm        mCameraX = 0.0f;
76cfd74d65d832137e20e193c960802afba73b5d38sm        mCameraY = 0.0f;
77cfd74d65d832137e20e193c960802afba73b5d38sm        mCallbackRequested = false;
78cfd74d65d832137e20e193c960802afba73b5d38sm    }
79cfd74d65d832137e20e193c960802afba73b5d38sm
80cfd74d65d832137e20e193c960802afba73b5d38sm    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
81cfd74d65d832137e20e193c960802afba73b5d38sm        /*
82cfd74d65d832137e20e193c960802afba73b5d38sm         * Some one-time OpenGL initialization can be made here probably based
83cfd74d65d832137e20e193c960802afba73b5d38sm         * on features of this particular context
84cfd74d65d832137e20e193c960802afba73b5d38sm         */
85cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
86cfd74d65d832137e20e193c960802afba73b5d38sm
87cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glClearColor(0.0f, 0.0f, 0.0f, 1);
88cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glShadeModel(GL10.GL_FLAT);
89cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glDisable(GL10.GL_DEPTH_TEST);
90cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glEnable(GL10.GL_TEXTURE_2D);
91cfd74d65d832137e20e193c960802afba73b5d38sm        /*
92cfd74d65d832137e20e193c960802afba73b5d38sm         * By default, OpenGL enables features that improve quality but reduce
93cfd74d65d832137e20e193c960802afba73b5d38sm         * performance. One might want to tweak that especially on software
94cfd74d65d832137e20e193c960802afba73b5d38sm         * renderer.
95cfd74d65d832137e20e193c960802afba73b5d38sm         */
96cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glDisable(GL10.GL_DITHER);
97cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glDisable(GL10.GL_LIGHTING);
98cfd74d65d832137e20e193c960802afba73b5d38sm
99cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
100cfd74d65d832137e20e193c960802afba73b5d38sm
101cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
102cfd74d65d832137e20e193c960802afba73b5d38sm
103cfd74d65d832137e20e193c960802afba73b5d38sm        String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
104cfd74d65d832137e20e193c960802afba73b5d38sm        String version = gl.glGetString(GL10.GL_VERSION);
1053c1e67e433728684b5f228c5d4f3e5b1457bb271sm        String renderer = gl.glGetString(GL10.GL_RENDERER);
1063c1e67e433728684b5f228c5d4f3e5b1457bb271sm        boolean isSoftwareRenderer = renderer.contains("PixelFlinger");
107cfd74d65d832137e20e193c960802afba73b5d38sm        boolean isOpenGL10 = version.contains("1.0");
108cfd74d65d832137e20e193c960802afba73b5d38sm        boolean supportsDrawTexture = extensions.contains("draw_texture");
109cfd74d65d832137e20e193c960802afba73b5d38sm        // VBOs are standard in GLES1.1
1103c1e67e433728684b5f228c5d4f3e5b1457bb271sm        // No use using VBOs when software renderering, esp. since older versions of the software renderer
1113c1e67e433728684b5f228c5d4f3e5b1457bb271sm        // had a crash bug related to freeing VBOs.
1123c1e67e433728684b5f228c5d4f3e5b1457bb271sm        boolean supportsVBOs = !isSoftwareRenderer && (!isOpenGL10 || extensions.contains("vertex_buffer_object"));
113cfd74d65d832137e20e193c960802afba73b5d38sm        ContextParameters params = BaseObject.sSystemRegistry.contextParameters;
114cfd74d65d832137e20e193c960802afba73b5d38sm        params.supportsDrawTexture = supportsDrawTexture;
115cfd74d65d832137e20e193c960802afba73b5d38sm        params.supportsVBOs = supportsVBOs;
116cfd74d65d832137e20e193c960802afba73b5d38sm
117cfd74d65d832137e20e193c960802afba73b5d38sm        hackBrokenDevices();
118cfd74d65d832137e20e193c960802afba73b5d38sm
1193c1e67e433728684b5f228c5d4f3e5b1457bb271sm        DebugLog.i("Graphics Support", version + " (" + renderer + "): " +(supportsDrawTexture ?  "draw texture," : "") + (supportsVBOs ? "vbos" : ""));
120cfd74d65d832137e20e193c960802afba73b5d38sm
121cfd74d65d832137e20e193c960802afba73b5d38sm        mGame.onSurfaceCreated();
122cfd74d65d832137e20e193c960802afba73b5d38sm
123cfd74d65d832137e20e193c960802afba73b5d38sm    }
124cfd74d65d832137e20e193c960802afba73b5d38sm
125cfd74d65d832137e20e193c960802afba73b5d38sm    private void hackBrokenDevices() {
126cfd74d65d832137e20e193c960802afba73b5d38sm    	// Some devices are broken.  Fix them here.  This is pretty much the only
127cfd74d65d832137e20e193c960802afba73b5d38sm    	// device-specific code in the whole project.  Ugh.
128cfd74d65d832137e20e193c960802afba73b5d38sm        ContextParameters params = BaseObject.sSystemRegistry.contextParameters;
129cfd74d65d832137e20e193c960802afba73b5d38sm
130cfd74d65d832137e20e193c960802afba73b5d38sm
131cfd74d65d832137e20e193c960802afba73b5d38sm    	if (Build.PRODUCT.contains("morrison")) {
132cfd74d65d832137e20e193c960802afba73b5d38sm    		// This is the Motorola Cliq.  This device LIES and says it supports
133cfd74d65d832137e20e193c960802afba73b5d38sm    		// VBOs, which it actually does not (or, more likely, the extensions string
134cfd74d65d832137e20e193c960802afba73b5d38sm    		// is correct and the GL JNI glue is broken).
135cfd74d65d832137e20e193c960802afba73b5d38sm    		params.supportsVBOs = false;
136cfd74d65d832137e20e193c960802afba73b5d38sm    		// TODO: if Motorola fixes this, I should switch to using the fingerprint
137cfd74d65d832137e20e193c960802afba73b5d38sm    		// (blur/morrison/morrison/morrison:1.5/CUPCAKE/091007:user/ota-rel-keys,release-keys)
138cfd74d65d832137e20e193c960802afba73b5d38sm    		// instead of the product name so that newer versions use VBOs.
139cfd74d65d832137e20e193c960802afba73b5d38sm    	}
140cfd74d65d832137e20e193c960802afba73b5d38sm    }
141cfd74d65d832137e20e193c960802afba73b5d38sm
142cfd74d65d832137e20e193c960802afba73b5d38sm    public void loadTextures(GL10 gl, TextureLibrary library) {
143cfd74d65d832137e20e193c960802afba73b5d38sm        if (gl != null) {
144cfd74d65d832137e20e193c960802afba73b5d38sm            library.loadAll(mContext, gl);
145cfd74d65d832137e20e193c960802afba73b5d38sm            DebugLog.d("AndouKun", "Textures Loaded.");
146cfd74d65d832137e20e193c960802afba73b5d38sm        }
147cfd74d65d832137e20e193c960802afba73b5d38sm    }
148cfd74d65d832137e20e193c960802afba73b5d38sm
149cfd74d65d832137e20e193c960802afba73b5d38sm    public void flushTextures(GL10 gl, TextureLibrary library) {
150cfd74d65d832137e20e193c960802afba73b5d38sm        if (gl != null) {
151cfd74d65d832137e20e193c960802afba73b5d38sm            library.deleteAll(gl);
152cfd74d65d832137e20e193c960802afba73b5d38sm            DebugLog.d("AndouKun", "Textures Unloaded.");
153cfd74d65d832137e20e193c960802afba73b5d38sm        }
154cfd74d65d832137e20e193c960802afba73b5d38sm    }
155cfd74d65d832137e20e193c960802afba73b5d38sm
156cfd74d65d832137e20e193c960802afba73b5d38sm    public void loadBuffers(GL10 gl, BufferLibrary library) {
157cfd74d65d832137e20e193c960802afba73b5d38sm        if (gl != null) {
158cfd74d65d832137e20e193c960802afba73b5d38sm            library.generateHardwareBuffers(gl);
159cfd74d65d832137e20e193c960802afba73b5d38sm            DebugLog.d("AndouKun", "Buffers Created.");
160cfd74d65d832137e20e193c960802afba73b5d38sm        }
161cfd74d65d832137e20e193c960802afba73b5d38sm    }
162cfd74d65d832137e20e193c960802afba73b5d38sm
163cfd74d65d832137e20e193c960802afba73b5d38sm    public void flushBuffers(GL10 gl, BufferLibrary library) {
164cfd74d65d832137e20e193c960802afba73b5d38sm        if (gl != null) {
165cfd74d65d832137e20e193c960802afba73b5d38sm            library.releaseHardwareBuffers(gl);
166cfd74d65d832137e20e193c960802afba73b5d38sm            DebugLog.d("AndouKun", "Buffers Released.");
167cfd74d65d832137e20e193c960802afba73b5d38sm        }
168cfd74d65d832137e20e193c960802afba73b5d38sm    }
169cfd74d65d832137e20e193c960802afba73b5d38sm
170cfd74d65d832137e20e193c960802afba73b5d38sm    public void onSurfaceLost() {
171cfd74d65d832137e20e193c960802afba73b5d38sm        mGame.onSurfaceLost();
172cfd74d65d832137e20e193c960802afba73b5d38sm    }
173cfd74d65d832137e20e193c960802afba73b5d38sm
174cfd74d65d832137e20e193c960802afba73b5d38sm    public void requestCallback() {
175cfd74d65d832137e20e193c960802afba73b5d38sm    	mCallbackRequested = true;
176cfd74d65d832137e20e193c960802afba73b5d38sm    }
177cfd74d65d832137e20e193c960802afba73b5d38sm
178cfd74d65d832137e20e193c960802afba73b5d38sm    /** Draws the scene.  Note that the draw queue is locked for the duration of this function. */
179cfd74d65d832137e20e193c960802afba73b5d38sm    public void onDrawFrame(GL10 gl) {
1809d4cc2572d37983607df38b0f4216ed76ac51814sm
181cfd74d65d832137e20e193c960802afba73b5d38sm        long time = SystemClock.uptimeMillis();
182cfd74d65d832137e20e193c960802afba73b5d38sm        long time_delta = (time - mLastTime);
183cfd74d65d832137e20e193c960802afba73b5d38sm
184cfd74d65d832137e20e193c960802afba73b5d38sm        synchronized(mDrawLock) {
185cfd74d65d832137e20e193c960802afba73b5d38sm            if (!mDrawQueueChanged) {
186cfd74d65d832137e20e193c960802afba73b5d38sm                while (!mDrawQueueChanged) {
187cfd74d65d832137e20e193c960802afba73b5d38sm                    try {
188cfd74d65d832137e20e193c960802afba73b5d38sm                    	mDrawLock.wait();
189cfd74d65d832137e20e193c960802afba73b5d38sm                    } catch (InterruptedException e) {
190cfd74d65d832137e20e193c960802afba73b5d38sm                        // No big deal if this wait is interrupted.
191cfd74d65d832137e20e193c960802afba73b5d38sm                    }
192cfd74d65d832137e20e193c960802afba73b5d38sm                }
193cfd74d65d832137e20e193c960802afba73b5d38sm            }
194cfd74d65d832137e20e193c960802afba73b5d38sm            mDrawQueueChanged = false;
195cfd74d65d832137e20e193c960802afba73b5d38sm        }
196cfd74d65d832137e20e193c960802afba73b5d38sm
197cfd74d65d832137e20e193c960802afba73b5d38sm        final long wait = SystemClock.uptimeMillis();
198cfd74d65d832137e20e193c960802afba73b5d38sm
199cfd74d65d832137e20e193c960802afba73b5d38sm        if (mCallbackRequested) {
200cfd74d65d832137e20e193c960802afba73b5d38sm        	mGame.onSurfaceReady();
201cfd74d65d832137e20e193c960802afba73b5d38sm        	mCallbackRequested = false;
202cfd74d65d832137e20e193c960802afba73b5d38sm        }
203cfd74d65d832137e20e193c960802afba73b5d38sm
204cfd74d65d832137e20e193c960802afba73b5d38sm        DrawableBitmap.beginDrawing(gl, mWidth, mHeight);
205cfd74d65d832137e20e193c960802afba73b5d38sm
206cfd74d65d832137e20e193c960802afba73b5d38sm        synchronized (this) {
207cfd74d65d832137e20e193c960802afba73b5d38sm            if (mDrawQueue != null && mDrawQueue.getObjects().getCount() > 0) {
208cfd74d65d832137e20e193c960802afba73b5d38sm                OpenGLSystem.setGL(gl);
209cfd74d65d832137e20e193c960802afba73b5d38sm                FixedSizeArray<BaseObject> objects = mDrawQueue.getObjects();
210cfd74d65d832137e20e193c960802afba73b5d38sm                Object[] objectArray = objects.getArray();
211cfd74d65d832137e20e193c960802afba73b5d38sm                final int count = objects.getCount();
212cfd74d65d832137e20e193c960802afba73b5d38sm                final float scaleX = mScaleX;
213cfd74d65d832137e20e193c960802afba73b5d38sm                final float scaleY = mScaleY;
214cfd74d65d832137e20e193c960802afba73b5d38sm                final float halfWidth = mHalfWidth;
215cfd74d65d832137e20e193c960802afba73b5d38sm                final float halfHeight = mHalfHeight;
216cfd74d65d832137e20e193c960802afba73b5d38sm                mProfileObjectCount += count;
217cfd74d65d832137e20e193c960802afba73b5d38sm                for (int i = 0; i < count; i++) {
218cfd74d65d832137e20e193c960802afba73b5d38sm                    RenderElement element = (RenderElement)objectArray[i];
219cfd74d65d832137e20e193c960802afba73b5d38sm                    float x = element.x;
220cfd74d65d832137e20e193c960802afba73b5d38sm                    float y = element.y;
221cfd74d65d832137e20e193c960802afba73b5d38sm                    if (element.cameraRelative) {
222cfd74d65d832137e20e193c960802afba73b5d38sm                    	x = (x - mCameraX) + halfWidth;
223cfd74d65d832137e20e193c960802afba73b5d38sm                    	y = (y - mCameraY) + halfHeight;
224cfd74d65d832137e20e193c960802afba73b5d38sm                    }
225cfd74d65d832137e20e193c960802afba73b5d38sm                    element.mDrawable.draw(x, y, scaleX, scaleY);
226cfd74d65d832137e20e193c960802afba73b5d38sm                }
227cfd74d65d832137e20e193c960802afba73b5d38sm                OpenGLSystem.setGL(null);
228cfd74d65d832137e20e193c960802afba73b5d38sm            } else if (mDrawQueue == null) {
229cfd74d65d832137e20e193c960802afba73b5d38sm                // If we have no draw queue, clear the screen.  If we have a draw queue that
230cfd74d65d832137e20e193c960802afba73b5d38sm                // is empty, we'll leave the frame buffer alone.
231cfd74d65d832137e20e193c960802afba73b5d38sm                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
232cfd74d65d832137e20e193c960802afba73b5d38sm            }
233cfd74d65d832137e20e193c960802afba73b5d38sm        }
234cfd74d65d832137e20e193c960802afba73b5d38sm
235cfd74d65d832137e20e193c960802afba73b5d38sm        DrawableBitmap.endDrawing(gl);
236cfd74d65d832137e20e193c960802afba73b5d38sm
237cfd74d65d832137e20e193c960802afba73b5d38sm        long time2 = SystemClock.uptimeMillis();
238cfd74d65d832137e20e193c960802afba73b5d38sm        mLastTime = time2;
239cfd74d65d832137e20e193c960802afba73b5d38sm
240cfd74d65d832137e20e193c960802afba73b5d38sm        mProfileFrameTime += time_delta;
241cfd74d65d832137e20e193c960802afba73b5d38sm        mProfileSubmitTime += time2 - time;
242cfd74d65d832137e20e193c960802afba73b5d38sm        mProfileWaitTime += wait - time;
243cfd74d65d832137e20e193c960802afba73b5d38sm
244cfd74d65d832137e20e193c960802afba73b5d38sm        mProfileFrames++;
245cfd74d65d832137e20e193c960802afba73b5d38sm        if (mProfileFrameTime > PROFILE_REPORT_DELAY) {
246cfd74d65d832137e20e193c960802afba73b5d38sm        	final int validFrames = mProfileFrames;
247cfd74d65d832137e20e193c960802afba73b5d38sm            final long averageFrameTime = mProfileFrameTime / validFrames;
248cfd74d65d832137e20e193c960802afba73b5d38sm            final long averageSubmitTime = mProfileSubmitTime / validFrames;
249cfd74d65d832137e20e193c960802afba73b5d38sm            final float averageObjectsPerFrame = (float)mProfileObjectCount / validFrames;
250cfd74d65d832137e20e193c960802afba73b5d38sm            final long averageWaitTime = mProfileWaitTime / validFrames;
251cfd74d65d832137e20e193c960802afba73b5d38sm
252cfd74d65d832137e20e193c960802afba73b5d38sm            DebugLog.d("Render Profile",
253cfd74d65d832137e20e193c960802afba73b5d38sm            		"Average Submit: " + averageSubmitTime
254cfd74d65d832137e20e193c960802afba73b5d38sm            		+ "  Average Draw: " + averageFrameTime
255cfd74d65d832137e20e193c960802afba73b5d38sm            		+ " Objects/Frame: " + averageObjectsPerFrame
256cfd74d65d832137e20e193c960802afba73b5d38sm            		+ " Wait Time: " + averageWaitTime);
257cfd74d65d832137e20e193c960802afba73b5d38sm
258cfd74d65d832137e20e193c960802afba73b5d38sm            mProfileFrameTime = 0;
259cfd74d65d832137e20e193c960802afba73b5d38sm            mProfileSubmitTime = 0;
260cfd74d65d832137e20e193c960802afba73b5d38sm            mProfileFrames = 0;
261cfd74d65d832137e20e193c960802afba73b5d38sm            mProfileObjectCount = 0;
262cfd74d65d832137e20e193c960802afba73b5d38sm        }
263cfd74d65d832137e20e193c960802afba73b5d38sm
264cfd74d65d832137e20e193c960802afba73b5d38sm    }
265cfd74d65d832137e20e193c960802afba73b5d38sm
266cfd74d65d832137e20e193c960802afba73b5d38sm    public void onSurfaceChanged(GL10 gl, int w, int h) {
267cfd74d65d832137e20e193c960802afba73b5d38sm        DebugLog.d("AndouKun", "Surface Size Change: " + w + ", " + h);
268cfd74d65d832137e20e193c960802afba73b5d38sm
269cfd74d65d832137e20e193c960802afba73b5d38sm        //mWidth = w;0
270cfd74d65d832137e20e193c960802afba73b5d38sm        //mHeight = h;
271cfd74d65d832137e20e193c960802afba73b5d38sm    	// ensure the same aspect ratio as the game
272cfd74d65d832137e20e193c960802afba73b5d38sm    	float scaleX = (float)w / mWidth;
273cfd74d65d832137e20e193c960802afba73b5d38sm    	float scaleY =  (float)h / mHeight;
274cfd74d65d832137e20e193c960802afba73b5d38sm    	final int viewportWidth = (int)(mWidth * scaleX);
275cfd74d65d832137e20e193c960802afba73b5d38sm    	final int viewportHeight = (int)(mHeight * scaleY);
276cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glViewport(0, 0, viewportWidth, viewportHeight);
277cfd74d65d832137e20e193c960802afba73b5d38sm        mScaleX = scaleX;
278cfd74d65d832137e20e193c960802afba73b5d38sm        mScaleY = scaleY;
279cfd74d65d832137e20e193c960802afba73b5d38sm
280cfd74d65d832137e20e193c960802afba73b5d38sm
281cfd74d65d832137e20e193c960802afba73b5d38sm        /*
282cfd74d65d832137e20e193c960802afba73b5d38sm         * Set our projection matrix. This doesn't have to be done each time we
283cfd74d65d832137e20e193c960802afba73b5d38sm         * draw, but usually a new projection needs to be set when the viewport
284cfd74d65d832137e20e193c960802afba73b5d38sm         * is resized.
285cfd74d65d832137e20e193c960802afba73b5d38sm         */
286cfd74d65d832137e20e193c960802afba73b5d38sm        float ratio = (float) mWidth / mHeight;
287cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glMatrixMode(GL10.GL_PROJECTION);
288cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glLoadIdentity();
289cfd74d65d832137e20e193c960802afba73b5d38sm        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
290cfd74d65d832137e20e193c960802afba73b5d38sm
291cfd74d65d832137e20e193c960802afba73b5d38sm
292cfd74d65d832137e20e193c960802afba73b5d38sm        mGame.onSurfaceReady();
293cfd74d65d832137e20e193c960802afba73b5d38sm    }
294cfd74d65d832137e20e193c960802afba73b5d38sm
295cfd74d65d832137e20e193c960802afba73b5d38sm    public synchronized void setDrawQueue(ObjectManager queue, float cameraX, float cameraY) {
296cfd74d65d832137e20e193c960802afba73b5d38sm		mDrawQueue = queue;
297cfd74d65d832137e20e193c960802afba73b5d38sm		mCameraX = cameraX;
298cfd74d65d832137e20e193c960802afba73b5d38sm		mCameraY = cameraY;
299cfd74d65d832137e20e193c960802afba73b5d38sm    	synchronized(mDrawLock) {
300cfd74d65d832137e20e193c960802afba73b5d38sm    		mDrawQueueChanged = true;
301cfd74d65d832137e20e193c960802afba73b5d38sm    		mDrawLock.notify();
302cfd74d65d832137e20e193c960802afba73b5d38sm    	}
303cfd74d65d832137e20e193c960802afba73b5d38sm    }
304cfd74d65d832137e20e193c960802afba73b5d38sm
305cfd74d65d832137e20e193c960802afba73b5d38sm    public synchronized void onPause() {
306cfd74d65d832137e20e193c960802afba73b5d38sm    	// Stop waiting to avoid deadlock.
307cfd74d65d832137e20e193c960802afba73b5d38sm    	// TODO: this is a hack.  Probably this renderer
308cfd74d65d832137e20e193c960802afba73b5d38sm    	// should just use GLSurfaceView's non-continuious render
309cfd74d65d832137e20e193c960802afba73b5d38sm    	// mode.
310cfd74d65d832137e20e193c960802afba73b5d38sm    	synchronized(mDrawLock) {
311cfd74d65d832137e20e193c960802afba73b5d38sm    		mDrawQueueChanged = true;
312cfd74d65d832137e20e193c960802afba73b5d38sm    		mDrawLock.notify();
313cfd74d65d832137e20e193c960802afba73b5d38sm    	}
314cfd74d65d832137e20e193c960802afba73b5d38sm    }
315cfd74d65d832137e20e193c960802afba73b5d38sm
316cfd74d65d832137e20e193c960802afba73b5d38sm    /**
317cfd74d65d832137e20e193c960802afba73b5d38sm     * This function blocks while drawFrame() is in progress, and may be used by other threads to
318cfd74d65d832137e20e193c960802afba73b5d38sm     * determine when drawing is occurring.
319cfd74d65d832137e20e193c960802afba73b5d38sm     */
320cfd74d65d832137e20e193c960802afba73b5d38sm
321cfd74d65d832137e20e193c960802afba73b5d38sm    public synchronized void waitDrawingComplete() {
322cfd74d65d832137e20e193c960802afba73b5d38sm    }
323cfd74d65d832137e20e193c960802afba73b5d38sm
324cfd74d65d832137e20e193c960802afba73b5d38sm    public void setContext(Context newContext) {
325cfd74d65d832137e20e193c960802afba73b5d38sm        mContext = newContext;
326cfd74d65d832137e20e193c960802afba73b5d38sm    }
327cfd74d65d832137e20e193c960802afba73b5d38sm
328cfd74d65d832137e20e193c960802afba73b5d38sm
329cfd74d65d832137e20e193c960802afba73b5d38sm}
330