home games dev
Lewpen.com»Research & Development»3D Graphics»Java 3D Engine»Box & Reflective Tetrahedron

Box & Reflective Tetrahedron

Using a BSP tree for reflections and object intersection

/ Raytrace.java

import java.awt.image.*;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.awt.Image;
import java.awt.Font;



public class Raytrace extends java.applet.Applet implements Runnable {



//---- DATA ----------------------------------------------------------------//

  //- Thread data

  Thread runThread;

  //- Output image data

  static int image_w = 160, image_h = 160;

  byte r[], g[], b[];
  byte buf[];
  byte back[];
  IndexColorModel pal;

  MemoryImageSource src;
  Image im;

  byte poly_alpha[];

  //- Mouse move stuff

  int mouse_oldx, mouse_oldy;
  int pause = 0;

  //- 3D Object data

  //  Rotation matrix

  double m[][];

  //  Object 1

  int o1_rx, o1_ry, o1_rz;
  double o1_cx, o1_cy, o1_cz;

  int o1_numpoints;
  double o1_x[], o1_y[], o1_z[];
  double o1_tx[], o1_ty[], o1_tz[];
  double o1_sx[], o1_sy[], o1_sz[];

  int o1_numfaces;
  int o1_fn[], o1_f[][];
  double o1_nx[], o1_ny[], o1_nz[];
  double o1_tnx[], o1_tny[], o1_tnz[];

  //  Object 2

  int o2_rx, o2_ry, o2_rz;
  double o2_cx, o2_cy, o2_cz;

  int o2_numpoints;
  double o2_x[], o2_y[], o2_z[];
  double o2_tx[], o2_ty[], o2_tz[];
  double o2_sx[], o2_sy[], o2_sz[];

  int o2_numfaces;
  int o2_fn[], o2_f[][];
  double o2_nx[], o2_ny[], o2_nz[];
  double o2_tnx[], o2_tny[], o2_tnz[];

  //  BSP Tree

  static int bsp_size = 256;
  static int bsp_polysize = 8;

  int bsp_num;
  int bsp_left[];
  int bsp_right[];
  int bsp_poly_num[];
  double bsp_poly_sx[][], bsp_poly_sy[][];
  double bsp_poly_x[][], bsp_poly_y[][], bsp_poly_z[][];
  double bsp_nx[], bsp_ny[], bsp_nz[];
  double bsp_x[], bsp_y[], bsp_z[];
  int bsp_object[];

  //  Polygon stack

  static int polystack_size = 256;
  static int polystack_polysize = 8;

  int polystack_sp, polystack_bp;

  int polystack_num[];
  double polystack_x[][], polystack_y[][], polystack_z[][];
  double polystack_sx[][], polystack_sy[][];
  double polystack_nx[], polystack_ny[], polystack_nz[];
  double polystack_cx[], polystack_cy[], polystack_cz[];
  double polystack_clip[][];
  int polystack_object[];

  //  Polygon data

  int poly_ymin, poly_ymax;
  int poly_xmin[], poly_xmax[];

  int poly2_ymin, poly2_ymax;
  int poly2_xmin[], poly2_xmax[];

  //  Lookup tables

  double sintable[], costable[];



//---- INIT & THREAD FUNCTIONS ---------------------------------------------//

  //---- init

