Previous Page TOC Next Page See Page



17


Advanced Graphics: Multimedia


by Jim Morey


Introduction: The Information Age


There is no doubt that we are in the information age. Right now, people are reading books, newspapers, magazines, journals, listening to radios, and watching TV. Information is flowing like a million rivers spreading their spider web tributaries across the world. Information is a profitable commodity with large corollary industries. There are many different distribution paths for information. A simple example is a book, which is directly bought (and read). A more complex distribution path is the use of advertisers to support TV and radio stations' programs (the information). Stations attempt to draw in the most viewers possible so that advertisers have a large pool of viewers' time to buy.

One of the newest distribution paths for information is the Internet. Information is put on the Internet to be read. Since there is such an abundance of information on the net, the information needs to be very impressive for people to want to read it. Advertisers may wish to embed their advertisements in Internet information with a high readership, just as they target radio and TV stations that have high viewerships. But regardless of whether information providers seek to sell time to advertisers with their information, they are still likely to make their information as impressive as possible to the readers.

The best way to create impressive presentations is to understand the medium. For instance, an example of misuse of a medium is a TV show that scrolls by the text of a Shakespearean play. This is unsuccessful because it is not using the benefits of the TV medium--moving picture and sound. For the text of a Shakespearean play, this interface is much worse than a book as a medium because the TV scroll does not account for the reader's speed, a reader cannot refer back to earlier passages to check forgotten characters or internal references, and such. Thus most viewers prefer to watch a mindless sitcom on TV--which more effectively uses the TV medium's potential benefits-- than read a Shakespearean play on TV, even though the play has considerably more quality content than the sitcom.

The Internet Medium


What is the Internet as a medium about? As with TV, information on the Internet can be displayed by pictures and sound. However, on the Internet, viewers have more freedom in what they view, they can interact with the information they view, and they can interact with other viewers. The Internet can use most forms of media (visual, auditory, textual, and so forth).

