Java程序  |  160行  |  5.65 KB

/*
 * 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());
            }
        }
    }
}