  public void init() {
    int size = image_w*image_h;
    int i, j, k;
    char rr, gg, bb;
    double d;
    String s;

    System.out.println("LKS Renderer v0.1");

    //- Set up image buffer and palette

    buf = new byte[size];
    back = new byte[size];
    r = new byte[256];
    g = new byte[256];
    b = new byte[256];

    s  = "*(!'1*89%])%%.";

    for(i=0; i<size; i++) {
      buf[i] = 0;
    }

    rr = (57*5)&255;
    gg = (57*3)&255;
    bb = (57*7)&255;

    for(i=0; i<64; i++) {
      r[i] = (byte)(i*4);
      g[i] = (byte)(i*4);
      b[i] = (byte)(i*4);
    }

    for(i=0; i<64; i++) {
      r[i+64] = (byte)(i*4);
      g[i+64] = (byte)(0);
      b[i+64] = (byte)(0);
    }

    s += "%^(1@% %) *^).";

    for(i=0; i<64; i++) {
      r[i+128] = (byte)(255);
      g[i+128] = (byte)(i*3);
      b[i+128] = (byte)(i*3);
    }

    for(i=0; i<64; i++) {
      r[i+192] = (byte)(0);
      g[i+192] = (byte)(0);
      b[i+192] = (byte)(i*4);
    }

    s += "%4$(@**.? ^*%-";

    //  Alpha blending

    poly_alpha = new byte[256*64];

    for(j=0; j<64; j++) {
      for(i=0; i<64; i++) {
        poly_alpha[(j<<8)+i] = (byte)((i+j)>>1);
      }

      for(i=0; i<64; i++) {
        poly_alpha[(j<<8)+i+64] = (byte)(64+i+j);
      }

      for(i=0; i<64; i++) {
        poly_alpha[(j<<8)+i+128] = 0;
      }

      for(i=0; i<64; i++) {
        poly_alpha[(j<<8)+i+192] = (byte)((i+j)>>1);
      }

    }

    //  Make background

    s += "* !1(%?*/?^89*";

    for(j=0; j<image_h; j++) {
      for(i=0; i<image_w; i++) {
        d = ((i-image_w/2)*(i-image_w/2)+(j-image_h/2)*(j-image_h/2))*0.0035;
        k = (int)(d);
        if(k<0) { k=0; }
        back[i+j*image_w] = (byte)(192+(k&63));
      }
    }

    s += "*%*%-*//*?*%*+";

    k=image_w*(image_h-7)-16;
    for(j=0; j<5; j++) {
      for(i=0; i<14; i++) {
        if(s.charAt(i+14*j) == '*' || s.charAt(i+14*j) == '%') {
          back[k] = (byte)255;
          back[k+image_w+1] = (byte)192;
        }
        k++;
      }
      k += image_w-14;
    }

    pal = new IndexColorModel(8, 256, r, g, b);
    src = new MemoryImageSource(image_w, image_h, pal, buf, 0, image_w);
    src.setAnimated(true);
    im = createImage(src);

    //- Create lookup tables

    sintable = new double[4096];
    costable = new double[4096];

    for(i=0; i<4096; i++) {
      sintable[i] = Math.sin(3.1415926*i/2048);
      costable[i] = Math.cos(3.1415926*i/2048);
    }

    //- Create matrix

    m = new double[3][3];

    //- Create BSP tree

    bsp_object = new int[bsp_size];
    bsp_left = new int[bsp_size];
    bsp_right = new int[bsp_size];
    bsp_poly_num = new int[bsp_size];
    bsp_poly_sx = new double[bsp_size][bsp_polysize];
    bsp_poly_sy = new double[bsp_size][bsp_polysize];
    bsp_poly_x = new double[bsp_size][bsp_polysize];
    bsp_poly_y = new double[bsp_size][bsp_polysize];
    bsp_poly_z = new double[bsp_size][bsp_polysize];
    bsp_nx = new double[bsp_size];
    bsp_ny = new double[bsp_size];
    bsp_nz = new double[bsp_size];
    bsp_x = new double[bsp_size];
    bsp_y = new double[bsp_size];
    bsp_z = new double[bsp_size];

    //  Create stacks

    polystack_num = new int[polystack_size];
    polystack_sx = new double[polystack_size][polystack_polysize];
    polystack_sy = new double[polystack_size][polystack_polysize];
    polystack_nx = new double[polystack_size];
    polystack_ny = new double[polystack_size];
    polystack_nz = new double[polystack_size];
    polystack_x = new double[polystack_size][polystack_polysize];
    polystack_y = new double[polystack_size][polystack_polysize];
    polystack_z = new double[polystack_size][polystack_polysize];
    polystack_cx = new double[polystack_size];
    polystack_cy = new double[polystack_size];
    polystack_cz = new double[polystack_size];
    polystack_object = new int[polystack_size];
    polystack_clip = new double[polystack_size][polystack_polysize];
    polystack_sp = 0;
    polystack_bp = 0;

    //- Create polygon

    poly_xmin = new int[image_h];
    poly_xmax = new int[image_h];
    poly2_xmin = new int[image_h];
    poly2_xmax = new int[image_h];

    //- Create objects

    //  Initial position of object 1

    o1_cx = 0; o1_cy = 0; o1_cz = 5.0;
    o1_rx = 0; o1_ry = 0; o1_rz = 0;

    //  Define points of object 1

    o1_numpoints = 4;

    o1_x = new double[4]; o1_y = new double[4]; o1_z = new double[4];
    o1_tx = new double[4]; o1_ty = new double[4]; o1_tz = new double[4];
    o1_sx = new double[4]; o1_sy = new double[4]; o1_sz = new double[4];

    o1_x[0] =  1.8; o1_y[0] =  1.8; o1_z[0] =  1.8;
    o1_x[1] = -1.8; o1_y[1] =  1.8; o1_z[1] = -1.8;
    o1_x[2] =  1.8; o1_y[2] = -1.8; o1_z[2] = -1.8;
    o1_x[3] = -1.8; o1_y[3] = -1.8; o1_z[3] =  1.8;
/*
    o1_x[0] =  1.8; o1_y[0] =  1.8; o1_z[0] =    0;
    o1_x[2] =  1.8; o1_y[2] = -1.8; o1_z[2] =    0;
    o1_x[1] = -1.8; o1_y[1] =  1.8; o1_z[1] =    0;
    o1_x[3] = -1.8; o1_y[3] = -1.8; o1_z[3] =    0;
*/
    //  Define faces of object 1

    o1_numfaces = 4;

    o1_nx = new double[4]; o1_ny = new double[4]; o1_nz = new double[4];
    o1_tnx = new double[4]; o1_tny = new double[4]; o1_tnz = new double[4];

    makenormal_o1( 0,  0,  2,  1);
    makenormal_o1( 1,  1,  2,  3);
    makenormal_o1( 2,  0,  1,  3);
    makenormal_o1( 3,  3,  2,  0);

    //  Initial position of object 2

    o2_cx = 0; o2_cy = 0; o2_cz = 5.0;
    o2_rx = 0; o2_ry = 0; o2_rz = 0;

    o2_numpoints = 16;

    //  Define points of object 2

    o2_x = new double[16]; o2_y = new double[16]; o2_z = new double[16];
    o2_tx = new double[16]; o2_ty = new double[16]; o2_tz = new double[16];
    o2_sx = new double[16]; o2_sy = new double[16]; o2_sz = new double[16];

    o2_x[ 0] =  1.5; o2_y[ 0] =  0.5; o2_z[ 0] =  2.5;
    o2_x[ 1] =  1.0; o2_y[ 1] =  0.5; o2_z[ 1] =  2.0;
    o2_x[ 2] =  1.0; o2_y[ 2] = -0.5; o2_z[ 2] =  2.0;
    o2_x[ 3] =  1.5; o2_y[ 3] = -0.5; o2_z[ 3] =  2.5;
    o2_x[ 4] =  1.5; o2_y[ 4] =  0.5; o2_z[ 4] = -2.5;
    o2_x[ 5] =  1.0; o2_y[ 5] =  0.5; o2_z[ 5] = -2.0;
    o2_x[ 6] =  1.0; o2_y[ 6] = -0.5; o2_z[ 6] = -2.0;
    o2_x[ 7] =  1.5; o2_y[ 7] = -0.5; o2_z[ 7] = -2.5;
    o2_x[ 8] = -1.5; o2_y[ 8] =  0.5; o2_z[ 8] = -2.5;
    o2_x[ 9] = -1.0; o2_y[ 9] =  0.5; o2_z[ 9] = -2.0;
    o2_x[10] = -1.0; o2_y[10] = -0.5; o2_z[10] = -2.0;
    o2_x[11] = -1.5; o2_y[11] = -0.5; o2_z[11] = -2.5;
    o2_x[12] = -1.5; o2_y[12] =  0.5; o2_z[12] =  2.5;
    o2_x[13] = -1.0; o2_y[13] =  0.5; o2_z[13] =  2.0;
    o2_x[14] = -1.0; o2_y[14] = -0.5; o2_z[14] =  2.0;
    o2_x[15] = -1.5; o2_y[15] = -0.5; o2_z[15] =  2.5;

    //  Define faces of object 2

    o2_numfaces = 16;

    o2_nx = new double[16]; o2_ny = new double[16]; o2_nz = new double[16];
    o2_tnx = new double[16]; o2_tny = new double[16]; o2_tnz = new double[16];

    makenormal_o2( 0,  0,  4,  5,  1);
    makenormal_o2( 1,  1,  5,  6,  2);
    makenormal_o2( 2,  2,  6,  7,  3);
    makenormal_o2( 3,  3,  7,  4,  0);
    makenormal_o2( 4,  4,  8,  9,  5);
    makenormal_o2( 5,  5,  9, 10,  6);
    makenormal_o2( 6,  6, 10, 11,  7);
    makenormal_o2( 7,  7, 11,  8,  4);
    makenormal_o2( 8,  8, 12, 13,  9);
    makenormal_o2( 9,  9, 13, 14, 10);
    makenormal_o2(10, 10, 14, 15, 11);
    makenormal_o2(11, 11, 15, 12,  8);
    makenormal_o2(12, 12,  0,  1, 13);
    makenormal_o2(13, 13,  1,  2, 14);
    makenormal_o2(14, 14,  2,  3, 15);
    makenormal_o2(15, 15,  3,  0, 12);

  }

  public void start() {
    if(runThread == null) {
      runThread = new Thread(this);
      runThread.start();
    }
  }

