Java 2 Graphics Rendering
by Torpum Jannak


Example 1:
public void run() {
  while (true) {
    while (! m_paintQueue.isEmpty()) {
      repaint();
    }
    synchronized(m_paintQueue) {
      m_paintQueue.wait();
    }
  }
}


Listing One
import java.util.*;

public class ZBuffer extends Object {
  public static final int    MIN_Z_DEPTH     = 2;
  public static final int    MIN_GROWTH_SIZE = 10;
  public static final int    MAX_GROWTH_SIZE = 100;
  protected           int    m_maxZDepth;
  protected           Vector m_zDepthVectors[];
  
  public ZBuffer(int maxZDepth, int zGrowthSize)
      throws InstantiationException {
    // Validate and set internal variable from initialization param.
    m_maxZDepth   = Math.max(maxZDepth, MIN_Z_DEPTH);
    zGrowthSize   = Math.min(MAX_GROWTH_SIZE,
                      Math.max(zGrowthSize, MIN_GROWTH_SIZE));
    // Create the array of vectors
    m_zDepthVectors = new Vector[m_maxZDepth];
    for (int i = 0; i < m_maxZDepth; ++i) {
      m_zDepthVectors[i] = new Vector(zGrowthSize);
    }
  }
  public void addElement(int zDepth, Object obj) {
    m_zDepthVectors[zDepth].addElement(obj);
  }
  public int getMaxZDepth() { return m_maxZDepth; }

  public void removeElementAt(int zDepth, int index) {
    m_zDepthVectors[zDepth].removeElementAt(index);
  }
  public void removeAllElementsAtDepth(int zDepth) {
    m_zDepthVectors[zDepth].removeAllElements();
  }
  public void removeAllElements() {
    for (int i=0; i < m_maxZDepth; ++i)
      m_zDepthVectors[zDepth].removeAllElements();
  }
  /* Returns an enumeration of the components of this zBuffer
   * along the z axis from back to front.
   * @return  an enumeration of the components of this zBuffer.
   * @see     java.util.Enumeration
   */
  public final synchronized Enumeration elements() {    
    return new ZBufferEnumerator(this);
  }
  /* Supports the enumerator class
   * @return  the total number of elements in the ZBuffer
   */
  public int size() {
    int count = 0;
    for (int i=0; i < m_maxZDepth; --i)
      count += m_zDepthVectors[zDepth].size();
    return count;
  }
  /* Supports the enumerator class
   * @return Vector at the given zDepth
   */
  public Vector getVectorAtDepth(int depth) {
    return m_zDepthVectors[zDepth];
  }
}
final class ZBufferEnumerator implements Enumeration
{
  ZBuffer m_zb;
  int     m_count, m_depthCount, m_totalCount;
  int     m_zLevelCount, m_zLevelElementCount;
  ZBufferEnumerator(ZBuffer zb) {
      m_zb    = zb;
      m_count = m_zLevelCount = m_zLevelElementCount = 0;
    m_totalCount = zb.size();
  }
  public boolean hasMoreElements() { return m_count < m_totalCount; }
  public Object nextElement()
      throws NoSuchElementException {
    Object retObject = null;

      synchronized (m_zb) {
        // Check if we are done with the enumeration, otherwise
        // there is definitely something to return and we can
        // trust the while loop to exit at some point.
        if (m_count < m_totalCount) {
        Vector vCurrent;
        while (retObject == null) {
          vCurrent = m_zb.getVectorAtDepth(m_zLevelCount);
          if (m_zLevelElementCount < vCurrent.size()) {
            retObject = vCurrent.elementAt(m_zLevelElementCount++);
          } else {
            // Move to next zdepth level.
            ++m_zLevelCount;
            m_zLevelElementCount = 0;
          }
        }
        ++m_count;
          return retObject;
      }

    }
      throw new java.util.NoSuchElementException("ZBufferEnumerator");
  }
}


