VRML, 3-D Graphics, Simulation

How can you display text on the screen?


(Submitted by Nelson Yu)
The simplest way to draw a string is to do it in paint() i.e

public void paint(Graphics g)
{
   // This will draw the string in a red "TimesRoman" font
   g.setColor(Color.red);
   g.setFont(new Font("TimesRoman", Font.BOLD, 12));
   // This draws the string given the x,y co-ordinates of the _baseline_
   // Don't think the point you give it is the upper-left corner
   g.drawString("Hi There", 10, 50)
}

You can override paint in a Panel, Frame, Dialog, etc.. I would sub-class a Panel. Thus not messing around with the Frame's paint routine.

public class MyPanel extends Panel
{
...
...
   public void paint(Graphics g)
... 
}

Note: "Graphics" is abstract and thus you can not just instantiated. I.e.,

Graphics g = new Graphics() 
g.drawString(...);

is illegal in Java. Thus the easiest way to retrieve a Graphics instance is in paint(), update(), etc. But if you have any instance of Graphics you should be able to draw a string.


How can you draw a line?


(Submitted by Nelson Yu)
drawLine(x1, y1, x2, y2)
is a method in the Graphics class, so you'll need an instance of it. You can't create one yourself since it is abstract. I.e.

// g is an instance of Graphics
g.drawLine(10, 10, 100, 100);

// This is a nice little app I wrote for my "Introduction to the AWT"
// document. (A newbie guide before I overload them with information 
// with my new (and IMPROVED) "AWT Tutorial").
// It draws 50 squares within each other

import java.awt.*;

public class FiftySquares extends Frame
{
	float xA, yA, xB, yB, xC, yC, xD, yD,
			xA1, yA1, xB1, yB1, xC1, yC1, xD1, yD1,p,q,r;
	int i;
	int x_center, y_center;

	static final int H_SIZE = 300;
	static final int V_SIZE = 300;

	public FiftySquares()
	{
		q = (float)0.05;
		p = 1 - q;
		r = (float)0.95 * H_SIZE;

		x_center = H_SIZE/2;
		y_center = V_SIZE/2;

		resize(H_SIZE, V_SIZE);
		show();
	}

	public void paint(Graphics g)
	{
		xA = xD = x_center - r;
		xB = xC = x_center + r;
		yA = yB = y_center - r;
		yC = yD = y_center + r;

		for(i=0; i<50; i++)
		{
			g.drawLine((int)xA, (int)yA, (int)xB, (int)yB);
			g.drawLine((int)xB, (int)yB, (int)xC, (int)yC);
			g.drawLine((int)xC, (int)yC, (int)xD, (int)yD);
			g.drawLine((int)xD, (int)yD, (int)xA, (int)yA);
			xA1= p*xA+q*xB;yA1= p*yA+q*yB;
			xB1= p*xB+q*xC;yB1= p*yB+q*yC;
			xC1= p*xC+q*xD;yC1= p*yC+q*yD;
			xD1= p*xD+q*xA;yD1= p*yD+q*yA;
			xA=xA1;xB=xB1;xC=xC1;xD=xD1;
			yA=yA1;yB=yB1;yC=yC1;yD=yD1;
		}
	}

	public static void main(String args[])
	{
			new FiftySquares();
	}
}


How can you fill a region?


(Submitted by Andreas, P. Gregoriou)
To fill a region you must call the fill method. For example, say that you want to fill a rectangular region. This is good to be implemented in the paint method.
public void paint(Graphics g)
{
 g.drawRect(100, 100, 70, 80); // define the area 
 g.SetColor(Color.blue);       // define the fill color
 g.fillRect(100,100,70,80);    // fill it with red color
 g.SetColor(Color.black);      // change color so you are able to write
 							   // in the (blue) area if you want, and be visible
 
}
(Submitted by Maria Winslow)
There are also fill methods on the following shapes; all can be found in java.awt.Graphics.
fill3DRect()
fillArc()
fillOval()
fillPolygon()
fillRect()
fillRoundRect()
If you want a filled circle, use fillRoundRect() with an arcWidth=width and arcHeight=height.

How can you display an image on the screen?


(Submitted by Vivek Pabby)
The folowing code in the init() method of an applet will get an image into an Image object. The image can be loaded only if the getDocumentBase() is valid i.e. - works well with an applet. Will not load images from arbitrary URLs

