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