  public void stop() {
    if(runThread != null) {
      runThread.stop();
      runThread = null;
    }
  }

  public void run() {

    while(true) {
      try {
        runThread.sleep(20);
      } catch (InterruptedException e) {
        return;
      }

      redraw();
    }
  }



//---- EVENT HANDLERS ------------------------------------------------------//

  public boolean mouseDown(Event evt, int x, int y) {
    pause = 0;
    mouse_oldx = x;
    mouse_oldy = y;
    return true;
  }
  
  public boolean mouseUp(Event evt, int x, int y) {
    pause = 0;
    return true;
  }
  
  public boolean mouseDrag(Event e, int x, int y) {
    pause = 1;
    o1_rx += 12*(y-mouse_oldy);
    o1_ry += 8*(y-mouse_oldy)+4*(x-mouse_oldx);
    o1_rz += 12*(x-mouse_oldx);
    o2_rx += 12*(y-mouse_oldy);
    o2_ry += 8*(y-mouse_oldy)+4*(x-mouse_oldx);
    o2_rz += 12*(x-mouse_oldx);
    mouse_oldx = x;
    mouse_oldy = y;
    return true;
  }

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

  public void paint(Graphics g) {
    g.drawImage(im, 0, 0, this);
  }



//---- VECTOR ROUTINES -----------------------------------------------------//

//---- MakeTrans

  public void maketrans(int rx, int ry, int rz) {
    double cx, sx, cy, sy, cz, sz;

    cx = costable[rx&4095]; cy = costable[ry&4095]; cz = costable[rz&4095];
    sx = sintable[rx&4095]; sy = sintable[ry&4095]; sz = sintable[rz&4095];

    m[0][0] =          cy*cz; m[0][1] =          cy*sz; m[0][2] = -sy;
    m[1][0] = sx*sy*cz-cx*sz; m[1][1] = sx*sy*sz+cx*cz; m[1][2] = sx*cy;
    m[2][0] = cx*sy*cz+sx*sz; m[2][1] = cx*sy*sz-sx*cz; m[2][2] = cx*cy;
  }



//---- MakeNormal_o1

  public void makenormal_o1(int poly, int p1, int p2, int p3) {
    double ax, ay, az, bx, by, bz, nx, ny, nz, n;

    ax = o1_x[p3]-o1_x[p2]; ay = o1_y[p3]-o1_y[p2]; az = o1_z[p3]-o1_z[p2];
    bx = o1_x[p1]-o1_x[p2]; by = o1_y[p1]-o1_y[p2]; bz = o1_z[p1]-o1_z[p2];

    nx = ay*bz-az*by; ny = az*bx-ax*bz; nz = ax*by-ay*bx;

    n = 1/Math.sqrt(nx*nx+ny*ny+nz*nz);

    o1_nx[poly] = nx*n;
    o1_ny[poly] = ny*n;
    o1_nz[poly] = nz*n;
  }



//---- MakeNormal_o2

  public void makenormal_o2(int poly, int p1, int p2, int p3, int p4) {
    double ax, ay, az, bx, by, bz, nx, ny, nz, n;

    ax = o2_x[p3]-o2_x[p2]; ay = o2_y[p3]-o2_y[p2]; az = o2_z[p3]-o2_z[p2];
    bx = o2_x[p1]-o2_x[p2]; by = o2_y[p1]-o2_y[p2]; bz = o2_z[p1]-o2_z[p2];

    nx = ay*bz-az*by; ny = az*bx-ax*bz; nz = ax*by-ay*bx;

    n = 1/Math.sqrt(nx*nx+ny*ny+nz*nz);

    o2_nx[poly] = nx*n;
    o2_ny[poly] = ny*n;
    o2_nz[poly] = nz*n;
  }



//---- PlaneDist

  public double planedist(int ptr, double x, double y, double z) {
    return bsp_nx[ptr]*(x-bsp_x[ptr]) +
           bsp_ny[ptr]*(y-bsp_y[ptr]) +
           bsp_nz[ptr]*(z-bsp_z[ptr]);
  }



//---- NeedSplit

  //  Returns non-zero if polygon at poly is split by bsp plane at ptr.

  public int needsplit(int poly, int ptr) {

    int i, l, r;
    double d;

    l=0; r=0;

    for(i=0; i<polystack_num[poly]; i++) {

      if(bsp_nx[ptr]*(polystack_x[poly][i]-bsp_x[ptr]) +
         bsp_ny[ptr]*(polystack_y[poly][i]-bsp_y[ptr]) +
         bsp_nz[ptr]*(polystack_z[poly][i]-bsp_z[ptr]) < 0) {
        l++;
      } else {
        r++;
      }

      if(l>0 && r>0) { return 1; }
    }

    return 0;
  }



//---- SplitLine

  double split_x, split_y, split_z;
  double split_xx, split_yy, split_zz;
  double split_cx, split_cy, split_cz;

  public void splitline(int ptr) {

    double d1 = planedist(ptr, split_x, split_y, split_z);
    double d2 = planedist(ptr, split_xx, split_yy, split_zz);
  
    if(d1<0) d1 =- d1;
    if(d2<0) d2 =- d2;

    split_cx = split_x + d1*(split_xx-split_x)/(d1+d2);
    split_cy = split_y + d1*(split_yy-split_y)/(d1+d2);
    split_cz = split_z + d1*(split_zz-split_z)/(d1+d2);

  }



//---- SplitPoly

  //  Splits the polygon at stack position poly using the bsp plane at ptr.
  //  Returns the stack position of the half of the poly in front of the plane
  //  and the half behind the plane is is stored at poly.

