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