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 19cfd74d65d832137e20e193c960802afba73b5d38sm 20cfd74d65d832137e20e193c960802afba73b5d38sm/** 21cfd74d65d832137e20e193c960802afba73b5d38sm * Manages a double-buffered queue of renderable objects. The game thread submits drawable objects 22cfd74d65d832137e20e193c960802afba73b5d38sm * to the the active render queue while the render thread consumes drawables from the alternate 23cfd74d65d832137e20e193c960802afba73b5d38sm * queue. When both threads complete a frame the queues are swapped. Note that this class can 24cfd74d65d832137e20e193c960802afba73b5d38sm * manage any number (>=2) of render queues, but increasing the number over two means that the game 25cfd74d65d832137e20e193c960802afba73b5d38sm * logic will be running significantly ahead of the rendering thread, which may make the user feel 26cfd74d65d832137e20e193c960802afba73b5d38sm * that the controls are "loose." 27cfd74d65d832137e20e193c960802afba73b5d38sm */ 28cfd74d65d832137e20e193c960802afba73b5d38smpublic class RenderSystem extends BaseObject { 29cfd74d65d832137e20e193c960802afba73b5d38sm private static final int TEXTURE_SORT_BUCKET_SIZE = 1000; 30cfd74d65d832137e20e193c960802afba73b5d38sm private RenderElementPool mElementPool; 31cfd74d65d832137e20e193c960802afba73b5d38sm private ObjectManager[] mRenderQueues; 32cfd74d65d832137e20e193c960802afba73b5d38sm private int mQueueIndex; 33cfd74d65d832137e20e193c960802afba73b5d38sm 34cfd74d65d832137e20e193c960802afba73b5d38sm private final static int DRAW_QUEUE_COUNT = 2; 352b1168acefb6a4104bb7f008df6ac51fcd1de7ecsm private final static int MAX_RENDER_OBJECTS_PER_FRAME = 384; 36cfd74d65d832137e20e193c960802afba73b5d38sm private final static int MAX_RENDER_OBJECTS = MAX_RENDER_OBJECTS_PER_FRAME * DRAW_QUEUE_COUNT; 37cfd74d65d832137e20e193c960802afba73b5d38sm 38cfd74d65d832137e20e193c960802afba73b5d38sm public RenderSystem() { 39cfd74d65d832137e20e193c960802afba73b5d38sm super(); 40cfd74d65d832137e20e193c960802afba73b5d38sm mElementPool = new RenderElementPool(MAX_RENDER_OBJECTS); 41cfd74d65d832137e20e193c960802afba73b5d38sm mRenderQueues = new ObjectManager[DRAW_QUEUE_COUNT]; 42cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < DRAW_QUEUE_COUNT; x++) { 439d4cc2572d37983607df38b0f4216ed76ac51814sm mRenderQueues[x] = new PhasedObjectManager(MAX_RENDER_OBJECTS_PER_FRAME); 44cfd74d65d832137e20e193c960802afba73b5d38sm } 45cfd74d65d832137e20e193c960802afba73b5d38sm mQueueIndex = 0; 46cfd74d65d832137e20e193c960802afba73b5d38sm } 47cfd74d65d832137e20e193c960802afba73b5d38sm 48cfd74d65d832137e20e193c960802afba73b5d38sm @Override 49cfd74d65d832137e20e193c960802afba73b5d38sm public void reset() { 50cfd74d65d832137e20e193c960802afba73b5d38sm 51cfd74d65d832137e20e193c960802afba73b5d38sm } 52cfd74d65d832137e20e193c960802afba73b5d38sm 53cfd74d65d832137e20e193c960802afba73b5d38sm public void scheduleForDraw(DrawableObject object, Vector2 position, int priority, boolean cameraRelative) { 54cfd74d65d832137e20e193c960802afba73b5d38sm RenderElement element = mElementPool.allocate(); 55cfd74d65d832137e20e193c960802afba73b5d38sm if (element != null) { 56cfd74d65d832137e20e193c960802afba73b5d38sm element.set(object, position, priority, cameraRelative); 57cfd74d65d832137e20e193c960802afba73b5d38sm mRenderQueues[mQueueIndex].add(element); 58cfd74d65d832137e20e193c960802afba73b5d38sm } 59cfd74d65d832137e20e193c960802afba73b5d38sm } 60cfd74d65d832137e20e193c960802afba73b5d38sm 61cfd74d65d832137e20e193c960802afba73b5d38sm private void clearQueue(FixedSizeArray<BaseObject> objects) { 62cfd74d65d832137e20e193c960802afba73b5d38sm final int count = objects.getCount(); 63cfd74d65d832137e20e193c960802afba73b5d38sm final Object[] objectArray = objects.getArray(); 64cfd74d65d832137e20e193c960802afba73b5d38sm final RenderElementPool elementPool = mElementPool; 65cfd74d65d832137e20e193c960802afba73b5d38sm for (int i = count - 1; i >= 0; i--) { 66cfd74d65d832137e20e193c960802afba73b5d38sm RenderElement element = (RenderElement)objectArray[i]; 67cfd74d65d832137e20e193c960802afba73b5d38sm elementPool.release(element); 68cfd74d65d832137e20e193c960802afba73b5d38sm objects.removeLast(); 69cfd74d65d832137e20e193c960802afba73b5d38sm } 70cfd74d65d832137e20e193c960802afba73b5d38sm 71cfd74d65d832137e20e193c960802afba73b5d38sm } 72cfd74d65d832137e20e193c960802afba73b5d38sm 73cfd74d65d832137e20e193c960802afba73b5d38sm public void swap(GameRenderer renderer, float cameraX, float cameraY) { 74cfd74d65d832137e20e193c960802afba73b5d38sm mRenderQueues[mQueueIndex].commitUpdates(); 75cfd74d65d832137e20e193c960802afba73b5d38sm 76cfd74d65d832137e20e193c960802afba73b5d38sm // This code will block if the previous queue is still being executed. 77cfd74d65d832137e20e193c960802afba73b5d38sm renderer.setDrawQueue(mRenderQueues[mQueueIndex], cameraX, cameraY); 78cfd74d65d832137e20e193c960802afba73b5d38sm 79cfd74d65d832137e20e193c960802afba73b5d38sm final int lastQueue = (mQueueIndex == 0) ? DRAW_QUEUE_COUNT - 1 : mQueueIndex - 1; 80cfd74d65d832137e20e193c960802afba73b5d38sm 81cfd74d65d832137e20e193c960802afba73b5d38sm // Clear the old queue. 82cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<BaseObject> objects = mRenderQueues[lastQueue].getObjects(); 83cfd74d65d832137e20e193c960802afba73b5d38sm clearQueue(objects); 84cfd74d65d832137e20e193c960802afba73b5d38sm 85cfd74d65d832137e20e193c960802afba73b5d38sm mQueueIndex = (mQueueIndex + 1) % DRAW_QUEUE_COUNT; 86cfd74d65d832137e20e193c960802afba73b5d38sm } 87cfd74d65d832137e20e193c960802afba73b5d38sm 88cfd74d65d832137e20e193c960802afba73b5d38sm /* Empties all draw queues and disconnects the game thread from the renderer. */ 89cfd74d65d832137e20e193c960802afba73b5d38sm public void emptyQueues(GameRenderer renderer) { 90cfd74d65d832137e20e193c960802afba73b5d38sm renderer.setDrawQueue(null, 0.0f, 0.0f); 91cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < DRAW_QUEUE_COUNT; x++) { 92cfd74d65d832137e20e193c960802afba73b5d38sm mRenderQueues[x].commitUpdates(); 93cfd74d65d832137e20e193c960802afba73b5d38sm FixedSizeArray<BaseObject> objects = mRenderQueues[x].getObjects(); 94cfd74d65d832137e20e193c960802afba73b5d38sm clearQueue(objects); 95cfd74d65d832137e20e193c960802afba73b5d38sm 96cfd74d65d832137e20e193c960802afba73b5d38sm } 97cfd74d65d832137e20e193c960802afba73b5d38sm } 98cfd74d65d832137e20e193c960802afba73b5d38sm 99cfd74d65d832137e20e193c960802afba73b5d38sm public class RenderElement extends PhasedObject { 100cfd74d65d832137e20e193c960802afba73b5d38sm public RenderElement() { 101cfd74d65d832137e20e193c960802afba73b5d38sm super(); 102cfd74d65d832137e20e193c960802afba73b5d38sm } 103cfd74d65d832137e20e193c960802afba73b5d38sm 104cfd74d65d832137e20e193c960802afba73b5d38sm public void set(DrawableObject drawable, Vector2 position, int priority, boolean isCameraRelative) { 105cfd74d65d832137e20e193c960802afba73b5d38sm mDrawable = drawable; 106cfd74d65d832137e20e193c960802afba73b5d38sm x = position.x; 107cfd74d65d832137e20e193c960802afba73b5d38sm y = position.y; 108cfd74d65d832137e20e193c960802afba73b5d38sm cameraRelative = isCameraRelative; 109cfd74d65d832137e20e193c960802afba73b5d38sm final int sortBucket = priority * TEXTURE_SORT_BUCKET_SIZE; 110cfd74d65d832137e20e193c960802afba73b5d38sm int sortOffset = 0; 111cfd74d65d832137e20e193c960802afba73b5d38sm if (drawable != null) { 112cfd74d65d832137e20e193c960802afba73b5d38sm Texture tex = drawable.getTexture(); 113cfd74d65d832137e20e193c960802afba73b5d38sm if (tex != null) { 114cfd74d65d832137e20e193c960802afba73b5d38sm sortOffset = (tex.resource % TEXTURE_SORT_BUCKET_SIZE) * Utils.sign(priority); 115cfd74d65d832137e20e193c960802afba73b5d38sm } 116cfd74d65d832137e20e193c960802afba73b5d38sm } 117cfd74d65d832137e20e193c960802afba73b5d38sm setPhase(sortBucket + sortOffset); 118cfd74d65d832137e20e193c960802afba73b5d38sm } 119cfd74d65d832137e20e193c960802afba73b5d38sm 120cfd74d65d832137e20e193c960802afba73b5d38sm public void reset() { 121cfd74d65d832137e20e193c960802afba73b5d38sm mDrawable = null; 122cfd74d65d832137e20e193c960802afba73b5d38sm x = 0.0f; 123cfd74d65d832137e20e193c960802afba73b5d38sm y = 0.0f; 124cfd74d65d832137e20e193c960802afba73b5d38sm cameraRelative = false; 125cfd74d65d832137e20e193c960802afba73b5d38sm } 126cfd74d65d832137e20e193c960802afba73b5d38sm 127cfd74d65d832137e20e193c960802afba73b5d38sm public DrawableObject mDrawable; 128cfd74d65d832137e20e193c960802afba73b5d38sm public float x; 129cfd74d65d832137e20e193c960802afba73b5d38sm public float y; 130cfd74d65d832137e20e193c960802afba73b5d38sm public boolean cameraRelative; 131cfd74d65d832137e20e193c960802afba73b5d38sm } 132cfd74d65d832137e20e193c960802afba73b5d38sm 133cfd74d65d832137e20e193c960802afba73b5d38sm protected class RenderElementPool extends TObjectPool<RenderElement> { 134cfd74d65d832137e20e193c960802afba73b5d38sm 135cfd74d65d832137e20e193c960802afba73b5d38sm RenderElementPool(int max) { 136cfd74d65d832137e20e193c960802afba73b5d38sm super(max); 137cfd74d65d832137e20e193c960802afba73b5d38sm } 138cfd74d65d832137e20e193c960802afba73b5d38sm 139cfd74d65d832137e20e193c960802afba73b5d38sm @Override 140cfd74d65d832137e20e193c960802afba73b5d38sm public void release(Object element) { 141cfd74d65d832137e20e193c960802afba73b5d38sm RenderElement renderable = (RenderElement)element; 142cfd74d65d832137e20e193c960802afba73b5d38sm // if this drawable came out of a pool, make sure it is returned to that pool. 143cfd74d65d832137e20e193c960802afba73b5d38sm final ObjectPool pool = renderable.mDrawable.getParentPool(); 144cfd74d65d832137e20e193c960802afba73b5d38sm if (pool != null) { 145cfd74d65d832137e20e193c960802afba73b5d38sm pool.release(renderable.mDrawable); 146cfd74d65d832137e20e193c960802afba73b5d38sm } 147cfd74d65d832137e20e193c960802afba73b5d38sm // reset on release 148cfd74d65d832137e20e193c960802afba73b5d38sm renderable.reset(); 149cfd74d65d832137e20e193c960802afba73b5d38sm super.release(element); 150cfd74d65d832137e20e193c960802afba73b5d38sm } 151cfd74d65d832137e20e193c960802afba73b5d38sm 152cfd74d65d832137e20e193c960802afba73b5d38sm @Override 153cfd74d65d832137e20e193c960802afba73b5d38sm protected void fill() { 154cfd74d65d832137e20e193c960802afba73b5d38sm for (int x = 0; x < getSize(); x++) { 155cfd74d65d832137e20e193c960802afba73b5d38sm getAvailable().add(new RenderElement()); 156cfd74d65d832137e20e193c960802afba73b5d38sm } 157cfd74d65d832137e20e193c960802afba73b5d38sm } 158cfd74d65d832137e20e193c960802afba73b5d38sm } 159cfd74d65d832137e20e193c960802afba73b5d38sm} 160