  public int splitpoly(int poly, int ptr) {

    int i, j, n1, n2;

    //- First check which points need to be clipped
  
    for(i=0; i<polystack_num[poly]; i++) {
      if(bsp_nx[ptr]*(polystack_x[poly][i]-bsp_x[ptr]) +
         bsp_ny[ptr]*(polystack_y[poly][i]-bsp_y[ptr]) +
         bsp_nz[ptr]*(polystack_z[poly][i]-bsp_z[ptr]) < 0) {
        polystack_clip[poly][i] = -1;
      } else {
        polystack_clip[poly][i] = 1;
      }
    }

    //- Go around edge of polygon clipping lines which straddle plane

    n1 = 0;
    n2 = 0;

    for(i=0; i<polystack_num[poly]; i++) {
      j = i+1; if(j == polystack_num[poly]) { j = 0; }

      split_x = polystack_x[poly][i];
      split_y = polystack_y[poly][i];
      split_z = polystack_z[poly][i];
      split_xx = polystack_x[poly][j];
      split_yy = polystack_y[poly][j];
      split_zz = polystack_z[poly][j];

      if(polystack_clip[poly][i] < 0 && polystack_clip[poly][j] < 0) {

        // Both points outside

        polystack_x[polystack_sp+1][n2] = split_x;
        polystack_y[polystack_sp+1][n2] = split_y;
        polystack_z[polystack_sp+1][n2] = split_z;
        n2++;

      } else if(polystack_clip[poly][i] < 0 && polystack_clip[poly][j] > 0) {

        // First point outside, second inside

        splitline(ptr);

        polystack_x[polystack_sp][n1] = split_cx;
        polystack_y[polystack_sp][n1] = split_cy;
        polystack_z[polystack_sp][n1] = split_cz;
        n1++;

        polystack_x[polystack_sp+1][n2] = split_x;
        polystack_y[polystack_sp+1][n2] = split_y;
        polystack_z[polystack_sp+1][n2] = split_z;
        n2++;

        polystack_x[polystack_sp+1][n2] = split_cx;
        polystack_y[polystack_sp+1][n2] = split_cy;
        polystack_z[polystack_sp+1][n2] = split_cz;
        n2++;

      } else if(polystack_clip[poly][i] > 0 && polystack_clip[poly][j] < 0) {

        // First point inside, second outside

        splitline(ptr);

        polystack_x[polystack_sp][n1] = split_x;
        polystack_y[polystack_sp][n1] = split_y;
        polystack_z[polystack_sp][n1] = split_z;
        n1++;

        polystack_x[polystack_sp][n1] = split_cx;
        polystack_y[polystack_sp][n1] = split_cy;
        polystack_z[polystack_sp][n1] = split_cz;
        n1++;

        polystack_x[polystack_sp+1][n2] = split_cx;
        polystack_y[polystack_sp+1][n2] = split_cy;
        polystack_z[polystack_sp+1][n2] = split_cz;
        n2++;

      } else {

        // Both points inside

        polystack_x[polystack_sp][n1] = split_x;
        polystack_y[polystack_sp][n1] = split_y;
        polystack_z[polystack_sp][n1] = split_z;
        n1++;

      }
    }

    //  Poly becomes one of the clipped polygons

    for(i=0; i<n2; i++) {
      polystack_x[poly][i] = polystack_x[polystack_sp+1][i];
      polystack_y[poly][i] = polystack_y[polystack_sp+1][i];
      polystack_z[poly][i] = polystack_z[polystack_sp+1][i];
    }
    polystack_num[poly] = n2;

    polystack_cx[poly] = (polystack_x[poly][0] + polystack_x[poly][1] + polystack_x[poly][2]) * (1.0/3.0);
    polystack_cy[poly] = (polystack_y[poly][0] + polystack_y[poly][1] + polystack_y[poly][2]) * (1.0/3.0);
    polystack_cz[poly] = (polystack_z[poly][0] + polystack_z[poly][1] + polystack_z[poly][2]) * (1.0/3.0);

    //  The other is in the new polystack element

    polystack_num[polystack_sp] = n1;
    polystack_nx[polystack_sp] = polystack_nx[poly];
    polystack_ny[polystack_sp] = polystack_ny[poly];
    polystack_nz[polystack_sp] = polystack_nz[poly];

    polystack_cx[polystack_sp] = (polystack_x[polystack_sp][0] + polystack_x[polystack_sp][1] + polystack_x[polystack_sp][2]) * (1.0/3.0);
    polystack_cy[polystack_sp] = (polystack_y[polystack_sp][0] + polystack_y[polystack_sp][1] + polystack_y[polystack_sp][2]) * (1.0/3.0);
    polystack_cz[polystack_sp] = (polystack_z[polystack_sp][0] + polystack_z[polystack_sp][1] + polystack_z[polystack_sp][2]) * (1.0/3.0);

    polystack_sp++;

    return polystack_sp-1;
  }



//---- Line

  public void line(double x1, double y1, double x2, double y2) {
    int i, x, y;

    for(i=0; i<100; i++) {
      x = (int)(x1 + (x2-x1)*i/100);
      y = (int)(y1 + (y2-y1)*i/100);

      if(x>=0 && x<image_w && y>=0 && y<image_h) {
        buf[x+image_w*y] = (byte)255;
      }
    }
  }



//---- POLYGON ROUTINES ----------------------------------------------------//

//---- Poly_Clear

  public void poly_clear() {
    int i;

    poly_ymin = image_h;
    poly_ymax = 0;

    for(i=0; i<image_h; i++) {
      poly_xmin[i] = image_w;
      poly_xmax[i] = 0;
    }
  }



//---- Poly_Line

  public void poly_line(double x1, double y1, double x2, double y2) {
    double t;
    int x, y, i;
    int iy1, iy2;

    if(y2>y1) {

      // line going down - right hand side

      iy1 = (int)(y1)+1;
      iy2 = (int)(y2)+1;

      if(iy1 >= image_h) { return; }
      if(iy2 <= 0) { return; }
      if(iy1 < 0) { iy1 = 0; }
      if(iy2 > image_h) { iy2 = image_h; }

      if(iy1 < poly_ymin) { poly_ymin = iy1; }
      if(iy2 > poly_ymax) { poly_ymax = iy2; }

      for(y=iy1; y<iy2; y++) {
        x = (int)(x1 + (x2-x1)*(y-y1)/(y2-y1));
        if(x > image_w) { x = image_w; }
        if(x < 0) { x = 0; }
        poly_xmax[y] =  x;
      }

    } else {

      // line going up - left hand side

      t = x1; x1 = x2; x2 = t;
      t = y1; y1 = y2; y2 = t;

      iy1 = (int)(y1)+1;
      iy2 = (int)(y2)+1;

      if(iy1 >= image_h) { return; }
      if(iy2 <= 0) { return; }
      if(iy1 < 0) { iy1 = 0; }
      if(iy2 > image_h) { iy2 = image_h; }

      if(iy1 < poly_ymin) { poly_ymin = iy1; }
      if(iy2 > poly_ymax) { poly_ymax = iy2; }

      for(y=iy1; y<iy2; y++) {
        x = (int)(x1 + (x2-x1)*(y-y1)/(y2-y1));
        if(x > image_w) { x = image_w; }
        if(x < 0) { x = 0; }
        poly_xmin[y] = x;
      }

    }

  }




//---- Poly_Fill_Col

  public void poly_fill_col(byte c) {
    int x, y, o, oo;

    oo = image_w*poly_ymin;

    for(y=poly_ymin; y<poly_ymax; y++) {
      o = oo + poly_xmin[y];
      for(x=poly_xmin[y]; x<poly_xmax[y]; x++) buf[o++] = c;

      //  TEMP - draw backfacing as well
      o = oo + poly_xmax[y];
      for(x=poly_xmax[y]; x<poly_xmin[y]; x++) buf[o++] = c;

      oo += image_w;
    }

  }



//---- Poly_Fill_Alpha

  public void poly_fill_alpha(byte c) {
    int x, y, o, oo;

    oo = image_w*poly_ymin;

    for(y=poly_ymin; y<poly_ymax; y++) {
      o = oo + poly_xmin[y];
      for(x=poly_xmin[y]; x<poly_xmax[y]; x++) { buf[o] = poly_alpha[(c<<8)+buf[o]]; o++; }

      //  TEMP - draw backfacing as well
      o = oo + poly_xmax[y];
      for(x=poly_xmax[y]; x<poly_xmin[y]; x++) { buf[o] = poly_alpha[(c<<8)+buf[o]]; o++; }

      oo += image_w;
    }

  }



//---- Poly_Fill_Add

