BSP Test 3D : BSP Map « Game « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Class
8. Collections Data Structure
9. Data Type
10. Database SQL JDBC
11. Design Pattern
12. Development Class
13. EJB3
14. Email
15. Event
16. File Input Output
17. Game
18. Generics
19. GWT
20. Hibernate
21. I18N
22. J2EE
23. J2ME
24. JDK 6
25. JNDI LDAP
26. JPA
27. JSP
28. JSTL
29. Language Basics
30. Network Protocol
31. PDF RTF
32. Reflection
33. Regular Expressions
34. Scripting
35. Security
36. Servlets
37. Spring
38. Swing Components
39. Swing JFC
40. SWT JFace Eclipse
41. Threads
42. Tiny Application
43. Velocity
44. Web Services SOA
45. XML
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
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java » Game » BSP MapScreenshots 
BSP Test 3D

       /*
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.Color;
import java.awt.Component;
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.Toolkit;
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.Line2D;
import java.awt.geom.Point2D;
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;

import java.awt.*;
import java.util.List;
import java.util.ArrayList;

public class BSPTest3D extends GameCore3D {

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

    protected BSPTree bspTree;

    public void init() {
        init(LOW_RES_MODES);
    }


    public void createPolygons() {
        ShadedTexture floorTexture = (ShadedTexture)
            Texture.createTexture("../images/roof1.png"true);
        ShadedTexture ceilingTexture = (ShadedTexture)
            Texture.createTexture("../images/roof2.png"true);
        ShadedTexture wallTexture = (ShadedTexture)
            Texture.createTexture("../images/wall1.png"true);

        // The floor/ceiling polygons
        Polygon3D floor = new BSPPolygon(new Vector3D[] {
            new Vector3D(0,0,150)new Vector3D(0,0,450),
            new Vector3D(800,0,450)new Vector3D(800,0,300),
            new Vector3D(500,0,300)new Vector3D(500,0,75),
        }, BSPPolygon.TYPE_FLOOR);
        Polygon3D ceiling = new BSPPolygon(new Vector3D[] {
            new Vector3D(0,300,450)new Vector3D(0,300,150),
            new Vector3D(500,300,75)new Vector3D(500,300,300),
            new Vector3D(800,300,300)new Vector3D(800,300,450),
        }, BSPPolygon.TYPE_FLOOR);
        polygons.add(floor);
        polygons.add(ceiling);
        setTexture(floor, floorTexture);
        setTexture(ceiling, ceilingTexture);

        // 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)0300);
        BSPPolygon wallD = createPolygon(
            new BSPLine(8004500450)0300);
        BSPPolygon wallE = createPolygon(
            new BSPLine(04500150)0300);
        BSPPolygon wallF = createPolygon(
            new BSPLine(800300800450)0300);
        polygons.add(wallA);
        polygons.add(wallB);
        polygons.add(wallC);
        polygons.add(wallD);
        polygons.add(wallE);
        polygons.add(wallF);

        setTexture(wallA, wallTexture);
        setTexture(wallB, wallTexture);
        setTexture(wallC, wallTexture);
        setTexture(wallD, wallTexture);
        setTexture(wallE, wallTexture);
        setTexture(wallF, wallTexture);

        BSPTreeBuilder builder = new BSPTreeBuilder();
        bspTree = builder.build(polygons);

        // build surfaces
        ArrayList lights = new ArrayList();
        lights.add(new PointLight3D(4002001001300));
        lights.add(new PointLight3D(700200400.5f1000));
        lights.add(new PointLight3D(652003851100));
        bspTree.createSurfaces(lights);

    }

    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 setTexture(Polygon3D poly, Texture texture) {

        Vector3D origin = poly.getVertex(1);

        Vector3D dv = new Vector3D(poly.getVertex(0));
        dv.subtract(origin);

        Vector3D du = new Vector3D();
        du.setToCrossProduct(poly.getNormal(), dv);

        Rectangle3D texBounds = new Rectangle3D(origin, du, dv,
            texture.getWidth(), texture.getHeight());

        ((TexturedPolygon3D)poly).setTexture(texture, texBounds);
    }

    public void createPolygonRenderer() {
        // make the view window the entire screen
        viewWindow = new ViewWindow(00,
            screen.getWidth(), screen.getHeight(),
            (float)Math.toRadians(75));

        Transform3D camera = new Transform3D(400,100,300);
        polygonRenderer = new SimpleBSPRenderer(
            camera, viewWindow);
    }

     public void draw(Graphics2D g) {

        // draw polygons
        polygonRenderer.startFrame(g);
        ((SimpleBSPRenderer)polygonRenderer).draw(g, bspTree);
        polygonRenderer.endFrame(g);

        super.drawText(g);
    }

}


/**
    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);
        ((SortedScanConverter)scanConverter).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);
        ((SortedScanConverter)scanConverter).clear();
    }


    public void endFrame(Graphics2D g) {
        super.endFrame(g);
        if (!((SortedScanConverter)scanConverter).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 !((SortedScanConverter)scanConverter).isFilled();
    }


    protected void drawCurrentPolygon(Graphics2D g) {
        if (!(sourcePolygon instanceof TexturedPolygon3D)) {
            // not a textured polygon - return
            return;
        }
        buildSurface();
        SortedScanConverter scanConverter =
            (SortedScanConverter)this.scanConverter;
        TexturedPolygon3D poly = (TexturedPolygon3D)destPolygon;
        Texture texture = poly.getTexture();
        ScanRenderer scanRenderer =
            (ScanRenderer)scanRenderers.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