public void init() {

	Image image1 = null;

	image1 = getImage(getDocumentBase(), "\somepath\xyz.gif")

	//  other code .....
}

public void paint(Graphics g) {

	g.drawImage(image1, 0, 0, this);
	//  other code .....
}

How can you clip a (rectangular and other) region?


(Submitted by Jay Nelson)
If you clip a graphics object, you must dispose of it before attempting to clip in a different way or nothing will be drawn:
Graphics g = this.getGraphics();
g.clipRect(LeftPoint, TopPoint, RectWidth, RectHeight);
g.drawImage(Img, X, Y, this);
g.dispose();
g = this.getGraphics();
g.clipRect(LeftPoint2, TopPoint2, RectWidth2, RectHeight2);
g.drawImage(Img2, X, Y, this);
g.dispose();
(Submitted by Paul Walker)
This is how you clip a rectangular region. This draws a cross on the full screen with and without clipping so you can see the effect.

import java.awt.*;
import java.applet.Applet;

// Demonstrates using clipRect to clip a rectangular region

public class ClipEG extends Applet
{
  public void init()
  {
    resize(300,300);
  }

  public void paint(Graphics g)
  {
    // Draw a diagonal cross without clipping
    g.drawLine(0,0,300,300);
    g.drawLine(300,0,0,300);
    // Draw a vertical cross with clipping
    Graphics gsave = g.create();
    g.clipRect(100,100,100,100);
    g.setColor(Color.blue);
    g.drawLine(0,150,300,150);
    g.drawLine(150,0,150,300);
    // reset and check.  Note that we can't naievely reset
    // g.clipRect, it seems, since the clipRect is an intersection.
    g = gsave;
    g.setColor(Color.red);
    g.drawLine(0,149,300,149);
    
  }
}
(Submitted by Glenn Murray)
For a rectangular region:

  Graphics g = this.getGraphics();
  Graphics clipg = g.create();
  clipg.clipRect(LeftPoint, TopPoint, RectWidth, RectHeight);
  clipg.drawImage(Img, X, Y, this);

The image is "placed" at the specified X,Y location in the drawImage call, but the only part of the image which is painted, is that area which lies in the area specified by the clipRect call.

How can you drag an image around the screen


(Submitted by Thomas M. Miller)
import java.awt.*;
import java.applet.Applet;

public class MovingImage extends Applet
{
    int Ix, Iy;
    Image image1=null;

    public void init()
    {
            image1 = getImage(getDocumentBase(), "F1.gif");
    }

    public void paint(Graphics g)
    {
            if(image1 != null)
                g.drawImage(image1, Ix, Iy, this);
    }

    public boolean mouseDrag(Event evt, int x, int y)
    {
            Ix = x;
            Iy = y;
            repaint();
            return true;
    }
}

How can you retrieve the regions that need updating from a Graphic object when paint() is called?


(Submitted by "Julie")
public void paint(Graphics g)
{
Rectangle r = g.getClipRect();

    // r contains the clip rect. Do something
    // like see if it intersects my expensive-to-draw
    // thing or not
}
(Submitted by Brian Miller)
Be forwarned that Graphics.getClipRect() will return null if the entire Component or Image is to be redrawn.

How can you display CMYK colors?



How can I draw offscreen using double-buffering?


(Submitted by Rudolf Scheurer)
The following answer I found in newsgroup comp.lang.java:

From hvvliet@inter.nl.net (Hanpeter van Vliet)...

How to do Offscreen drawing. This technique is also described on the Java
home site, albeit in terms of alpha3 API's. A search for "flash" will yield
those samples.

Here's the list of it in beta1 terms. It uses a boolean "doubleBuffer"
switch so you can see how the code differs from the standard case:

class MyApplet extends Applet
{
    ....
    private boolean doubleBuffer=true; // or false of course
    private Image buf;                 // bitmap for double buffering
    private Graphics gBuf;             // gc to draw on bitmap

    public void init()
    {
        ....
        if (doubleBuffer)
        {
            Dimension d = size();
            buf = createImage(d.width, d.height);
            gBuf = buf.getGraphics();
        }
    }

    public void destroy()
    {
        ....
        if (doubleBuffer)
            gBuf.dispose();
    }

    protected void paintApplet(Graphics g)
    {
        // pre-clear the bitmap or the applet
        // remove this if you paint the entire area anyway
        Dimension d = size();
        g.setColor(getBackground());
        g.fillRect(0, 0, d.width, d.height);

        ....code that was originally in paint()...
    }