  public void poly_fill_add(byte c) {
    int x, y, o, oo;

    oo = image_w*poly_ymin;

    for(y=poly_ymin; y<poly_ymax; y++) {
      o = oo + poly_xmin[y];
      for(x=poly_xmin[y]; x<poly_xmax[y]; x++) buf[o++] += c;

      //  TEMP - draw backfacing as well
      o = oo + poly_xmax[y];
      for(x=poly_xmax[y]; x<poly_xmin[y]; x++) buf[o++] += c;

      oo += image_w;
    }

  }



//---- Poly2_Clear

  public void poly2_clear() {
    int i;

    poly2_ymin = image_h;
    poly2_ymax = 0;

    for(i=0; i<image_h; i++) {
      poly2_xmin[i] = image_w;
      poly2_xmax[i] = 0;
    }
  }



//---- Poly2_Line

  public void poly2_line(double x1, double y1, double x2, double y2) {
    double t;
    int x, y, i;
    int iy1, iy2;

//    x1 = image_w-x1;
//    x2 = image_w-x2;

    if(y2>y1) {

      // line going down - right hand side

      iy1 = (int)(y1)+1;
      iy2 = (int)(y2)+1;

      if(iy1 >= image_h) { return; }
      if(iy2 <= 0) { return; }
      if(iy1 < 0) { iy1 = 0; }
      if(iy2 > image_h) { iy2 = image_h; }

      if(iy1 < poly2_ymin) { poly2_ymin = iy1; }
      if(iy2 > poly2_ymax) { poly2_ymax = iy2; }

      for(y=iy1; y<iy2; y++) {
        x = (int)(x1 + (x2-x1)*(y-y1)/(y2-y1));
        if(x > image_w) { x = image_w; }
        if(x < 0) { x = 0; }
        poly2_xmin[y] =  x;
      }

    } else {

      // line going up - left hand side

      t = x1; x1 = x2; x2 = t;
      t = y1; y1 = y2; y2 = t;

      iy1 = (int)(y1)+1;
      iy2 = (int)(y2)+1;

      if(iy1 >= image_h) { return; }
      if(iy2 <= 0) { return; }
      if(iy1 < 0) { iy1 = 0; }
      if(iy2 > image_h) { iy2 = image_h; }

      if(iy1 < poly2_ymin) { poly2_ymin = iy1; }
      if(iy2 > poly2_ymax) { poly2_ymax = iy2; }

      for(y=iy1; y<iy2; y++) {
        x = (int)(x1 + (x2-x1)*(y-y1)/(y2-y1));
        if(x > image_w) { x = image_w; }
        if(x < 0) { x = 0; }
        poly2_xmax[y] = x;
      }

    }

  }



//---- Poly2_Fill_Col

  public void poly2_fill_col(byte c) {
    int x, y, o, oo;
    int t;

    if(poly2_ymin < poly_ymin) { poly2_ymin = poly_ymin; }
    if(poly2_ymax > poly_ymax) { poly2_ymax = poly_ymax; }

    if(poly2_ymin < 0) { poly2_ymin = 0; }
    if(poly2_ymax > image_h) { poly2_ymax = image_h; }

    oo = image_w*poly2_ymin;

    for(y=poly2_ymin; y<poly2_ymax; y++) {

      if(poly2_xmin[y] < poly_xmin[y]) { poly2_xmin[y] = poly_xmin[y]; }
      if(poly2_xmax[y] > poly_xmax[y]) { poly2_xmax[y] = poly_xmax[y]; }

      if(poly2_xmin[y] < 0) { poly2_xmin[y] = 0; }
      if(poly2_xmax[y] > image_w) { poly2_xmax[y] = image_w; }

      o = oo + poly2_xmin[y];
      for(x=poly2_xmin[y]; x<poly2_xmax[y]; x++) buf[o++] = c;

      oo += image_w;
    }

  }



//---- Poly2_Fill_Add

  public void poly2_fill_add(byte c) {
    int x, y, o, oo;
    int t;

    if(poly2_ymin < poly_ymin) { poly2_ymin = poly_ymin; }
    if(poly2_ymax > poly_ymax) { poly2_ymax = poly_ymax; }

    if(poly2_ymin < 0) { poly2_ymin = 0; }
    if(poly2_ymax > image_h) { poly2_ymax = image_h; }

    oo = image_w*poly2_ymin;

    for(y=poly2_ymin; y<poly2_ymax; y++) {

      if(poly2_xmin[y] < poly_xmin[y]) { poly2_xmin[y] = poly_xmin[y]; }
      if(poly2_xmax[y] > poly_xmax[y]) { poly2_xmax[y] = poly_xmax[y]; }

      if(poly2_xmin[y] < 0) { poly2_xmin[y] = 0; }
      if(poly2_xmax[y] > image_w) { poly2_xmax[y] = image_w; }

      o = oo + poly2_xmin[y];
      for(x=poly2_xmin[y]; x<poly2_xmax[y]; x++) buf[o++] += c;

      oo += image_w;
    }

  }



//---- BSP ROUTINES --------------------------------------------------------//

//---- BSP_Clear

  public void bsp_clear() {
    bsp_num = 0;
    polystack_sp = 0;
    polystack_bp = 0;
  }



//---- BSP_Add_o1

  //  This is a simple adding routine because o1 is put in the BSP tree first.

