blob: 977eb1b49d820d287a3d5902e63e4cb3f7ef28c2 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.replica.replicaisland;
/**
* Manages a double-buffered queue of renderable objects. The game thread submits drawable objects
* to the the active render queue while the render thread consumes drawables from the alternate
* queue. When both threads complete a frame the queues are swapped. Note that this class can
* manage any number (>=2) of render queues, but increasing the number over two means that the game
* logic will be running significantly ahead of the rendering thread, which may make the user feel
* that the controls are "loose."
*/
public class RenderSystem extends BaseObject {
private static final int TEXTURE_SORT_BUCKET_SIZE = 1000;
private RenderElementPool mElementPool;
private ObjectManager[] mRenderQueues;
private int mQueueIndex;
private final static int DRAW_QUEUE_COUNT = 2;
private final static int MAX_RENDER_OBJECTS_PER_FRAME = 384;
private final static int MAX_RENDER_OBJECTS = MAX_RENDER_OBJECTS_PER_FRAME * DRAW_QUEUE_COUNT;
public RenderSystem() {
super();
mElementPool = new RenderElementPool(MAX_RENDER_OBJECTS);
mRenderQueues = new ObjectManager[DRAW_QUEUE_COUNT];
for (int x = 0; x < DRAW_QUEUE_COUNT; x++) {
mRenderQueues[x] = new PhasedObjectManager(MAX_RENDER_OBJECTS_PER_FRAME);
}
mQueueIndex = 0;
}
@Override
public void reset() {
}
public void scheduleForDraw(DrawableObject object, Vector2 position, int priority, boolean cameraRelative) {
RenderElement element = mElementPool.allocate();
if (element != null) {
element.set(object, position, priority, cameraRelative);
mRenderQueues[mQueueIndex].add(element);
}
}
private void clearQueue(FixedSizeArray<BaseObject> objects) {
final int count = objects.getCount();
final Object[] objectArray = objects.getArray();
final RenderElementPool elementPool = mElementPool;
for (int i = count - 1; i >= 0; i--) {
RenderElement element = (RenderElement)objectArray[i];
elementPool.release(element);
objects.removeLast();
}
}
public void swap(GameRenderer renderer, float cameraX, float cameraY) {
mRenderQueues[mQueueIndex].commitUpdates();
// This code will block if the previous queue is still being executed.
renderer.setDrawQueue(mRenderQueues[mQueueIndex], cameraX, cameraY);
final int lastQueue = (mQueueIndex == 0) ? DRAW_QUEUE_COUNT - 1 : mQueueIndex - 1;
// Clear the old queue.
FixedSizeArray<BaseObject> objects = mRenderQueues[lastQueue].getObjects();
clearQueue(objects);
mQueueIndex = (mQueueIndex + 1) % DRAW_QUEUE_COUNT;
}
/* Empties all draw queues and disconnects the game thread from the renderer. */
public void emptyQueues(GameRenderer renderer) {
renderer.setDrawQueue(null, 0.0f, 0.0f);
for (int x = 0; x < DRAW_QUEUE_COUNT; x++) {
mRenderQueues[x].commitUpdates();
FixedSizeArray<BaseObject> objects = mRenderQueues[x].getObjects();
clearQueue(objects);
}
}
public class RenderElement extends PhasedObject {
public RenderElement() {
super();
}
public void set(DrawableObject drawable, Vector2 position, int priority, boolean isCameraRelative) {
mDrawable = drawable;
x = position.x;
y = position.y;
cameraRelative = isCameraRelative;
final int sortBucket = priority * TEXTURE_SORT_BUCKET_SIZE;
int sortOffset = 0;
if (drawable != null) {
Texture tex = drawable.getTexture();
if (tex != null) {
sortOffset = (tex.resource % TEXTURE_SORT_BUCKET_SIZE) * Utils.sign(priority);
}
}
setPhase(sortBucket + sortOffset);
}
public void reset() {
mDrawable = null;
x = 0.0f;
y = 0.0f;
cameraRelative = false;
}
public DrawableObject mDrawable;
public float x;
public float y;
public boolean cameraRelative;
}
protected class RenderElementPool extends TObjectPool<RenderElement> {
RenderElementPool(int max) {
super(max);
}
@Override
public void release(Object element) {
RenderElement renderable = (RenderElement)element;
// if this drawable came out of a pool, make sure it is returned to that pool.
final ObjectPool pool = renderable.mDrawable.getParentPool();
if (pool != null) {
pool.release(renderable.mDrawable);
}
// reset on release
renderable.reset();
super.release(element);
}
@Override
protected void fill() {
for (int x = 0; x < getSize(); x++) {
getAvailable().add(new RenderElement());
}
}
}
}