Listing Two
import java.awt.Point;
import java.awt.Image;

public class FinalRenderImage extends Object {
  public Point  screenOrigin;    // Upper left corner placement.
  public long   expirationTime;  // time when frame expires
  public Image  imageRef;        // Image for this segment.

  public FinalRenderImage(int id) {
    screenOrigin   = new Point(0,0);
    expirationTime = 0L;
    imageRef       = null;
  }
}


Listing Three
public void paint(Graphics g)
{
  // Pop the element off the paint queue
  RenderImage fri     = (RenderImage)(m_paintQueue.popElement());

  //Check if frame expired. If so, just drop it.
  long frameTimeStamp = System.currentTimeMillis();
  if (fri.expirationTime < frameTimeStamp) {
    if (fri.imageRef != null) {
      g.drawImage(
        fri.imageRef, fri.screenOrigin.x, fri.screenOrigin.y, null);
    }
  }
  // Push the used element back into the object pool's free queue.
  m_freePaintQueue.pushElement(fri);
}


Listing Four
private static final int TIMEOUT_LIMIT = 100;
  
  // ObjPoolElement is the data structure to hold and monitor
  // the object's usage
  private class ObjPoolElement {
    public boolean isAvailable;
    public Object  theObject;

    public void setObject(Object o) { theObject = o; }
  }
  
  private int m_maxSize;          // Pool's capacity
  private int m_currentFreeIndex; // round-robin index for getObject
  private ObjPoolElement m_Pool[];// Array of objects in pool
  
  // It is the responsibility of the derived class to define
  // what object is being pooled.  So a pool of visual objects
  // might be declared as 'public VisualObjPool extends ObjectPool'
  // and defines the create() method as 'return new VisualObj();'
  public abstract Object create();

  // Construct and initiate the pool
  public ObjectPool(int maxSize) {
    m_maxSize = Math.max(1, maxSize);

    m_Pool = new ObjPoolElement[m_maxSize];
    for (int i=0; i < m_maxSize; ++i) {
      m_Pool[i] = new ObjPoolElement();
      m_Pool[i].isAvailable = true;
      m_Pool[i].theObject  = create();
    }
  }

  public synchronized int capacity() { return (m_maxSize); }

  // Provide a method to mark all elements as available.
  public synchronized void reset() {
    for (int i=0; i < m_maxSize; ++i)
      m_Pool[i].isAvailable = true;
  }

  // Object allocation method
  public synchronized Object getObject()
  {
    Object retObj = null;        
    int numTries = 0;

    do {
      // Round robin loop through the array starting
      // with m_currentFreeIndex.  The modulo takes
      // care of wrapping around back to zero.
      for (int j = m_currentFreeIndex;
               j < m_currentFreeIndex + m_maxSize - 1; ++j) {
        int i = j % m_maxSize;
        if (m_Pool[i].isAvailable) {
          retObj = m_Pool[i].theObject;
          m_Pool[i++].isAvailable = false;
          m_currentFreeIndex = (i==m_maxSize) ? 0 : i;
          break;
        }
      }
    
      // None available, wait once, and then try one more time.
      // Otherwise, return null.
      if ((retObj == null) && (numTries < 2)) {
        ++numTries;
        try { wait(TIMEOUT_LIMIT); }
        catch (java.lang.InterruptedException ie) { /* Do Nothing */ }
      }
    } while ((retObj == null) && (numTries < 2));
    
    return retObj;
  }

  public synchronized void releaseObject( Object anObj )
    throws ArrayStoreException
  {
    boolean cleared = false;
    for (int i=0; i < m_maxSize; ++i) {
      if (m_Pool[i].theObject == anObj) {
        m_Pool[i].isAvailable = true;
        cleared = true;
        notify();
        break;
      }
    }
    if (! cleared) {
      throw new ArrayStoreException("Object does not belong to pool");
    }
  }
}