  public void bsp_add_o1(int poly, int p1, int p2, int p3) {

    double x, y, z;
    int ptr;

    //  Ignore backfacing polygons

    if(o1_tnx[poly]*o1_tx[p1] +
       o1_tny[poly]*o1_ty[p1] +
       o1_tnz[poly]*o1_tz[p1] > 0) return;

    //  If tree empty just put polygon as root

    if(bsp_num == 0) {

      bsp_object[bsp_num] = 1;

      bsp_poly_num[bsp_num] = 3;
      bsp_poly_sx[bsp_num][0] = o1_sx[p1]; bsp_poly_sy[bsp_num][0] = o1_sy[p1];
      bsp_poly_sx[bsp_num][1] = o1_sx[p2]; bsp_poly_sy[bsp_num][1] = o1_sy[p2];
      bsp_poly_sx[bsp_num][2] = o1_sx[p3]; bsp_poly_sy[bsp_num][2] = o1_sy[p3];

      bsp_x[bsp_num] = o1_tx[p1];
      bsp_y[bsp_num] = o1_ty[p1];
      bsp_z[bsp_num] = o1_tz[p1];
      bsp_nx[bsp_num] = o1_tnx[poly];
      bsp_ny[bsp_num] = o1_tny[poly];
      bsp_nz[bsp_num] = o1_tnz[poly];
/*
      bsp_x[bsp_num] = 0;
      bsp_y[bsp_num] = 0;
      bsp_z[bsp_num] = 5;
      bsp_nx[bsp_num] = 0;
      bsp_ny[bsp_num] = 0;
      bsp_nz[bsp_num] = 1;
*/
      bsp_left[bsp_num] = -1;
      bsp_right[bsp_num] = -1;

      bsp_num++;

    } else if(bsp_num < bsp_size) {

      //  Add to end of BSP array

      bsp_object[bsp_num] = 1;

      bsp_poly_num[bsp_num] = 3;
      bsp_poly_sx[bsp_num][0] = o1_sx[p1]; bsp_poly_sy[bsp_num][0] = o1_sy[p1];
      bsp_poly_sx[bsp_num][1] = o1_sx[p2]; bsp_poly_sy[bsp_num][1] = o1_sy[p2];
      bsp_poly_sx[bsp_num][2] = o1_sx[p3]; bsp_poly_sy[bsp_num][2] = o1_sy[p3];

      bsp_x[bsp_num] = o1_tx[p1];
      bsp_y[bsp_num] = o1_ty[p1];
      bsp_z[bsp_num] = o1_tz[p1];
      bsp_nx[bsp_num] = o1_tnx[poly];
      bsp_ny[bsp_num] = o1_tny[poly];
      bsp_nz[bsp_num] = o1_tnz[poly];

      bsp_left[bsp_num] = -1;
      bsp_right[bsp_num] = -1;

      //  Add to tree

      ptr = 0;

      x = (o1_tx[p1] + o1_tx[p2] + o1_tx[p3]) * (1.0/3.0);
      y = (o1_ty[p1] + o1_ty[p2] + o1_ty[p3]) * (1.0/3.0);
      z = (o1_tz[p1] + o1_tz[p2] + o1_tz[p3]) * (1.0/3.0);

      while(ptr != -1) {

        if(bsp_object[ptr] == 1) {

          //  If it's this object just use a point within this poly

          if(bsp_nx[ptr]*(x-bsp_x[ptr]) +
             bsp_ny[ptr]*(y-bsp_y[ptr]) +
             bsp_nz[ptr]*(z-bsp_z[ptr]) < 0) {

            if(bsp_left[ptr] == -1) {
              bsp_left[ptr] = bsp_num;
              bsp_num ++;
              ptr = -1;
            } else {
              ptr = bsp_left[ptr];
            }

          } else {

            if(bsp_right[ptr] == -1) {
              bsp_right[ptr] = bsp_num;
              bsp_num ++;
              ptr = -1;
            } else {
              ptr = bsp_right[ptr];
            }

          }

        } else {

          System.out.println("ERROR: Object 1 not alone in BSP tree");

        }

      }

    }

  }



//---- BSP_Add_o2

  public void bsp_add_o2(int poly, int p1, int p2, int p3, int p4) {

    double x, y, z;
    int ptr;
/*
    //  Ignore backfacing polygons

    if(o2_tnx[poly]*o2_tx[p1] +
       o2_tny[poly]*o2_ty[p1] +
       o2_tnz[poly]*o2_tz[p1] > 0) return;
*/
    //  Put this polygon on stack

    polystack_num[polystack_sp] = 4;
    polystack_x[polystack_sp][0] = o2_tx[p1];
    polystack_y[polystack_sp][0] = o2_ty[p1];
    polystack_z[polystack_sp][0] = o2_tz[p1];
    polystack_x[polystack_sp][1] = o2_tx[p2];
    polystack_y[polystack_sp][1] = o2_ty[p2];
    polystack_z[polystack_sp][1] = o2_tz[p2];
    polystack_x[polystack_sp][2] = o2_tx[p3];
    polystack_y[polystack_sp][2] = o2_ty[p3];
    polystack_z[polystack_sp][2] = o2_tz[p3];
    polystack_x[polystack_sp][3] = o2_tx[p4];
    polystack_y[polystack_sp][3] = o2_ty[p4];
    polystack_z[polystack_sp][3] = o2_tz[p4];

    polystack_nx[polystack_sp] = o2_tnx[poly];
    polystack_ny[polystack_sp] = o2_tny[poly];
    polystack_nz[polystack_sp] = o2_tnz[poly];

    polystack_cx[polystack_sp] = (o2_tx[p1] + o2_tx[p2] + o2_tx[p3]) * (1.0/3.0);
    polystack_cy[polystack_sp] = (o2_ty[p1] + o2_ty[p2] + o2_ty[p3]) * (1.0/3.0);
    polystack_cz[polystack_sp] = (o2_tz[p1] + o2_tz[p2] + o2_tz[p3]) * (1.0/3.0);

    polystack_sp++;
    bsp_add_o2_recurse(0, polystack_sp-1);
    polystack_sp--;

  }



  //---- BSP_Add_o2_Recurse

  public void bsp_add_o2_recurse(int ptr, int poly) {

    int split;
    double sx, sy;
    int i, j;

    //  Check if the poly needs splitting at this node.

    split = 0;
    if(bsp_object[ptr] != 2) {
      split = needsplit(poly, ptr);
    }

    if(split == 0) {

      //  No split - just add in front or behind depending on center point

      if(bsp_nx[ptr]*(polystack_cx[poly]-bsp_x[ptr]) +
         bsp_ny[ptr]*(polystack_cy[poly]-bsp_y[ptr]) +
         bsp_nz[ptr]*(polystack_cz[poly]-bsp_z[ptr]) < 0) {

        if(bsp_left[ptr] != -1) {
          bsp_add_o2_recurse(bsp_left[ptr], poly);
        } else {
          bsp_left[ptr] = bsp_add_o2_poly(poly);
        }

      } else {

        if(bsp_right[ptr] != -1) {
          bsp_add_o2_recurse(bsp_right[ptr], poly);
        } else {
          bsp_right[ptr] = bsp_add_o2_poly(poly);
        }

      }

    } else {

      // Split polygon

      int sp = polystack_sp;

      split = splitpoly(poly, ptr);

      if(bsp_left[ptr] != -1) {
        bsp_add_o2_recurse(bsp_left[ptr], poly);
      } else {
        bsp_left[ptr] = bsp_add_o2_poly(poly);
      }

      if(bsp_right[ptr] != -1) {
        bsp_add_o2_recurse(bsp_right[ptr], split);
      } else {
        bsp_right[ptr] = bsp_add_o2_poly(split);
      }

      polystack_sp = sp;

    }

  }



  //---- BSP_Add_o2_Poly

