com.hdcookbook.grin.util
Class ManagedImage

java.lang.Object
  extended by com.hdcookbook.grin.util.ManagedImage
Direct Known Subclasses:
HeadlessManagedImage, ManagedFullImage, ManagedSubImage

public abstract class ManagedImage
extends java.lang.Object

An image that is managed by the GRIN utilities. Managed images have reference counts, and a count of how many clients have asked it to be prepared. This is used to flush images once they're no longer needed. A ManagedImage instance is obtained from ImageManager.

ManagedImage contract - get() and unget()

ManagedImage instances are created and managed with a family of get() and unget() methods on ImageManager. ImageManager does reference counting based on the get() and unget() calls so it can keep track of the image instances being managed. If you ask for the same image twice (with one of the get() methods), you will get the same instance of ManagedImage, and you will of course need to balance the two calls to get() with two calls to unget() when you're done.

get() and unget() are just for creating ManagedImage instances -- they have nothing to do with loading and unloading the actual image pixmap.

The GRIN features fixed_image and image_sequence get() their images when the show is read, and unget() them when the show is destroyed.

ManagedImage contract - prepare(), unprepare() and loading

The second level of reference counting is for tracking whether the underlying image asset is not loaded, loading, or loaded. Every client of an image that wants the image to be loaded should call prepare() on the image, and each prepare call must eventually be balanced by a call to unprepare(). If a ManagedImage is "prepared" (that is, if prepare() has been called more times than unprepare(), that means that something wants the image to be loaded, but it doesn't necessarily mean that the image is loaded. Because image loading is a time-consuming information, it's useful to do as the GRIN scene graph does, and use a seperate thread (like the SetupManager thread) to do the actual image loading. This is why loading is separated from prepare/unprepare.

The following code shows one way of causing an image to actually load. Queueing a task for another thread is somewhat expensive, so if an image is already loaded, it's good to skip that step. This can be done with the following client code:


        ManagedImage mi = ...
        mi.prepare();
        if (!mi.isLoaded()) {
            Queue a task for another thread to call load() on this image
        }

 
When an image is in the prepared state, callling one of the load methods (load() or startLoading()) is necessary to make the actual image loading happen.

Eventually, when the client no longer wants the image to be loaded, it must call unprepare(). In other words, each call to prepare() must eventually be balanced by a call to unprepare(). When that final call to unprepare() is received, the image is unloaded (by calling Image.flush()).

The GRIN features fixed_image and image_sequence prepare() their images when the feature is in the active segment's active or setup clause, and they unprepare() them when leaving the segment. On a segment switch, prepare() is called for the new segment before unprepare() is called for the old segment, so images stay loaded when they should.

Sticky Images

An image can be marked as "sticky" by calling makeSticky(), and unmarked with unmakeSticky(). A sticky image won't be unloaded when the count of prepares reaches zero.

Author:
Bill Foote (http://jovial.com)

Method Summary
abstract  void draw(java.awt.Graphics2D gr, int x, int y, java.awt.Component comp)
          Draw this image into the given graphics context
abstract  void drawClipped(java.awt.Graphics2D gr, int x, int y, java.awt.Rectangle subsection, java.awt.Component comp)
          Draw the the given subsection of the image into a graphics context, without scaling.
abstract  void drawScaled(java.awt.Graphics2D gr, java.awt.Rectangle bounds, java.awt.Component comp)
          Draw this image into the given graphics context, scaled to fit within the given bounds.
 boolean equals(java.lang.Object other)
           
abstract  int getHeight()
          Get the height of this image.
abstract  java.lang.String getName()
           
abstract  int getWidth()
          Get the width of this image.
abstract  boolean hadErrorLoading()
          Tells whether or not the image had an error loading, e.g.
abstract  boolean isLoaded()
          Determine whether or not the image is currently loaded.
abstract  void load(java.awt.Component comp)
          Load this image for display in the given component, or any other component for the same graphics device.
 void makeSticky()
          Make this image "sticky".
abstract  void prepare()
          Prepare this image for display, by registering interest in having the image be loaded.
abstract  void startLoading(java.awt.Component comp)
          Start loading an image.
 java.lang.String toString()
           
 void unmakeSticky()
          Undo the effects of one call to makeSticky().
abstract  void unprepare()
          Undo a prepare.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Method Detail

getName

public abstract java.lang.String getName()

toString

public java.lang.String toString()
Overrides:
toString in class java.lang.Object

getWidth

public abstract int getWidth()
Get the width of this image. This may return 0 if the image has not yet been loaded.


getHeight

public abstract int getHeight()
Get the height of this image. This may return 0 if the image has not yet been loaded.


prepare

public abstract void prepare()
Prepare this image for display, by registering interest in having the image be loaded. In order to actually load the image, load(Component) must be called.

See ManagedImage's main class documentation under "ManagedImage contract - image loading and unloading".

See Also:
isLoaded(), load(Component), unprepare(), ManagedImage

isLoaded

public abstract boolean isLoaded()
Determine whether or not the image is currently loaded. After a call to prepare(), this method can be used to query whether or not it's necessary to arrange for load(Component) to be called.

See ManagedImage's main class documentation under "ManagedImage contract - image loading and unloading".

See Also:
ManagedImage

hadErrorLoading

public abstract boolean hadErrorLoading()
Tells whether or not the image had an error loading, e.g. because the path didn't refer to a valid image. This is always false if isLoaded() is false.


load

public abstract void load(java.awt.Component comp)
Load this image for display in the given component, or any other component for the same graphics device. The image will only be loaded if an interest in loading this ManagedImage has been registered by calling prepare(). If no interest has been registered, or if this image is already loaded, then this method will return immediately. If another thread is loading this same image, this method will wait until that image load is complete before it returns.

See ManagedImage's main class documentation under "ManagedImage contract - image loading and unloading".

Parameters:
comp - A component to use for loading the image. Clients using ManagedImage should never pass in null.
See Also:
prepare(), unprepare(), ManagedImage

startLoading

public abstract void startLoading(java.awt.Component comp)
Start loading an image. This is just like load(Component), except that it doesn't block until the image is loaded. If the image has a postive prepare() count, then sometime after startLoading(Component) is called, isLoaded() will return true (unless, of course, the caller loses interest in the image and calls unprepare()

This method is useful for loading an image asynchronously when the threading model makes polling for image load a natural thing to do. For example, if one wants to load an image while a show is running, one good way to do that is to start the loading, then poll for the completion of the loading in a once-per-frame "heartbeat" method.

See Also:
prepare(), unprepare(), load(Component), isLoaded(), ManagedImage

unprepare

public abstract void unprepare()
Undo a prepare. We do reference counting; when the number of active prepares hits zero, and the "sticky" count reaches zero, we flush the image.

See ManagedImage's main class documentation under "ManagedImage contract - image loading and unloading".

See Also:
prepare(), load(Component), makeSticky(), unmakeSticky(), ManagedImage

makeSticky

public final void makeSticky()
Make this image "sticky". An image that is sticky will be loaded the normal way when prepare()/load() are called, but it will not be unloaded when the count of active prepares reaches zero due to a call to unprepare(). The calls to makeSticky() are themselves reference-counted; an image is sticky until the sticky count reaches zero due to a call to unmakeSticky().

If an image is a tile within a mosaic, the entire mosaic will be held in memory as long as the mosaic tile is loaded.

This is equivalent to prepare(). It's given a different name to emphasize the different role of a sticky image in a GRIN show.

See Also:
unmakeSticky(), unprepare(), prepare()

unmakeSticky

public final void unmakeSticky()
Undo the effects of one call to makeSticky(). This is described in more detail under makeSticky().

This is equivalent to unprepare(). It's given a different name to emphasize the different role of a sticky image in a GRIN show.

See Also:
makeSticky(), unprepare(), prepare()

equals

public boolean equals(java.lang.Object other)
Overrides:
equals in class java.lang.Object

draw

public abstract void draw(java.awt.Graphics2D gr,
                          int x,
                          int y,
                          java.awt.Component comp)
Draw this image into the given graphics context


drawScaled

public abstract void drawScaled(java.awt.Graphics2D gr,
                                java.awt.Rectangle bounds,
                                java.awt.Component comp)
Draw this image into the given graphics context, scaled to fit within the given bounds.


drawClipped

public abstract void drawClipped(java.awt.Graphics2D gr,
                                 int x,
                                 int y,
                                 java.awt.Rectangle subsection,
                                 java.awt.Component comp)
Draw the the given subsection of the image into a graphics context, without scaling.