Home | History | Annotate | Download | only in replicaisland
      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 
     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
     49     public void reset() {
     50 
     51     }
     52 
     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 
     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 
     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. */
     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 {
    100         public RenderElement() {
    101             super();
    102         }
    103 
    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 
    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 
    135         RenderElementPool(int max) {
    136             super(max);
    137         }
    138 
    139         @Override
    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
    153         protected void fill() {
    154             for (int x = 0; x < getSize(); x++) {
    155                 getAvailable().add(new RenderElement());
    156             }
    157         }
    158     }
    159 }
    160