    public void paint(Graphics g)
    {
        if (doubleBuffer)
        {
            paintApplet(gBuf);
            g.drawImage(buf, 0, 0, this);
        }
        else
        {
            paintApplet(g);
        }
    }

    public void update(Graphics g)
    {
        // override this because the default implementation always
        // calls clearRect first, causing unwanted flicker
        paint(g);
    }
}
    
-- hanpeter


How does one get and set individual pixels in an Image?


(Submitted by Jeff Marin)
The following code will take m_Image and copy its bytes into pix_src. You can then manipulate these bytes and create a new image using MemoryImageSource. I am tying to put together a RotatingImage class that would use this code. If anyone has suggestions/experiences about manipulating images in Java, please email me: jmarin@superlink.com
// wait for the whole image to load (look at imageUpdate)

while(m_width == -1)
	m_width = m_Image.getWidth(null);
m_height = m_Image.getHeight(null);

pix_src = new int[m_width*m_height];

m_pg = new PixelGrabber(
	m_Image, 0, 0, m_width, m_height, pix_src, 0, m_width);
m_Image.getSource().addConsumer(m_pg);
boolean stat = false;

try
{
	stat = m_pg.grabPixels();
}
catch(InterruptedException e)
{
	Debug("interrupted waiting for pixels");
	return;
}

if((m_pg.status() & ImageObserver.ABORT) != 0)
{
	Debug("image fetch aborted or errored");
	return;
}

//  m_Image bytes are now pix_src!
(Submitted by Garth A. Dickie)
If an image was created with a call to
Component.createImage( width, height )
or
Toolbox.createImage( width, height )
then you can set individual pixels by creating a Graphics object which draws to the image:
public static void setOnePixel( Image image, int x, int y, Color color ) {
	Graphics g = image.getGraphics( );
	g.setColor( color );
	g.fillRect( x, y, 1, 1 );
	g.dispose( );
}
For reading the pixels of an image, or modifying an image which you obtained from a URL, you need to use the ImageProducer, ImageConsumer, ImageFilter classes from the package java.awt.image. There is an example ImageFilter provided with the awt (for changing the ColorModel). The documentation seems good.

How do I draw a dithered or a stippled polygon, rectangle etc.?


(Submitted by Garth Dickie)
To draw a stippled rectangle, create a 1 pixel wide by 1 pixel high offscreen image whose pixel is set to the color you would like. Then draw it to the screen with scaling. The drawImage call with dither your single color into the available onscreen colors.

Here is an applet which does this:

import java.awt.*;
import java.awt.image.*;
import java.applet.Applet;

public class FuzzyTestApplet extends Applet {
    private Color    rectangleColor = new Color( 250, 240, 230 );
    private Image    solidImage;

    public void init( ) {
        solidImage = createOnePixelImage( rectangleColor );
    }

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

    public void paint( Graphics g ) {
        g.drawImage( solidImage, 0, 0, size( ).width, size( ).height, this );
    }

    public Image createOnePixelImage( Color color ) {
        byte[ ] red   = { ( byte ) color.getRed( ) };
        byte[ ] green = { ( byte ) color.getGreen( ) };
        byte[ ] blue  = { ( byte ) color.getBlue( ) };
        byte[ ] pixel = { 0 };

        IndexColorModel colorModel =
            new IndexColorModel( 8, 1, red, green, blue );

        MemoryImageSource source =
            new MemoryImageSource( 1, 1, colorModel, pixel, 0, 1 );

        return createImage( source );
    }
}

How can I avoid flicker by displaying a background graphic once, and then just modifying the foreground in response to events?


(Submitted by Cliff Berg)
The first thing to do is to override the method update() for the canvas (or whatever component you are displaying the image in). The default behavior of update() is that it first clears the display: this causes flicker.

Next, do not put all of your drawing code into paint(). Only put in there the code that is necessary to recreate the canvas when the window is minimized and then restored - that is the purpose of paint(). One approach is to use "double-buffering", in which you apply all drawing operations twice whenever you do them: (1) to the canvas; and (2) to the buffer. Then, in paint(), simply restore the canvas with the drawImage() method. An example of a paint() method that does this is:

