MapCanvas.java

/*
  $RCSfile: MapCanvas.java,v $
  $Id: MapCanvas.java,v 1.6 1998/11/30 02:21:07 devnull Exp $
  by Lee Wilson, http://www.ad1440.net/~devnull
  Development started on 1998 10 01
  (c) Devnull Software, LLC. (http://www.devnullsoftware.com)
*/

package com.devnullsoftware.javaterrain;

/**
 Performs the actual drawing of the map.

 @author Lee Wilson
 @version 1.0
*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MapCanvas extends JPanel  {
  //-------------------------------------------------------------------
  // Global Constants
  //
  public static final int [] HEXSIZE = {
    9,13,25,49,99
  };
  public static final int VIEW_TERRAIN = 0;
  public static final int VIEW_TEMPERATURE = 1;
  public static final int VIEW_RAINFALL = 2;
  public static final int VIEW_ELEVATION = 3;


  //-------------------------------------------------------------------
  // Instance Variables
  //
  private Map pMap = null;
  int iZoomLevel = 2;
  int iViewMode = VIEW_TERRAIN;
  Dimension pPreferredSize = new Dimension (300,300);
  MapWindow pMapWindow = null;
  private Dimension pCanvasSize = new Dimension ();
  private SmallViewPanel pSmallView = null;


  //-------------------------------------------------------------------
  // Constructors
  //
  MapCanvas (Map m, MapWindow pMapWindow)  {
    super (true);
    pMap = m;
    this.pMapWindow = pMapWindow;
    init ();
  }

  private void init ()  {
    Hex.rescaleImages(pMap.pParams.pTerrainImage, iZoomLevel);
    pSmallView = new SmallViewPanel();
  }


  //-------------------------------------------------------------------
  // Accessors & Mutators
  //
  public Component getSmallView ()  {
    return pSmallView;
  }

  public void setSmallViewSize(int width, int height)  {
    pSmallView.setSize(width, height);
    pSmallView.setPreferredSize(new Dimension(width, height));
  }

  public Dimension getSmallViewSize()  {
    return pSmallView.getSize();
  }

  public void setSmallViewPort (Rectangle pRect)  {
    Rectangle pNewRect = new Rectangle();
    Dimension pSmallSize = getSmallViewSize();
    float fXScale = (float)pCanvasSize.width/(float)pSmallSize.width;
    float fYScale = (float)pCanvasSize.height/(float)pSmallSize.height;
    pNewRect.x = (int)((float)pRect.x / fXScale);
    pNewRect.y = (int)((float)pRect.y / fYScale);
    pNewRect.width = (int)((float)pRect.width / fXScale);
    pNewRect.height = (int)((float)pRect.height / fYScale);
    pSmallView.setViewRect(pNewRect);
    pSmallView.repaint();
  }

  public void zoomIn ()  {
    if (iZoomLevel < (HEXSIZE.length-1))  {
      iZoomLevel++;
      Hex.rescaleImages(pMap.pParams.pTerrainImage, iZoomLevel);
      repaint();
    }
  }

  public void zoomOut ()  {
    if (iZoomLevel > 0)  {
      iZoomLevel--;
      Hex.rescaleImages(pMap.pParams.pTerrainImage, iZoomLevel);
      repaint();
    }
  }

  public int getViewMode ()  {
    return iViewMode;
  }

  public void setViewMode (int i)  {
    iViewMode = i;
    repaint();
  }


  //-------------------------------------------------------------------
  // Security
  //


  //-------------------------------------------------------------------
  // Overridden Methods
  //
  public Dimension getPreferredSize()  {
    return pPreferredSize;
  }

  public void paintComponent (Graphics g)  {
    int x,y;
    int i;
    float fHeightCenter, fHeightAdjustment;
    float fWidthAdjustment, fWidthCenter;
    float fHexWidth, fHexHeight;
    int xPoints[] = new int[6];
    int yPoints[] = new int[6];
    Hex pTempHex, pTempNeighborHex;

    fHexWidth = fHexHeight = (float)HEXSIZE[iZoomLevel];
    fWidthCenter = fHexWidth / 2.0f;
    fWidthAdjustment = fHexWidth / 4.0f;
    fHeightCenter = fHexHeight / 2.0f;
    pCanvasSize.width = Math.round ((
			      (
			       (float)pMap.getDimension()
			       * (fWidthCenter+fWidthAdjustment)
			      )
			      + (fHexWidth * 2.0f)
			     ));
    pCanvasSize.height = Math.round(((float)pMap.getDimension() * fHexHeight) + (fHexHeight * 3.0f));
    pPreferredSize = pCanvasSize;
    setSize(pCanvasSize);

    Rectangle pRect = pMapWindow.pMapScrollPane.getViewport().getViewRect();
    g.setClip(pRect);
    setSmallViewPort(pRect);
    pMapWindow.pMapScrollPane.getHorizontalScrollBar().setUnitIncrement((int)fHexWidth);
    pMapWindow.pMapScrollPane.getVerticalScrollBar().setUnitIncrement((int)fHexHeight);
    
    g.setColor (Color.black);
    g.fillRect (0, 0, pCanvasSize.width, pCanvasSize.height);

    for (x = 0; x < pMap.getDimension(); x++)  {
      if (x % 2 == 0)  {
	fHeightAdjustment = fHexHeight / 2.0f;
      }
      else  {
	fHeightAdjustment = 0.0f;
      }
      for (y = 0; y < pMap.getDimension(); y++)  {
	xPoints[0] = Math.round((
			   fHexWidth
			   + ((float)x * (fWidthCenter + fWidthAdjustment))
			   + fWidthCenter 
			   - fWidthAdjustment
			   ));
	yPoints[0] = Math.round(
			   fHexHeight 
			   + ((float)y * fHexHeight)
			   + fHeightAdjustment
			   );
	if (g.hitClip(xPoints[0], yPoints[0],
		      (int)fHexWidth, (int)fHexHeight))  {
	  xPoints[1] = Math.round(
				  fHexWidth
				  + ((float)x
				     * (fWidthCenter + fWidthAdjustment))
				  + fWidthCenter
				  + fWidthAdjustment
				  );
	  yPoints[1] = yPoints[0];
	  xPoints[2] = Math.round(
				  fHexWidth 
				  + (fHexWidth
				  + ((float)x 
				     * (fWidthCenter + fWidthAdjustment))
				     - 1.0f
				    )
				  );
	  yPoints[2] = Math.round(yPoints[0] + (int)fHeightCenter);
	  xPoints[3] = xPoints[1];
	  yPoints[3] = Math.round(
				  fHexHeight
				  + (((float)y + 1.0f) * fHexHeight)
				  + fHeightAdjustment 
				  - 1.0f
				  );
	  xPoints[4] = xPoints[0];
	  yPoints[4] = yPoints[3];
	  xPoints[5] = Math.round(
				  fHexWidth
				  + ((float)x 
				     * (fWidthCenter + fWidthAdjustment))
				  );
	  yPoints[5] = yPoints[2];

	  // Draw Hex border
	  Polygon pHexBorder = new Polygon(xPoints, yPoints, 6);
	  Rectangle pHexRect = pHexBorder.getBounds();
	  if (pRect.contains(pHexRect))  {
	    switch (getViewMode())  {
	    case VIEW_TEMPERATURE:
	    case VIEW_RAINFALL:
	    case VIEW_ELEVATION:
	      pTempHex = pMap.getHex(x,y);
	      for (i = 0; i < 6; i++)  {
		if (pTempHex.isShoreline (Hex.BW_DIRS[i]))  {
		  g.setColor(Color.black);
		}
		else  {
		  g.setColor(Color.white);
		}
		g.drawLine(xPoints[i], yPoints[i], xPoints[(i+1)%6], yPoints[(i+1)%6]);
	      }
	      break;
	    case VIEW_TERRAIN:
	    default:
	      g.setColor(Color.white);
	      g.drawPolygon(pHexBorder);
	      break;
	    }

	    // Draw Hex Inside
	    yPoints[0] += 1;
	    yPoints[1] += 1;
	    xPoints[2] -= 1;
	    yPoints[3] -= 1;
	    yPoints[4] -= 1;
	    xPoints[5] += 1;
	    Polygon pHexInside = new Polygon(xPoints, yPoints, 6);
	    pMap.getHex(x,y).paintHex(g,pHexInside,iZoomLevel,iViewMode);
	  }
	}
      }
    }
  }



  public class SmallViewPanel extends JPanel implements MouseListener {
    Image offscreen;
    Image pScaledImage;
    Rectangle pViewRect;
    Dimension pLastScreenSize;

    SmallViewPanel ()  {
      super();
      init ();
    }

    private void init ()  {
      addMouseListener (this);
    }

    public void setViewRect (Rectangle pRect)  {
      pViewRect = pRect;
    }

    public void paintComponent (Graphics g)  {
      Dimension   d = getSize();

      if (   pLastScreenSize == null
	  || pLastScreenSize.width != d.width
	  || pLastScreenSize.height != d.height
	  || pScaledImage == null)  {
	Graphics offgraphics;
	MediaTracker pTracker
	  = new MediaTracker (Main.pThisApplet);
	if (pScaledImage != null)  {
	  pScaledImage.flush();
	}
	pScaledImage = null;	
	pLastScreenSize = d;
	if (offscreen == null)  {
	  offscreen     = createImage (pMap.getDimension(),
				       pMap.getDimension());
	}
	offgraphics = offscreen.getGraphics();
	offgraphics.setColor (Color.black);
	offgraphics.fillRect (0, 0,
			      pMap.getDimension(),pMap.getDimension());
	for (int x = 0; x < pMap.getDimension(); x++)  {
	  for (int y = 0; y < pMap.getDimension(); y++)  {
	    offgraphics.setColor(Hex.COLOR_TERRAIN[pMap.getHex(x,y).getTerrainType()]);
	    offgraphics.drawLine (x,y,x,y);
	  }
	}
	offgraphics.dispose();
	pScaledImage = offscreen.getScaledInstance(d.width, d.height,
						   Image.SCALE_FAST);
	pTracker.addImage(pScaledImage, 0);
	try  {
	  pTracker.waitForID(0);
	}
	catch (InterruptedException e)  {
	}
      }
      g.drawImage(pScaledImage, 0, 0, null);
      if (pViewRect != null)  {
	g.setColor(Color.black);
	g.drawRect(pViewRect.x, pViewRect.y, pViewRect.width, pViewRect.height);
      }
    }

    //------------------------------------------------------------------------
    // MouseListener Interface
    //
    public void mouseClicked(MouseEvent e)  {
    }

    public void mousePressed(MouseEvent e)  {
      if (pViewRect == null)  {
	return;
      }
      pViewRect.x = e.getX() - (pViewRect.width / 2);
      pViewRect.y = e.getY() - (pViewRect.height / 2);
      Dimension pSmallSize = getSmallViewSize();
      pMapWindow.pMapScrollPane.getViewport().setViewPosition
	(new Point ((int)((float)pViewRect.x 
			  * (float)pCanvasSize.width 
			  / (float)pSmallSize.width
			 ),
		    (int)((float)pViewRect.y 
			  * (float)pCanvasSize.height 
			  / (float)pSmallSize.height
			 )
		   )
	);
      repaint();
    }

    public void mouseReleased (MouseEvent e)  {
    }

    public void mouseEntered(MouseEvent e)  {
    }
   
    public void mouseExited(MouseEvent e)  {
    }

  }

}