However, the Internet does have two serious drawbacks: bandwidth limitations and accessibility. Radio shows and songs can be heard over the Internet (with RealAudio http://www.realaudio.com), but the bandwidth problems reduce the sound quality. Similarly, TV has bandwidth problems that reduce picture quality. Books on the other hand can be comfortably downloaded but the interface is not as physically convenient as a hand-held novel. Even for interactive computer games and educational tools, CDs are better because all of the information is local. It is therefore much quicker than the Internet--again, a bandwidth problem. On the other hand, CDs are static, so there is no real interaction with the information. Accessibility is another problem as there are still many individuals and companies who lack Internet access. And once accessed, the information is not always portable.

The best use of the Internet as a medium is one that maximizes its potential benefits and minimizes the problems like bandwidth limitations and accessibility. The Internet is therefore the best medium for numerous uses, including the following:


Information Format


How can the information be displayed effectively? This question brings up the focus of this chapter. Computers are very good at manipulating and massaging data. It is important to give the computer the information in a format such that the computer can play with it and output the data in many ways. For instance, text of many Web pages can be configured by viewers. They can change the font, font size, and page size and search for key words. If, instead of using primitive text, the text is scanned in from a page in a book (maybe in the format of a bitmap), then viewers can do very little with the information. The format of the information is thus of vital importance, and choosing a format that is appropriate needs to be stressed.

When designing a format for graphics, you can learn from the flexibility shown in the text format, as in the previous example. Finally, you arrive at a strategy for making impressive graphics. Right now, there are many pages that use ImageloopItem written by James Gosling at Sun Systems or its descendants like the Animator. ImageloopItem takes a series of GIFs and flips through them, making a short animation. The Java mascot Duke is a classic example. Duke waves every once in a while--it is very impressively done. The animation consists of ten images that are 55x68 pixels. In total, it consists of approximately 20k of data and 3k of class files. I contrast this example with my program Rotator, which uses a very different technology. Rotator uses more primitive data and constructs the images from the data. The example I use has 1k of data and 16k of class files.

Rotator


All the previous discussion leads to Rotator. Rotator is a utility that displays rotating 3D shapes. The shapes are composed of colored polygons that fit together snugly. The output, the picture, is shown on a Canvas whose size is determined at run time. The main method of achieving a 3D effect with the shape is to keep the picture rotating continuously, but perspective, shading, and hidden face removal also help achieve this effect. There is a simple interface that allows the user to move the shape around. The original intent of the utility is to make geometrical objects accessible, but this utility can also be used to make 3D logos spin, bounce, and move around in fascinating patterns. Much of the appeal of these 3-D logos compared with many of the standard 3-D logos is that they are interactive, and they have infinite variety, as opposed to a fixed collection of frames.

Rotator is an extension of Canvas, which is a "component." This means Rotator inherits a large number of methods that relate to input from the keyboard and mouse, and graphics (these methods can be found in the API User's Guide). Rotator is thus in the same family as Label, Button, List, TextComponent and such, which means that it is simple to place Rotator within a complex applet like a data entry form or the game in Chapter 18, "Serious Play: Game Applets."

For instance, Listing 17.1 is a section of code that adds Rotator to a panel.

Listing 17.1. Excerpt from SimpleApplet.

Rotator rotator= new Rotator(this,solid,W,H);
new Thread(rotator).start();
rotator.background = new Color(255,200,200);
add(rotator);
show();

This code comes from SimpleApplet.java. Rotator has its own thread, making the continuous rotating independent and easy.

The classes that Rotator uses are Solid (which later gets extended to NCSolid--non-convex solid) and Omatrix. The Solid class holds all the information about the shape: faces, colors, position, and how to draw the shape. The Omatrix class holds all the information about orientations of shapes: how the shape sits in space. With these general class descriptions in mind, take a look at the code for Rotator in Listing 17.2.

Listing 17.2. Rotator.

import java.io.*;
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.lang.*;
import Solid;
import Omatrix;
/*----------------------------------------------------------------------*/
public class Rotator extends Canvas implements Runnable {
  public Color background;
  private int W,H,delay,oldx,oldy;
  private double angle,angle0=0,bounce=0;
  private boolean keep_going;
  private Solid solid;
  private Omatrix tmp,tmp2,tmp3,M0;
  private Image im;
  private Graphics offscreen;

The only public variable is background; all the other variables can only be accessed by Rotator's methods. The purpose of the variables will become clear later, as they are used.

Listing 17.3 shows the constructor (there is only one for now).

Listing 17.3. Constructor for Rotator.

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  Rotator(Applet applet,Solid solid_,int width,int height) {
    solid = solid_;
    W = width;
    H = height;
    M0 = new Omatrix();
    tmp = new Omatrix();
    tmp2 = new Omatrix();
    tmp3 = new Omatrix();
    angle0 = 0;
    delay = 100;
    resize(W,H);
    im = applet.createImage(W,H);
    background = Color.lightGray;
    setBackground(background);
    offscreen = im.getGraphics();
  }

Now, look at two major aspects of the above code. First, the reference solid is set to match the reference passed in solid_ since solid_'s scope is only the constructor; these references are now equivalent. The reference refers to the object that knows everything about the shape to be drawn. Similarly, W and H are set to the values passed in. Then four orientation matrices (Omatrix)are instantiated. M0 stands for the initial orientation, and all tmps signify temporary matrices that are used to do calculations.

Second, regarding the display, the Canvas is resized to the desired width and height, creating an image, im, that is used for double buffering. This means that instead of drawing directly to the screen, you can create an image that you can take your time drawing and then when you are finished drawing, you can throw the whole image to the screen. This stops the distracting flicker that some programs have. The image is basically a block of memory for which the object, offscreen, can manipulate with the graphics methods like fillRect, setColor, drawPoly and so forth.

The Subtleties of Update and Paint


Since this is the graphics chapter, I had better start drawing things! The three essential methods in a Canvas are paint, update, and repaint. The first information to know about these methods is how they fit in the hierarchy. Paint and update are methods called by the parent. The parent calls the Canvas' 'paint' method when the Canvas is initialized. Also, if part or all of the Canvas gets covered by another window, the parent can call the paint command to fix its appearance. If the Canvas is static, this is the only method required. If the Canvas changes, as in the case of animation, then the Canvas calls the 'repaint,' which notifies the parent that it should update the Canvas; the parent then calls the Canvas' 'update' method.

Often it is easier to redraw the whole picture than to change only what needs to be changed. The following strategy achieves this:

    public void update(Graphics g) {
    paint(g);
  }

Unfortunately, this solution introduces a flicker problem. The paint method starts by clearing the Canvas, and then numerous commands draw the picture. There can be a noticeable time lag between the execution of the first and last commands in the drawing sequence, which is distracting.

The way to solve this problem is by reversing the roles of update and paint: have paint call update. As well, you may add a double buffer. The update is likely called more frequently than the paint, so it makes sense for it to be the dominant method of the two.

Listing 17.4 shows Rotator's paint and update methods.

Listing 17.4. Rotator's paint and update methods.

../* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void paint(Graphics g) {
    update(g);
  }
  public void update(Graphics g) {
    offscreen.setColor(background);
    offscreen.fillRect(0, 0, W, H);
    solid.Draw(offscreen,(int)(W/2),(int)(H/2),bounce);
    g.drawImage(im, 0, 0, null);
  }

This simple update draws a filled rectangle to offscreen (which effectively clears anything that is on the off screen) and then draws the solid. The offscreen image, im, is then drawn to g. This g is a graphics context like offscreen, but it is beyond the scope of this class; it must be supplied by the parent.

In the update method of Rotator, there is little that can change except the variable bounce. Another value that may change--although it is not readily apparent--is the orientation matrix of the shape that is encapsulated in the object, solid. In the run method of Rotator, repaint is called. The update then draws the picture using the current bounce and shape orientation values. If they have changed since the last update, the current picture may be drastically different from the previous picture.

Rotator on the Run


The run method of Rotator is conceptually simple, as shown in Listing 17.5. It updates the height and the orientation of the shape and then redraws the shape. It then loops until it is told to stop.

Listing 17.5. Run method for Rotator.

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void run(){
    keep_going = true;
    angle=0;
    while(keep_going){
      /* .. modify bounce and solid.orient .. */
      angle += 0.1;
      tmp3.Rotation(1,2,angle);
      tmp2.Rotation(1,0,angle*Math.sqrt(2)/2);
      tmp.Rotation(0,2,angle*Math.PI/4);
      solid.orient = tmp3.Times(tmp2.Times(tmp.Times(M0)));
      bounce = Math.abs(Math.cos(0.5*(angle+angle0)))*2-1;
      repaint();
      try {Thread.sleep(delay);} catch (InterruptedException e){}
    }
  }

Referring to the loop in the above code, solid.orient (the shape's orientation) is a function of angle, with M0 as the initial value. Bounce (the shape's height), however, is a function of angle, with angle0 as its initial value. The values of solid.orient exhibit interesting behavior: theoretically, the orientation never repeats. Rotation and Times methods are discussed later in the chapter.

After the request to update via the repaint command, the run thread sleeps for a while to give up the CPU for other threads. This process continues as long as keep_going is true.

A simple and logical interface is essential to any interactive application. Now look at a simple interface for Rotator that gives the user control of the shape's orientation, rather than leaving the shape to tumble in accordance with the convoluted function. The interface design is this: the tumbling stops when users press a mouse button. They may then drag the mouse to rotate the shape in chosen directions at will. Letting go of the mouse button returns the shape to its tumbling.

The first step in designing this interface is to stop the run thread when a mouse button is pressed, as shown in Listing 17.6.

Listing 17.6. Rotator: mouseDown routine.

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public boolean mouseDown(java.awt.Event evt, int x, int y) {
    keep_going = false;
    try {Thread.sleep(delay*2);} catch (InterruptedException e){}
    M0 = solid.orient;
    angle0 += angle;
    angle = 0;
    oldx = x;
    oldy = y;
    return true;
  }

The first line ensures that the run process eventually finishes. The sleep command waits to make sure this is so. The current value of the shape's orientation is saved, as it becomes the new initial value. When the tumbling resumes, it thus resumes from the current orientation. The variables oldx and oldy record the position where the mouse has been pressed; this is used to determine how much the mouse moves during a mouseDrag. The "return true" tells the Rotator's parent that the mouseDown event has been handled, so there is no need for another thread or process to handle the mouseDown event.

The responsibility of returning the shape to the tumbling shape falls on the mouseUp method, as shown in Listing 17.7. But all it has to do is start a new run thread.

Listing 17.7. Rotator: mouseUp routine.

/* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public boolean mouseUp(java.awt.Event evt, int x, int y) {
    new Thread(this).start();
    return true;
  }

The mouseUp event starts the shape tumbling again by starting this thread, that is, starting the run method of this object (Rotator).

Finally, you arrive at the sensitive part of this interface. The mouseDrag method allows the user to manipulate the shape. You use the difference between the old and new mouse position to calculate how you want the shape moved.

Listing 17.8. Rotator: mouseDrag routine.

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public boolean mouseDrag(java.awt.Event evt, int x, int y) {
    tmp2.Rotation(0,2,(x - oldx) * Math.PI/ solid.W);
    tmp.Rotation(1,2,(oldy - y) * Math.PI/ solid.H);
    M0 = tmp.Times(tmp2.Times(M0));
    solid.orient = M0;
    oldx = x;
    oldy = y;
    repaint();
    return true;
  }

The first line of this method causes the shape to rotate in the XZ-plane by an angle that relates to the drag motion in the x direction, the angle being equal to (x-oldx)*constant. Similarly, the second line rotates in the YZ-plane. This case differs from the previous one by a minus sign; this is because the origin is in the upper left corner, and traveling down the screen corresponds to an increase in the y value. Since M0 always refers to the current orientation during mouseDrag, when the mouseUp is called the shape begins tumbling again starting with the current orientation.

Although this finishes the brief discussion of this interface, the next chapter looks more deeply into good interfaces.

Omatrix and Solid Classes


In the following section, there are some difficult mathematical concepts, so rather than going through every detail, a general picture of what is happening is presented. For those who like more details, you may check the CD and go over the code that is there. Part of the appeal of object-oriented code is that the programmer doesn't need to understand all of the code to effectively use it. For this reason, big projects benefit a great deal by using object-oriented programming languages.

Omatrix


The basis of the Omatrix method used by Rotator is that shapes are defined in terms of points, in the form (x, y, z). For a simple visualization of this form, imagine x as a horizontal axis across the width of the screen, y as a vertical axis along the length or height of the screen, and z as an axis along a direction perpendicular to the screen, with one end pointing in toward the screen and the other end pointing out toward the user. Call this the standard orientation.

The class Omatrix describes an orientation. The way it does this is it replaces the standard x-y-z axes with new axes. These new axes are 3 vectors; call them x'-y'-z'. You store x'-y'-z' as the columns of a matrix. For x'-y'-z' to make sense as an orientation, these vectors must each have a unit length, and must also be perpendicular to each other-- like the standard orientation (1,0,0)-(0,1,0)-(0,0,1).

In Listing 17.9, you have the initial code for the Omatrix class. It mainly concerns itself with the 3-by-3 matrix. When an Omatrix is constructed, it is set to the standard axis.

Listing 17.9. First section of the Omatrix class.

public class Omatrix{
  public double[][] M;
  private int row,col,k,l;
  Omatrix(){
    M = new double[3][3];
    Assign(1,0,0,0,1,0,0,0,1);
  }
  /*  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
  public void Assign(double a, double b, double c,
                     double d, double e, double f,
                     double g, double h, double i ){
    M[0][0] = a;
    M[1][0] = b;
    M[2][0] = c;
    M[0][1] = d;
    M[1][1] = e;
    M[2][1] = f;
    M[0][2] = g;
    M[1][2] = h;
    M[2][2] = i;
  }

This matrix, M, is the data part of the class. The other variables declared are row, col, k, and l. These dummy variables are used often. In general, it is safer to have dummy variables declared in the methods that require them, but this setup works here because no two methods are called at the same time.

In the Omatrix constructor, the space for M is allocated, and the method Assign sets the initial value of M equal to the standard orientation.

The following two methods are the major tools used by Rotator to change the orientation: Rotation and Times.

Rotation

The method Rotation replaces the matrix, M. It is replaced with a matrix that represents an orientation different from the standard orientation by a rotation in one of the coordinate planes by "angle" (in radians). Here, i and j are the numbers of the axes that get changed. For instance, 0 and 1 represent that the change occurs in the first and second columns--the x and y axis. Rotation(0,1,0.5) sets the orientation, M, to the following:

Orientation Matrix

 cos(0.5)  sin(0.5)  0
-sin(0.5)  cos(0.5)  0
    0         0      1

Figures 17.1 and 17.2 show the result.

Figure 17.1. The some shapes viewed with the standard basis.

Figure 17.2. The same shapes after of a rotation of half a radian.

Listing 17.10 shows how "rotation" works.

Listing 17.10. Rotation method in Omatrix.

 /*  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
  public void Rotation (int i, int j, double angle) {
    Assign(1,0,0,0,1,0,0,0,1);
    M[i][i] = Math.cos(angle);
    M[j][j] = M[i][i];
    M[i][j] = Math.sin(angle);
    M[j][i] = -M[i][j];
  }

Times

The next method, shown in Listing 17.11, allows you to make changes in the orientation relative to any given orientation. In matrix notation, this operation is multiplication or Times. Unlike the method Rotation, Times returns a new orientation object rather than changing M. This turns out to be convenient, as seen in Rotator. Notice that every instance Times is called, a new Omatrix object is created. Happily, however, garbage collection is automatic, so the old Omatrix objects are cleared away.

Listing 17.11. Times method of Omatrix.

/*  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
  public Omatrix Times(Omatrix N){
    Omatrix temp = new Omatrix();
    for (row=0; row < 3; row++) {
      for (col=0; col <3; col++) {
        temp.M[row][col] = 0.0;
        for (k=0; k < 3; k++) {
          temp.M[row][col] += M[row][k] * N.M[k][col];
        }
      }
    }
    return temp;
  }

In Figure 17.3, you can see the result of two rotations composed by using Times. Combining the methods Rotation and Times together allows you to make any orientation.

Figure 17.3. An orientation constructed by combining two simple rotations.

This completes the explanation of the Omatrix methods used by Rotator. However, there are several more methods to Omatrix, some of which are quite interesting. They are used in the next chapter, "Serious Play: Game Applets."

Solid


Next is an explanation about the Solid class. This class holds all of the shape's information. In general, the shapes are made up of faces; these faces are all flat. The faces are polygons that have only one side, or plane, that is visible. All the faces put together form the outside of a convex shape. In other words, the polygons are all joined along their sides to form one shape, for which there is a perspective that only sees the planes that face upwards. The upward-facing planes vary with the shape's orientation. This description of a shape is very narrow; it will be extended when NCSolid is described, but for now, these restrictions help draw the shape without a sorting routine, and without redrawing the same areas of the picture.

The method CalcScrPts (calculate screen coordinates) is a routine that takes the orientation of the shape in space and computes all the screen coordinates. First, it computes the points relative to the new basis, then it projects each of the points to the screen. This means that you can draw a wire frame diagram of the shape by connecting all the appropriate screen coordinates. This is a bad idea, however, since the back and front of the object often become hard to identify.

Instead, the Draw method uses faceUp to decide which faces it draws. The faceUp method returns a true if the face is pointing upwards; this is where the one-sidedness of the face is important. The faces have a top that you want drawn, and a bottom that you don't want drawn (as you never see the bottoms). Since the shape is convex, all the hidden faces return a false value for faceUp, and therefore don't need to be drawn. Thus all of the hidden face removal is taken care of. The getColour method then computes the shading, and the polygons are drawn with DrawPoly.

Since this Draw method is fairly specific, there is another Draw method that is more general, but slower. This Draw method is part of the class NCSolid in Listing 17.12, which extends Solid.

Listing 17.12. The class NCSolid.

import java.io.*;
import java.awt.*;
import Solid;
public class NCSolid extends Solid{
  private int order[],min;
  NCSolid (InputStream is, int wid, int heig, int ncolour_)
    throws IOException{
    super(is, wid, heig, ncolour_);
    order = new int[nface];
  }
  /*  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
  public void Draw(Graphics offscreen,int x0,int y0,double z){
    CalcScrPts((double)x0,(double)y0,z);
    /* .. put in a list all the faces that are point up.. */
    i=0;
    for (f=0;f<nface;f++)
      if (faceUp(f)) {
        order[i] = f;
        i++;
      }
    /* .. find the face farthest away and draw it 'i' times .. */
    for (j=0;j<i;j++){
      min = j;
      for (k=j+1;k<i;k++)
        if (rotPts[order[k]+nface][2]<rotPts[order[min]+nface][2]) min =k;
      if (min !=j) {
        f = order[min];
        order[min] = order[j];
      } else f = order[j];
      for (k=1;k<faces[f][0]+1;k++)
        DrawPoly(offscreen,faces[f][k],getColour(f,k));
    }
  }
}