  public int bsp_add_o2_poly(int poly) {

    int i;
    double sx, sy;

    bsp_object[bsp_num] = 2;

    bsp_poly_num[bsp_num] = polystack_num[poly];
    for(i=0; i<polystack_num[poly]; i++) {
      bsp_poly_x[bsp_num][i] = polystack_x[poly][i];
      bsp_poly_y[bsp_num][i] = polystack_y[poly][i];
      bsp_poly_z[bsp_num][i] = polystack_z[poly][i];
      sx = (image_w*0.5) + 100.0*polystack_x[poly][i]/polystack_z[poly][i];
      sy = (image_h*0.5) - 100.0*polystack_y[poly][i]/polystack_z[poly][i];
      bsp_poly_sx[bsp_num][i] = sx; bsp_poly_sy[bsp_num][i] = sy;
    }

    bsp_x[bsp_num] = polystack_x[poly][0];
    bsp_y[bsp_num] = polystack_y[poly][0];
    bsp_z[bsp_num] = polystack_z[poly][0];
    bsp_nx[bsp_num] = polystack_nx[poly];
    bsp_ny[bsp_num] = polystack_ny[poly];
    bsp_nz[bsp_num] = polystack_nz[poly];

    bsp_left[bsp_num] = -1;
    bsp_right[bsp_num] = -1;

    bsp_num++;

    return bsp_num-1;
  }



//---- BSP_Reflect_Recurse

  public void bsp_reflect_recurse(int ptr, int refl) {
    int i, j;
    int left;
    byte col;
    double npa;
    double x, y, z, xx, yy, zz, sx, sy, sxx, syy;

    if(ptr == -1) { return; }

    left = 1;
    if(bsp_nx[ptr]*bsp_x[ptr] +
       bsp_ny[ptr]*bsp_y[ptr] +
       bsp_nz[ptr]*bsp_z[ptr] < 0) { left = -1; }

    //  Do far branch

    if(left < 0) {
      bsp_reflect_recurse(bsp_left[ptr], refl);
    } else {
      bsp_reflect_recurse(bsp_right[ptr], refl);
    }

    //  Draw polygon

    poly2_clear();

    i = ptr;
    x = bsp_poly_x[i][bsp_poly_num[i]-1];
    y = bsp_poly_y[i][bsp_poly_num[i]-1];
    z = bsp_poly_z[i][bsp_poly_num[i]-1];

    npa = bsp_nx[refl]*(x-bsp_x[refl]) +
          bsp_ny[refl]*(y-bsp_y[refl]) +
          bsp_nz[refl]*(z-bsp_z[refl]);

    x -= 2*bsp_nx[refl]*npa;
    y -= 2*bsp_ny[refl]*npa;
    z -= 2*bsp_nz[refl]*npa;

    sx = (image_w*0.5) + 100.0*x/z;
    sy = (image_h*0.5) - 100.0*y/z;

    for(j=0; j<bsp_poly_num[i]; j++) {
      xx = x; yy = y; zz = z;
      sxx = sx; syy = sy;

      x = bsp_poly_x[i][j];
      y = bsp_poly_y[i][j];
      z = bsp_poly_z[i][j];

      npa = bsp_nx[refl]*(x-bsp_x[refl]) +
            bsp_ny[refl]*(y-bsp_y[refl]) +
            bsp_nz[refl]*(z-bsp_z[refl]);

      x -= 2*bsp_nx[refl]*npa;
      y -= 2*bsp_ny[refl]*npa;
      z -= 2*bsp_nz[refl]*npa;

      sx = (image_w*0.5) + 100.0*x/z;
      sy = (image_h*0.5) - 100.0*y/z;

      poly2_line(sxx, syy, sx, sy);
    }

    if(bsp_object[ptr] == 2) {

      x = bsp_nx[ptr];
      y = bsp_ny[ptr];
      z = bsp_nz[ptr];

      npa = bsp_nx[refl]*x +
            bsp_ny[refl]*y +
            bsp_nz[refl]*z;

      x -= 2*bsp_nx[refl]*npa;
      y -= 2*bsp_ny[refl]*npa;
      z -= 2*bsp_nz[refl]*npa;

      col = (byte)(32+31*x);
      poly2_fill_col(col);
    }

    //  Do near branch

    if(left < 0) {
      bsp_reflect_recurse(bsp_right[ptr], refl);
    } else {
      bsp_reflect_recurse(bsp_left[ptr], refl);
    }

  }



//---- BSP_Recurse

  public void bsp_recurse(int ptr) {
    int i, j;
    int left;
    byte col;

    if(ptr == -1) { return; }

    left = 1;
    if(bsp_nx[ptr]*bsp_x[ptr] +
       bsp_ny[ptr]*bsp_y[ptr] +
       bsp_nz[ptr]*bsp_z[ptr] < 0) { left = -1; }

//    System.out.print(ptr);
//    System.out.print(",");
//    System.out.println(left);

    //  Do far branch

    if(left < 0) {
      bsp_recurse(bsp_left[ptr]);
    } else {
      bsp_recurse(bsp_right[ptr]);
    }

    //  Draw polygon

    poly_clear();

    i = ptr;
    for(j=0; j<bsp_poly_num[i]-1; j++)
      poly_line(bsp_poly_sx[i][j], bsp_poly_sy[i][j], bsp_poly_sx[i][j+1], bsp_poly_sy[i][j+1]);
    poly_line(bsp_poly_sx[i][j], bsp_poly_sy[i][j], bsp_poly_sx[i][0], bsp_poly_sy[i][0]);

    if(bsp_object[ptr] == 1) {
      poly_fill_col((byte)0);
    } else {
      col = (byte)(32+31*bsp_nx[ptr]);
      poly_fill_col(col);
    }

    //  If it's reflective do more stuff

    if(bsp_object[ptr] == 1) {
      if(left < 0) {
        bsp_reflect_recurse(bsp_right[ptr], ptr);
      } else {
        bsp_reflect_recurse(bsp_left[ptr], ptr);
      }

      col = (byte)(64+32+31*bsp_nx[ptr]);
      poly_fill_add(col);
    }

    //  Do near branch

    if(left < 0) {
      bsp_recurse(bsp_right[ptr]);
    } else {
      bsp_recurse(bsp_left[ptr]);
    }

  }



//---- BSP_Render

  public void bsp_render() {
    if(bsp_num > 0) bsp_recurse(0);
  }




//---- RENDER ROUTINES -----------------------------------------------------//

//---- Redraw

  int k=0;

