BSP Test 2D : BSP Map « Game « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Collections Data Structure
8. Database SQL JDBC
9. Design Pattern
10. Development Class
11. Email
12. Event
13. File Input Output
14. Game
15. Hibernate
16. J2EE
17. J2ME
18. JDK 6
19. JSP
20. JSTL
21. Language Basics
22. Network Protocol
23. PDF RTF
24. Regular Expressions
25. Security
26. Servlets
27. Spring
28. Swing Components
29. Swing JFC
30. SWT JFace Eclipse
31. Threads
32. Tiny Application
33. Velocity
34. Web Services SOA
35. XML
Microsoft Office Word 2007 Tutorial
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Java » Game » BSP MapScreenshots 
BSP Test 2D

       /*
DEVELOPING GAME IN JAVA 

Caracteristiques

Editeur : NEW RIDERS 
Auteur : BRACKEEN 
Parution : 09 2003 
Pages : 972 
Isbn : 1-59273-005-1 
Reliure : Paperback 
Disponibilite : Disponible a la librairie 
*/


import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferUShort;
import java.awt.image.IndexColorModel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class BSPTest2D extends GameCore implements BSPTreeTraverseListener {

  public static void main(String[] args) {
    new BSPTest2D().run();
  }

  protected List polygons;

  protected BSPTree bspTree;

  protected BSPTreeTraverser traverser;

  protected int numWalls;

  protected int wallID;

  protected Vector3D viewLocation = new Vector3D();

  protected Image overlayImage;

  protected InputManager inputManager;

  private GameAction exit = new GameAction("exit");

  private GameAction addWall = new GameAction("addWall",
      GameAction.DETECT_INITAL_PRESS_ONLY);

  private GameAction removeWall = new GameAction("removeWall",
      GameAction.DETECT_INITAL_PRESS_ONLY);

  public void init() {
    super.init();

    inputManager = new InputManager(screen.getFullScreenWindow());

    inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
    inputManager.mapToKey(addWall, KeyEvent.VK_SPACE);
    inputManager.mapToKey(removeWall, KeyEvent.VK_BACK_SPACE);

    traverser = new BSPTreeTraverser();
    // create walls
    numWalls = 1;
    polygons = new ArrayList();
    createPolygons();
    buildTree();

    // create overlay image for lines and text labels
    overlayImage = screen.createCompatibleImage(screen.getWidth(), screen
        .getHeight(), Transparency.BITMASK);
  }

  public void createPolygons() {
    // The floor polygon
    BSPPolygon floor = new BSPPolygon(new Vector3D[] {
        new Vector3D(000)new Vector3D(00600),
        new Vector3D(8000600)new Vector3D(80000) },
        BSPPolygon.TYPE_FLOOR);
    polygons.add(floor);

    // vertices defined from left to right as the viewer
    // looks at the wall
    BSPPolygon wallA = createPolygon(new BSPLine(015050075)0300);
    BSPPolygon wallB = createPolygon(new BSPLine(50075500300)0300);
    BSPPolygon wallC = createPolygon(new BSPLine(500300800300)0,
        300);
    BSPPolygon wallD = createPolygon(new BSPLine(8004500450)0300);
    polygons.add(wallA);
    polygons.add(wallB);
    polygons.add(wallC);
    polygons.add(wallD);
  }

  public BSPPolygon createPolygon(BSPLine line, float bottom, float top) {
    return new BSPPolygon(new Vector3D[] {
        new Vector3D(line.x1, bottom, line.y1),
        new Vector3D(line.x2, bottom, line.y2),
        new Vector3D(line.x2, top, line.y2),
        new Vector3D(line.x1, top, line.y1) }, BSPPolygon.TYPE_WALL);
  }

  public void buildTree() {
    BSPTreeBuilder builder = new BSPTreeBuilder();
    bspTree = builder.build(polygons.subList(0, numWalls + 1));
  }

  public void update(long elapsedTime) {
    if (exit.isPressed()) {
      stop();
      return;
    }

    if (addWall.isPressed() && numWalls < polygons.size() 1) {
      numWalls++;
      buildTree();
    else if (removeWall.isPressed() && numWalls > 0) {
      numWalls--;
      buildTree();
    }

    viewLocation.x = inputManager.getMouseX();
    viewLocation.z = inputManager.getMouseY();

  }

  public void draw(Graphics2D g) {

    Graphics2D g2 = (Graphics2DoverlayImage.getGraphics();
    g2.setFont(g.getFont());

    // erase overlay image (set it to transparent);
    Composite defaultComposite = g2.getComposite();
    g2.setComposite(AlphaComposite.Clear);
    g2.fillRect(00, screen.getWidth(), screen.getHeight());
    g2.setComposite(defaultComposite);

    // draw info on overlay image
    g2.setColor(Color.WHITE);
    g2.drawString("Press Space/Backspace to add/remove "
        "walls. Press Esc to exit."5, fontSize);
    g2.drawString("The numbers represent front-to-back draw " "order.",
        5, fontSize * 2);
    g2.drawString("The mouse represents the camera location."5,
        fontSize * 3);
    g2.dispose();

    // erase screen
    g.setColor(Color.BLACK);
    g.fillRect(00, screen.getWidth(), screen.getHeight());

    // draw areas
    wallID = 1;
    traverser.setListener(this);
    traverser.traverse(bspTree, viewLocation);

    // draw overlay image on the screen
    g.drawImage(overlayImage, 00null);
  }

  public boolean visitPolygon(BSPPolygon poly, boolean isBack) {
    Shape shape;
    if (poly.isWall()) {
      shape = drawWall(poly);
    else {
      shape = drawFloor(poly, isBack);
    }

    // draw wall id
    Graphics2D g2 = (Graphics2DoverlayImage.getGraphics();
    g2.setFont(screen.getGraphics().getFont());
    Rectangle2D bounds = shape.getBounds2D();
    int x = (intbounds.getCenterX() - fontSize / 4;
    int y = (intbounds.getCenterY() + fontSize / 2;
    g2.setColor(Color.WHITE);
    g2.drawString(wallID + ".", x, y);
    wallID++;

    return true;
  }

  public Shape drawWall(BSPPolygon wall) {
    Graphics2D g = (Graphics2DoverlayImage.getGraphics();
    g.setColor(Color.BLACK);
    BSPLine line = wall.getLine();
    g.draw(line);
    g.fillRect((intline.x1 - 2(intline.y1 - 255);
    g.fillRect((intline.x2 - 2(intline.y2 - 255);
    g.dispose();
    return line;
  }

  public Shape drawFloor(BSPPolygon floor, boolean isBack) {
    Graphics2D g = screen.getGraphics();
    if (isBack) {
      g.setColor(Color.DARK_GRAY);
    else {
      g.setColor(Color.LIGHT_GRAY);
    }
    GeneralPath path = new GeneralPath();
    path.moveTo(floor.getVertex(0).x, floor.getVertex(0).z);
    for (int i = 1; i < floor.getNumVertices(); i++) {
      path.lineTo(floor.getVertex(i).x, floor.getVertex(i).z);
    }
    g.fill(path);
    return path;
  }

}

/**
 * The SimpleBSPRenderer class is a renderer capable of drawing polygons in a
 * BSP tree and any polygon objects in the scene. No Z-buffering is used.
 */

class SimpleBSPRenderer extends ShadedSurfacePolygonRenderer implements
    BSPTreeTraverseListener {
  protected Graphics2D currentGraphics2D;

  protected BSPTreeTraverser traverser;

  protected boolean viewNotFilledFirstTime;

  /**
   * Creates a new BSP renderer with the specified camera object and view
   * window.
   */
  public SimpleBSPRenderer(Transform3D camera, ViewWindow viewWindow) {
    super(camera, viewWindow, false);
    viewNotFilledFirstTime = true;
  }

  protected void init() {
    traverser = new BSPTreeTraverser(this);
    destPolygon = new TexturedPolygon3D();
    scanConverter = new SortedScanConverter(viewWindow);
    ((SortedScanConverterscanConverter).setSortedMode(true);

    // create renderers for each texture (HotSpot optimization)
    scanRenderers = new HashMap();
    scanRenderers.put(PowerOf2Texture.class, new PowerOf2TextureRenderer());
    scanRenderers.put(ShadedTexture.class, new ShadedTextureRenderer());
    scanRenderers.put(ShadedSurface.class, new ShadedSurfaceRenderer());
  }

  public void startFrame(Graphics2D g) {
    super.startFrame(g);
    ((SortedScanConverterscanConverter).clear();
  }

  public void endFrame(Graphics2D g) {
    super.endFrame(g);
    if (!((SortedScanConverterscanConverter).isFilled()) {
      g.drawString("View not completely filled"5, viewWindow
          .getTopOffset()
          + viewWindow.getHeight() 5);
      if (viewNotFilledFirstTime) {
        viewNotFilledFirstTime = false;
        // print message to console in case user missed it
        System.out.println("View not completely filled.");
      }
      // clear the background next time
      clearViewEveryFrame = true;
    else {
      clearViewEveryFrame = false;
    }
  }

  /**
   * Draws the visible polygons in a BSP tree based on the camera location.
   * The polygons are drawn front-to-back.
   */
  public void draw(Graphics2D g, BSPTree tree) {
    currentGraphics2D = g;
    traverser.traverse(tree, camera.getLocation());
  }

  // from the BSPTreeTraverseListener interface
  public boolean visitPolygon(BSPPolygon poly, boolean isBack) {
    draw(currentGraphics2D, poly);
    return !((SortedScanConverterscanConverter).isFilled();
  }

  protected void drawCurrentPolygon(Graphics2D g) {
    if (!(sourcePolygon instanceof TexturedPolygon3D)) {
      // not a textured polygon - return
      return;
    }
    buildSurface();
    SortedScanConverter scanConverter = (SortedScanConverterthis.scanConverter;
    TexturedPolygon3D poly = (TexturedPolygon3DdestPolygon;
    Texture texture = poly.getTexture();
    ScanRenderer scanRenderer = (ScanRendererscanRenderers.get(texture
        .getClass());
    scanRenderer.setTexture(texture);
    Rectangle3D textureBounds = poly.getTextureBounds();

    a.setToCrossProduct(textureBounds.getDirectionV(), textureBounds
        .getOrigin());
    b.setToCrossProduct(textureBounds.getOrigin(), textureBounds
        .getDirectionU());
    c.setToCrossProduct(textureBounds.getDirectionU(), textureBounds
        .getDirectionV());

    int y = scanConverter.getTopBoundary();
    viewPos.y = viewWindow.convertFromScreenYToViewY(y);
    viewPos.z = -viewWindow.getDistance();

    while (y <= scanConverter.getBottomBoundary()) {
      for (int i = 0; i < scanConverter.getNumScans(y); i++) {
        ScanConverter.Scan scan = scanConverter.getScan(y, i);

        if (scan.isValid()) {
          viewPos.x = viewWindow.convertFromScreenXToViewX(scan.left);
          int offset = (y - viewWindow.getTopOffset())
              * viewWindow.getWidth()
              (scan.left - viewWindow.getLeftOffset());

          scanRenderer.render(offset, scan.left, scan.right);
        }
      }
      y++;
      viewPos.y--;
    }
  }
}

/**
 * The PolygonRenderer class is an abstract class that transforms and draws
 * polygons onto the screen.
 */

abstract class PolygonRenderer {

  protected ScanConverter scanConverter;

  protected Transform3D camera;

  protected ViewWindow viewWindow;

  protected boolean clearViewEveryFrame;

  protected Polygon3D sourcePolygon;

  protected Polygon3D destPolygon;

  /**
   * Creates a new PolygonRenderer with the specified Transform3D (camera) and
   * ViewWindow. The view is cleared when startFrame() is called.
   */
  public PolygonRenderer(Transform3D camera, ViewWindow viewWindow) {
    this(camera, viewWindow, true);
  }

  /**
   * Creates a new PolygonRenderer with the specified Transform3D (camera) and
   * ViewWindow. If clearViewEveryFrame is true, the view is cleared when
   * startFrame() is called.
   */
  public PolygonRenderer(Transform3D camera, ViewWindow viewWindow,
      boolean clearViewEveryFrame) {
    this.camera = camera;
    this.viewWindow = viewWindow;
    this.clearViewEveryFrame = clearViewEveryFrame;
    init();
  }

  /**
   * Create the scan converter and dest polygon.
   */
  protected void init() {
    destPolygon = new Polygon3D();
    scanConverter = new ScanConverter(viewWindow);
  }

  /**
   * Gets the camera used for this PolygonRenderer.
   */
  public Transform3D getCamera() {
    return camera;
  }

  /**
   * Indicates the start of rendering of a frame. This method should be called
   * every frame before any polygons are drawn.
   */
  public void startFrame(Graphics2D g) {
    if (clearViewEveryFrame) {
      g.setColor(Color.black);
      g.fillRect(viewWindow.getLeftOffset(), viewWindow.getTopOffset(),
          viewWindow.getWidth(), viewWindow.getHeight());
    }
  }

  /**
   * Indicates the end of rendering of a frame. This method should be called
   * every frame after all polygons are drawn.
   */
  public void endFrame(Graphics2D g) {
    // do nothing, for now.
  }

  /**
   * Transforms and draws a polygon.
   */
  public boolean draw(Graphics2D g, Polygon3D poly) {
    if (poly.isFacing(camera.getLocation())) {
      sourcePolygon = poly;
      destPolygon.setTo(poly);
      destPolygon.subtract(camera);
      boolean visible = destPolygon.clip(-1);
      if (visible) {
        destPolygon.project(viewWindow);
        visible = scanConverter.convert(destPolygon);
        if (visible) {
          drawCurrentPolygon(g);
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Draws the current polygon. At this point, the current polygon is
   * transformed, clipped, projected, scan-converted, and visible.
   */
  protected abstract void drawCurrentPolygon(Graphics2D g);
}

/**
 * The ScanConverter class converts a projected polygon into a series of
 * horizontal scans for drawing.
 */

class ScanConverter {

  private static final int SCALE_BITS = 16;

  private static final int SCALE = << SCALE_BITS;

  private static final int SCALE_MASK = SCALE - 1;

  protected ViewWindow view;

  protected Scan[] scans;

  protected int top;

  protected int bottom;

  /**
   * A horizontal scan line.
   */
  public static class Scan {
    public int left;

    public int right;

    /**
     * Sets the left and right boundary for this scan if the x value is
     * outside the current boundary.
     */
    public void setBoundary(int x) {
      if (x < left) {
        left = x;
      }
      if (x - > right) {
        right = x - 1;
      }
    }

    /**
     * Clears this scan line.
     */
    public void clear() {
      left = Integer.MAX_VALUE;
      right = Integer.MIN_VALUE;
    }

    /**
     * Determines if this scan is valid (if left <= right).
     */
    public boolean isValid() {
      return (left <= right);
    }

    /**
     * Sets this scan.
     */
    public void setTo(int left, int right) {
      this.left = left;
      this.right = right;
    }

    /**
     * Checks if this scan is equal to the specified values.
     */
    public boolean equals(int left, int right) {
      return (this.left == left && this.right == right);
    }
  }

  /**
   * Creates a new ScanConverter for the specified ViewWindow. The
   * ViewWindow's properties can change in between scan conversions.
   */
  public ScanConverter(ViewWindow view) {
    this.view = view;
  }

  /**
   * Gets the top boundary of the last scan-converted polygon.
   */
  public int getTopBoundary() {
    return top;
  }

  /**
   * Gets the bottom boundary of the last scan-converted polygon.
   */
  public int getBottomBoundary() {
    return bottom;
  }

  /**
   * Gets the scan line for the specified y value.
   */
  public Scan getScan(int y) {
    return scans[y];
  }

  /**
   * Ensures this ScanConverter has the capacity to scan-convert a polygon to
   * the ViewWindow.
   */
  protected void ensureCapacity() {
    int height = view.getTopOffset() + view.getHeight();
    if (scans == null || scans.length != height) {
      scans = new Scan[height];
      for (int i = 0; i < height; i++) {
        scans[inew Scan();
      }
      // set top and bottom so clearCurrentScan clears all
      top = 0;
      bottom = height - 1;
    }

  }

  /**
   * Clears the current scan.
   */
  private void clearCurrentScan() {
    for (int i = top; i <= bottom; i++) {
      scans[i].clear();
    }
    top = Integer.MAX_VALUE;
    bottom = Integer.MIN_VALUE;
  }

  /**
   * Scan-converts a projected polygon. Returns true if the polygon is visible
   * in the view window.
   */
  public boolean convert(Polygon3D polygon) {

    ensureCapacity();
    clearCurrentScan();

    int minX = view.getLeftOffset();
    int maxX = view.getLeftOffset() + view.getWidth() 1;
    int minY = view.getTopOffset();
    int maxY = view.getTopOffset() + view.getHeight() 1;

    int numVertices = polygon.getNumVertices();
    for (int i = 0; i < numVertices; i++) {
      Vector3D v1 = polygon.getVertex(i);
      Vector3D v2;
      if (i == numVertices - 1) {
        v2 = polygon.getVertex(0);
      else {
        v2 = polygon.getVertex(i + 1);
      }

      // ensure v1.y < v2.y
      if (v1.y > v2.y) {
        Vector3D temp = v1;
        v1 = v2;
        v2 = temp;
      }
      float dy = v2.y - v1.y;

      // ignore horizontal lines
      if (dy == 0) {
        continue;
      }

      int startY = Math.max(MoreMath.ceil(v1.y), minY);
      int endY = Math.min(MoreMath.ceil(v2.y1, maxY);
      top = Math.min(top, startY);
      bottom = Math.max(bottom, endY);
      float dx = v2.x - v1.x;

      // special case: vertical line
      if (dx == 0) {
        int x = MoreMath.ceil(v1.x);
        // ensure x within view bounds
        x = Math.min(maxX + 1, Math.max(x, minX));
        for (int y = startY; y <= endY; y++) {
          scans[y].setBoundary(x);
        }
      else {
        // scan-convert this edge (line equation)
        float gradient = dx / dy;

        // (slower version)
        /*
         * for (int y=startY; y <=endY; y++) { int x =
         * MoreMath.ceil(v1.x + (y - v1.y) * gradient); // ensure x
         * within view bounds x = Math.min(maxX+1, Math.max(x, minX));
         * scans[y].setBoundary(x); }
         */

        // (faster version)
        // trim start of line
        float startX = v1.x + (startY - v1.y* gradient;
        if (startX < minX) {
          int yInt = (int) (v1.y + (minX - v1.x/ gradient);
          yInt = Math.min(yInt, endY);
          while (startY <= yInt) {
            scans[startY].setBoundary(minX);
            </