The following line is a check to see which one of the faces is closer to the screen:

if (rotPts[order[k]+nface][2]<rotPts[order[min]+nface][2]) min =k;

This line is used to sort the faces into an order that delineates farthest to closest.

Here are some examples of Rotator being used. Figure 17.4 uses Solid. Figure 17.5 uses NCSolid.

Figure 17.4. A sample of SimpleApplet (cubeR.html).

Figure 17.5. A sample of SimpleApplet2 (tetraR.html).

Summary: The Bottom Line Is Bandwidth


How economical has the bandwidth been so far? Table 17.1 shows the data for the cube.

Table 17.1. The breakdown of data needed to be transferred with SimpleApplet.

Data Size SimpleApplet.class 1885 bytes Rotator.class 3010 bytes Solid.class 6274 bytes Omatrix.class 4385 bytes cube.dat 947 bytes Total 16501 bytes = 16.5k

Table 17.2 shows the data for the tetrahedron with the center missing (the second image).

Table 17.2. The breakdown of data needed to be transferred with SimpleApplet2.

Data Size SimpleApplet2.class 1889 bytes Rotator.class 3010 bytes Solid.class 6274 bytes NCSolid.class 1197 bytes Omatrix.class 4385 bytes tetra.dat 1451 bytes Total 18206 bytes = 18.2k