public void paint(Graphics g)
{
	// Check if window was just resized
	Dimension d = size();
	if ((d.width != buffer.getWidth(this)) || 
			(d.height != buffer.getHeight(this)))
	{
		{
		// Save the currently displayed image
		Image temp = buffer;

		// Reallocate a buffer to match the new size
		setupBuffer(d.width, d.height);

		// Restore the image to the new buffer
		bg.drawImage(temp, 0, 0, this);
		}
		System.gc();	// force the old buffer to be free'd
	}

	// Restore the image to the screen -- this is the key part
	getGraphics().drawImage(buffer, 0, 0, this);
}

How do I change the size of the "pen" when drawing lines?


(Submitted by Jeff Harrington)
In Java 1.0, you cannot change the width of the pen. You'll have to draw multiple parallel lines or fill a polygon.
(Submitted by Cliff Berg)
Here is an algorithm I wrote for doing that. I hope it's right - it seems to work!

public void drawLine(
	Graphics g, int startX, int startY, int endX, int endY, int wid, Color col)
{
	// Make this reflect the current width and color...
	g.setColor(col);

	//
	// We draw a thick line by computing the four corners of an equivalent
	// diagonal rectangle, and filling it.

	//
	// Compute the corner points of the rectangle to fill
	//

	// The x and y deltas from the start to the end of the line...
	int dX = endX - startX;
	int dY = endY - startY;

	// The length of the line...
	double D = Math.sqrt(dX * dX + dY * dY);

	// The ratio of half the line thickness to the length of the line...
	double scale = (double)(wid) / (2 * D);

	// The x and y increments from an endpoint needed to create a rectangle...
	double ddx = -scale * (double)dY;
	double ddy = scale * (double)dX;
	if (ddx > 0) ddx += 0.5; else ddx -= 0.5;		// round off
	if (ddy > 0) ddy += 0.5; else ddy -= 0.5;		//  "
	int dx = (int)ddx;
	int dy = (int)ddy;

	// Now we can compute the corner points...

	int xPoints[] = new int[4];
	int yPoints[] = new int[4];

	xPoints[0] = startX + dx;
	yPoints[0] = startY + dy;

	xPoints[1] = startX - dx;
	yPoints[1] = startY - dy;

	xPoints[2] = endX - dx;
	yPoints[2] = endY - dy;

	xPoints[3] = endX + dx;
	yPoints[3] = endY + dy;

	// Fill the rectangle, effectively drawing a thick line
	g.fillPolygon(xPoints, yPoints, 4);
}

Given a screen image, how does one "copybits" a polygonal region from one place in the applet window to another?



How do you draw in only one of the A/R/G/B-channels of an image?
E.g. draw a text string in the alpha channel only?



How do I rotate images along different directions as the time changes?


(Submitted by Dean Jones)
I have done this using PixelGrabber and MemoryImageSource. Imagine a 50x50 image to be rotated by 90 degrees:
Image img = createImage(...);

int buffer[] = new int[50 * 50];
int rotate[] = new int[50 * 50];

PixelGrabber grabber = new PixelGrabber(img, 0, 0, 50, 50, buffer, 0, 50);

try
{
	grabber.grabPixels();
}
catch(InterruptedException e)
{
...
}

for(int y = 0; y < 50; y++)
{
	for(int x = 0; x < 50; x++)
	{
		rotate[((50-x-1)*50)+y] = buffer[(y*50)+x];
	}
}
Image rot = createImage(new MemoryImageSource(50, 50, rotate, 0, 50));

How can you scroll an image across the screen without leaving a trail or having to re-draw the enture background each time (sprite animation)?



How do I resize a GIF when using getImage and then drawImage?


(Submited by M. K. Kwong)
One form of the drawImage method lets you specify the width wd and height ht (in pixels) of the image to be drawn. The displayed image will then be scaled to those dimensions. An example:

Image img = getImage("picture.gif");
g.drawImage(img,0,0,wd,ht,this);

where g is the Graphics usually found in the paint(Graphics g) method.


How do I get the size a text string will be onscreen?


(Submitted by M. K. Kwong)
This is related to the question above on right-adjusting strings. To get the width of a string tx, use
int tw = g.getFontMetrics().stringWidth(tx);
To get its height use (note that you do not need to mention the string tx this time):
int th = g.getFontMetrics().getHeight();
Both commands must be used within the Context of a Grahpics g, such as in paint(Graphics g). Alternatively, if you know the Font f to be used for the string, you can use
int tw = getFontMetrics(f).stringWidth(tx);
without involving g.

How do I do (quick) bitmap style collision detection? (For interactive animations.)



How do I generate a simple VRML scene from Java?