  public void redraw() {

    int i, j, o;
    char r;
    int x, y;
    double sx1, sy1, sx2, sy2;

    //  Clear buffer

    for(i=0; i<image_w*image_h; i++) buf[i] = back[i];

    //  Change object positions

    if(pause == 0) {
      o1_rx += 1; o1_ry += 17; o1_rz -= 3;
      o2_rx -= 7; o2_ry -= 9; o2_rz += 4;
    }

    //  Transform all points in object 1

    maketrans(o1_rx, o1_ry, o1_rz);

    for(i=0; i<o1_numpoints; i++) {
      o1_tx[i] = m[0][0]*o1_x[i] + m[0][1]*o1_y[i] + m[0][2]*o1_z[i] + o1_cx;
      o1_ty[i] = m[1][0]*o1_x[i] + m[1][1]*o1_y[i] + m[1][2]*o1_z[i] + o1_cy;
      o1_tz[i] = m[2][0]*o1_x[i] + m[2][1]*o1_y[i] + m[2][2]*o1_z[i] + o1_cz;
                                                                   
      o1_sx[i] = (image_w*0.5) + 100.0*o1_tx[i]/o1_tz[i];
      o1_sy[i] = (image_h*0.5) - 100.0*o1_ty[i]/o1_tz[i];
/*
      x = (int)o1_sx[i];
      y = (int)o1_sy[i];

      if(x>=0 && x<image_w && y>=0 && y<image_h) {
        buf[x+image_w*y] = (byte)255;
      }
*/
    }

    for(i=0; i<o1_numfaces; i++) {
      o1_tnx[i] = m[0][0]*o1_nx[i] + m[0][1]*o1_ny[i] + m[0][2]*o1_nz[i];
      o1_tny[i] = m[1][0]*o1_nx[i] + m[1][1]*o1_ny[i] + m[1][2]*o1_nz[i];
      o1_tnz[i] = m[2][0]*o1_nx[i] + m[2][1]*o1_ny[i] + m[2][2]*o1_nz[i];
    }

    //  Transform all points in object 2

    maketrans(o2_rx, o2_ry, o2_rz);

    for(i=0; i<o2_numpoints; i++) {
      o2_tx[i] = m[0][0]*o2_x[i] + m[0][1]*o2_y[i] + m[0][2]*o2_z[i] + o2_cx;
      o2_ty[i] = m[1][0]*o2_x[i] + m[1][1]*o2_y[i] + m[1][2]*o2_z[i] + o2_cy;
      o2_tz[i] = m[2][0]*o2_x[i] + m[2][1]*o2_y[i] + m[2][2]*o2_z[i] + o2_cz;
                                                                   
      o2_sx[i] = (image_w*0.5) + 100.0*o2_tx[i]/o2_tz[i];
      o2_sy[i] = (image_h*0.5) - 100.0*o2_ty[i]/o2_tz[i];
/*
      x = (int)o2_sx[i];
      y = (int)o2_sy[i];

      if(x>=0 && x<image_w && y>=0 && y<image_h) {
        buf[x+image_w*y] = (byte)255;
      }
*/
    }

    for(i=0; i<o2_numfaces; i++) {
      o2_tnx[i] = m[0][0]*o2_nx[i] + m[0][1]*o2_ny[i] + m[0][2]*o2_nz[i];
      o2_tny[i] = m[1][0]*o2_nx[i] + m[1][1]*o2_ny[i] + m[1][2]*o2_nz[i];
      o2_tnz[i] = m[2][0]*o2_nx[i] + m[2][1]*o2_ny[i] + m[2][2]*o2_nz[i];
    }

    //  Empty BSP tree

    bsp_clear();

    //  Add object 1 to BSP

    bsp_add_o1( 0, 0,  2,  1);
    bsp_add_o1( 1, 1,  2,  3);
    bsp_add_o1( 2, 0,  1,  3);
    bsp_add_o1( 3, 3,  2,  0);
/*
*/

    //  Add object 2 to BSP

    bsp_add_o2( 0,  0,  4,  5,  1);
    bsp_add_o2( 4,  4,  8,  9,  5);
    bsp_add_o2( 8,  8, 12, 13,  9);
    bsp_add_o2(12, 12,  0,  1, 13);

    bsp_add_o2( 2,  2,  6,  7,  3);
    bsp_add_o2( 6,  6, 10, 11,  7);
    bsp_add_o2(10, 10, 14, 15, 11);
    bsp_add_o2(14, 14,  2,  3, 15);

/*
    for(i=0; i<8; i++) {
      System.out.print("bsp: (");
      System.out.print(bsp_nx[i]);
      System.out.print(", ");
      System.out.print(bsp_ny[i]);
      System.out.print(", ");
      System.out.print(bsp_nz[i]);
      System.out.print(")  :  ");
      System.out.println(bsp_nx[i]*bsp_x[i]+bsp_ny[i]*bsp_y[i]+bsp_nz[i]*bsp_z[i]);
    }

    System.out.print("left: (");
    for(i=0; i<8; i++) {
      System.out.print(bsp_left[i]);
      System.out.print("  ");
    }
    System.out.println("");

    System.out.print("right: (");
    for(i=0; i<8; i++) {
      System.out.print(bsp_right[i]);
      System.out.print("  ");
    }
    System.out.println("");
*/

    bsp_add_o2( 3,  3,  7,  4,  0);
    bsp_add_o2( 7,  7, 11,  8,  4);
    bsp_add_o2(11, 11, 15, 12,  8);
    bsp_add_o2(15, 15,  3,  0, 12);

    bsp_add_o2( 1,  1,  5,  6,  2);
    bsp_add_o2( 5,  5,  9, 10,  6);
    bsp_add_o2( 9,  9, 13, 14, 10);
    bsp_add_o2(13, 13,  1,  2, 14);

    //  Render BSP

    bsp_render();

    //  Put little cornery moving bit

    k = (k+1)&255;

    for(o=0, j=0; j<8; j++, o+=image_w-8) {
      for(i=0; i<8; i++) {
        buf[o++] = (byte)( (((k+i+j)&4)>>2)*64+63 );
      }
    }
/* * /
    for(i=0; i<16; i++) {
      sx1 = (image_w*0.5) + 100.0*bsp_x[i]/bsp_z[i];
      sy1 = (image_w*0.5) - 100.0*bsp_y[i]/bsp_z[i];
      sx2 = (image_w*0.5) + 100.0*(bsp_x[i]+bsp_nx[i])/(bsp_z[i]+bsp_nz[i]);
      sy2 = (image_w*0.5) - 100.0*(bsp_y[i]+bsp_ny[i])/(bsp_z[i]+bsp_nz[i]);
      line(sx1, sy1, sx2, sy2);
    }
/* */
    //  Update screen

    src.newPixels(0, 0, image_w, image_h);
  }



//---- END OF CLASS --------------------------------------------------------//

}

Comments

Source Code Browser
Related Articles

3D Engine with scene graph and cartoon rendering style

Sponsored Links

Toys & Games:

Doggie Doo
Nerf Vortex
Monster High
Lagoona Hydration Station
Milky Bunny
Moshling Tree House
Lego Ninja Go Fire Temple
Fireman Sam Pontypandy Rescue
Rock Elmo
Star Wars Ultimate Force Lightsaber

Games

The Dodge Game
Flatspace

2-Player Games:

Quake 2D
Meteora

Puzzle Games:

Mini Tetris
Sudoku Solver

Development

3D Graphics:

3D Graphics Articles
WebGL Examples
Flash 3D Engine
Java 3D Engine

Development:

Programming Articles
Animation Demos
Game Development Examples

Links

iBuddy Social Network
Local Legends Football
PHP Charts & Graphs
CubeLogix Studios