Since the bandwidth has been used sparingly so far (under 20k), go ahead and make Rotator more interesting by adding a background image, and call it ImageRotator (see Listing 17.13). Following the NCSolid example of sub-classing, add more data into the constructor, and replace the Draw routine. Just as the Solid is supplied to Rotator from Rotator's parent, the Image for Rotator's background is also supplied from the parent.

Listing 17.13. The class ImageRotator.

/*----------------------------------------------------------------------*/
public class ImageRotator extends Rotator implements Runnable {
  Image gif;
  int gifx,gify;
  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  ImageRotator(Applet applet,Solid solid_,Image gif_,int width,int height) {
    super(applet,solid_,width,height);
    gif = gif_;
  }
  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void update(Graphics g) {
    offscreen.setColor(background);
    offscreen.fillRect(0, 0, W, H);
    gifx = (int)((W - gif.getWidth(null))/2);
    gify = (int)(((H - gif.getHeight(null))/2)*(1-bounce));
    offscreen.drawImage(gif,gifx, gify, null);
    solid.Draw(offscreen,(int)(W/2),(int)(H/2),bounce);
    g.drawImage(im, 0, 0, null);
  }
}

The image that can be passed follows the general description of an Image. In the example of SimpleApplet3 in Listing 17.14, you will pass in an Image that is created from a GIF.

Listing 17.14. SimpleApplet3's inclusion of Rotator.

URL here = this.getDocumentBase();
...
      Image gif = getImage(new URL(here,image));
      add(new Label(title,Label.CENTER));
      ImageRotator rotator= new ImageRotator(this,solid,gif,W,H);
...

Figure 17.6 shows the program's output.

Figure 17.6. A sample of SimpleApplet3 (tetraRB.html).

Table 17.3 shows how much information is sent over the Net.

Table 17.3. The breakdown of data needed to be transferred with SimpleApplet3.

Data Size SimpleApplet3.class 2025 bytes Rotator.class 3010 bytes ImageRotator.class 1265 bytes Solid.class 6274 bytes NCSolid.class 1197 bytes Omatrix.class 4385 bytes tetra.dat 1451 bytes something.gif 92375 bytes Total 111982 bytes = 112.0k

Even in this small example that uses only one GIF, the GIF is a large portion of what has been sent. Notice as well, the pictures are no longer scaleable: when the size of the Canvas is changed, the shape is scaled, but the GIF has a fixed resolution. This takes away some of the flexibility. Instead of using the GIF, the graphics primitives can be used to create the background Image. This, no doubt, uses less information than needs to be sent, but the information is in a format that allows the computer to manipulate it. Thus the image also comes alive and dances and the viewer doesn't have to wait for everything to download.

So the real goal to graphics programming is to find the happy medium for bandwidth, flexibility, and really cool graphics. This must be solved by carefully choosing the format of the graphics information and pushing the format to its limit. Reflect back on the 92k GIF and think of all the wonderful Java code and data that can be downloaded in the same time.

Previous Page Page Top TOC Next Page See Page