test.cpp

C++ source for City Block, 791 lines. Raw file

#define WIN32_LEAN_AND_MEAN

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>

#include	"qe_ogl.h"


bool drawBlack = false;



//---- ZSYSTEM TEST VERSION 0.1 ----------------------------------------------//

//---- ZSYSTEM TYPES ---------------------------------------------------------//

typedef struct _ZS_RAND {
  unsigned int a, b, c, d;
} ZS_RAND;



//---- ZSYSTEM DATA ----------------------------------------------------------//

int zs_cubes = 0;
int zs_buildings = 0;



//---- ZSYSTEM FUNCTIONS -----------------------------------------------------//

//---- ZS_Rand_Create --------------------------------------------------------//

ZS_RAND *ZS_Rand_Create(int seed)
{
  ZS_RAND *r = (ZS_RAND *)malloc(sizeof(ZS_RAND));
  if(!r) return NULL;
  r->a = seed + 0x87123631;
  r->b = seed * 3;
  r->c = seed + 0x72319631;
  r->d = seed ^ 0x24121531;
  return r;
}



//---- ZS_Rand_Delete --------------------------------------------------------//

void ZS_Rand_Delete(ZS_RAND *r)
{
  if(!r) return;
  free(r);
}



//---- ZS_Rand ---------------------------------------------------------------//

unsigned int ZS_Rand(ZS_RAND *r, unsigned int max)
{
  r->d ^= (r->c<<9) + (r->a>>7) + (r->d&r->a);

  r->a += r->b>>1;
  r->b += r->c^0xF0F0A05;
  r->c += r->d;
  r->d += 0x35136613;

  unsigned int v = ( (r->a*7 + r->c*6)^((r->b<<13)-(r->d>>3)) );

  if(max == 0) return v;

  return v % max;
}



//---- ZS_Rand_Tween ---------------------------------------------------------//

double ZS_Rand_Tween(ZS_RAND *r, double min, double max)
{
  double t = min + ZS_Rand(r, 1000000)*0.000001*(max-min);
  return t;
}



//---- ZSYSTEM OBJECT: CUBE --------------------------------------------------//

void Cube(double x1, double y1, double z1, double x2, double y2, double z2, double r, double g, double b)
{
  zs_cubes ++;
/*
  int rr, gg, bb;
  rr = zs_cubes*787;
  gg = (zs_cubes*17)^815;
  bb = ((zs_cubes*91)|812)/3;

  r = (rr%1000)*0.001;
  g = (gg%1000)*0.001;
  b = (bb%1000)*0.001;
*/


/*
  double d;
  d = 1.0-(0.0005*x1*0.0005*x1+0.0005*z1*0.0005*z1);

  if(d < 0) return;
  r *= d; g *= d; b *= d;
*/

  if(!drawBlack) glColor3f(r, g, b); else glColor3f(0, 0, 0);

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1, y1, z1);
    glVertex3f(x1, y1, z2);
    glVertex3f(x2, y1, z2);
    glVertex3f(x2, y1, z1);
  glEnd();

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x2, y2, z1);
    glVertex3f(x2, y2, z2);
    glVertex3f(x1, y2, z2);
    glVertex3f(x1, y2, z1);
  glEnd();

  if(!drawBlack) glColor3f(r*0.95, g*0.95, b*0.95); else glColor3f(0, 0, 0);

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1, y2, z1);
    glVertex3f(x1, y2, z2);
    glVertex3f(x1, y1, z2);
    glVertex3f(x1, y1, z1);
  glEnd();

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x2, y1, z1);
    glVertex3f(x2, y1, z2);
    glVertex3f(x2, y2, z2);
    glVertex3f(x2, y2, z1);
  glEnd();

  if(!drawBlack) glColor3f(r*0.90, g*0.90, b*0.90); else glColor3f(0, 0, 0);

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x2, y1, z1);
    glVertex3f(x2, y2, z1);
    glVertex3f(x1, y2, z1);
    glVertex3f(x1, y1, z1);
  glEnd();

  glBegin(GL_TRIANGLE_FAN);
    glVertex3f(x1, y1, z2);
    glVertex3f(x1, y2, z2);
    glVertex3f(x2, y2, z2);
    glVertex3f(x2, y1, z2);
  glEnd();

}

void Cube2(double x1, double y1, double z1, double x2, double y2, double z2, double r, double g, double b)
{
  int i, j;

  for(j=-4; j<=4; j++)
    for(i=-4; i<=4; i++)
      Cube2(x1+i*500, y1, z1+j*500, x2+i*500, y2, z2+j*500, r, g, b);
}



//---- ZSYSTEM OBJECT: BUILDING ----------------------------------------------//

void Building(unsigned int seed, double x1, double z1, double x2, double z2, double y)
{
  zs_buildings ++;

  ZS_RAND *rand = ZS_Rand_Create(seed);

  int i, j, ii, jj;
  double x, z, w, h, d;

  int r = ZS_Rand(rand, 100);

  double lit = ZS_Rand_Tween(rand, 0.8, 1.0);

  if((x2-x1) < 10 || (z2-z1) < 10) {

    //  Nothing - too small

  } else if(r < 40) {

    //  Basic building

    Cube(x1, y, z1, x2, y+ZS_Rand_Tween(rand, 10, 50), z2, 0.8*lit, 0.8*lit, 0.8*lit);

  } else if(r < 60) {

    //  Building with array of blocks on top

    h = ZS_Rand_Tween(rand, 20, 70);
    Cube(x1, y, z1, x2, y+h, z2, 0.75, 0.75, 0.75);

    ii = 1+ZS_Rand(rand, (int)((x2-x1)/3)-1);
    jj = 1+ZS_Rand(rand, (int)((z2-z1)/3)-1);

    w = (x2-x1)/ii;
    d = (z2-z1)/jj;

    for(j=0; j<jj; j++) {
      for(i=0; i<ii; i++) {
        if(ZS_Rand(rand, 100) < 95) Cube(x1+i*w+1, y+h, z1+j*d+1, x1+(i+1)*w-1, y+h+0.5, z1+(j+1)*d-1, 0.6*lit, 0.6*lit, 0.6*lit);
      }
    }

  } else if(r < 90) {

    //  Building with smaller block on top

    h = ZS_Rand_Tween(rand, 20, 70);
    Cube(x1, y, z1, x2, y+h, z2, 0.65*lit, 0.65*lit, 0.65*lit);
    w = ZS_Rand_Tween(rand, (x2-x1)/6, (x2-x1)/3);
    d = ZS_Rand_Tween(rand, (z2-z1)/6, (z2-z1)/3);
    if(d > w*1.5) d = w*1.5;
    if(w > d*1.5) w = d*1.5;
    
    Building(ZS_Rand(rand, 0), x1+w, z1+d, x2-w, z2-d, y+h);

  } else {

    //  Building with array of long blocks

    h = ZS_Rand_Tween(rand, 10, 40);
    Cube(x1, y, z1, x2, y+h, z2, 0.8*lit, 0.8*lit, 0.8*lit);

    if(x2-x1 > z2-z1) {

      ii = ZS_Rand(rand, (int)((x2-x1)/3));
      if(ii > 0) {
        w = (x2-x1)/ii;
        for(i=0; i<ii; i++) {
          Cube(x1+i*w+1, y+h, z1+1, x1+(i+1)*w-1, y+h+1, z2-1, 0.7*lit, 0.7*lit, 0.7*lit);
        }
      }

    } else {

      ii = ZS_Rand(rand, (int)((z2-z1)/3));
      if(ii > 0) {
        d = (z2-z1)/ii;
        for(i=0; i<ii; i++) {
          Cube(x1+1, y+h, z1+i*d+1, x2-1, y+h+1, z1+(i+1)*d-1, 0.7*lit, 0.7*lit, 0.7*lit);
        }
      }

    }

  }

  ZS_Rand_Delete(rand);
}



//---- ZSYSTEM OBJECT: BLOCK -------------------------------------------------//

void Block(unsigned int seed, double x1, double z1, double x2, double z2)
{
  ZS_RAND *rand = ZS_Rand_Create(seed);

  //  Put base

  Cube(x1+3, 0, z1+3, x2-3, 0.1, z2-3, 0.5, 0.5, 0.5);

  //  Put buildings

  int r = ZS_Rand(rand, 100);

  if(r < 10) {

    //  No buildings

    Building(ZS_Rand(rand, 0), x1+8, z1+8, x2-8, z2-8, 0.1);

  } else if(r < 40) {

    //  Symmetrical array of buildings

    Building(ZS_Rand(rand, 0), x1+8, z1+8, (x2+x1)/2-4, z2-8, 0.1);
    Building(ZS_Rand(rand, 0), (x2+x1)/2+4, z1+8, x2-8, z2-8, 0.1);

  } else if(r < 80) {

    //  Randomly placed buildings

    Building(ZS_Rand(rand, 0), x1+8, z1+8, x2-8, z2-8, 0.1);

  } else {

    //  One big building

    Building(ZS_Rand(rand, 0), x1+8, z1+8, x2-8, z2-8, 0.1);

  }

  ZS_Rand_Delete(rand);
}



//---- ZSYSTEM OBJECT: ROAD --------------------------------------------------//

void Road(unsigned int seed, double x1, double z1, double x2, double z2)
{
  ZS_RAND *rand = ZS_Rand_Create(seed);

  //  Put base

  //  Put dashes

  int i, ii;
  double x, y, z;

  if(x2-x1 > z2-z1) {

    z=0.5*(z1+z2);
    for(x=x1; x<x2-1; x+=2) {
      Cube(x, 0, z-0.05, x+1, 0.01, z+0.05, 1, 1, 1);
    }

    for(z=z; z<z2; z+=0.4) {
      Cube(x1, 0, z, x1+0.10, 0.01, z+0.2, 1, 1, 1);
      Cube(x1+0.30, 0, z, x1+0.40, 0.01, z+0.2, 1, 1, 1);
    }

  } else {

    x=0.5*(x1+x2);
    for(z=z1; z<z2-1; z+=2) {
      Cube(x-0.05, 0, z, x+0.05, 0.01, z+1, 1, 1, 1);
    }

    for(x=x; x<x2; x+=0.4) {
      Cube(x, 0, z2-0.40, x+0.2, 0.01, z2-0.30, 1, 1, 1);
      Cube(x, 0, z2-0.10, x+0.2, 0.01, z2-0.00, 1, 1, 1);
    }

  }

  ZS_Rand_Delete(rand);
}



//---- ZSYSTEM OBJECT: SUBURB ------------------------------------------------//

void Suburb(unsigned int seed, double x1, double z1, double x2, double z2, int iter)
{
  ZS_RAND *rand = ZS_Rand_Create(seed);

  //- Check size

  BOOL smallx, smallz, smallrand;
  double x, z;

  smallx = (x2-x1) < 70;
  smallz = (z2-z1) < 70;
  smallrand = (ZS_Rand(rand, 100) < 20 && x2-x1 < 100 && z2-z1 < 100) || iter > 10;

  if(smallrand) {

    Block(ZS_Rand(rand, 0), x1, z1, x2, z2);

  } else if(smallx && smallz) {

    Block(ZS_Rand(rand, 0), x1, z1, x2, z2);

  } else if(smallx) {

    z = ZS_Rand_Tween(rand, z1+23, z2-23);
    Suburb(ZS_Rand(rand, 0), x1, z1, x2, z, iter+1);
    Suburb(ZS_Rand(rand, 0), x1, z, x2, z2, iter+1);

//    Road(ZS_Rand(rand, 0), x1+3, z-3, x2-3, z+3);

  } else if(smallz) {

    x = ZS_Rand_Tween(rand, x1+23, x2-23);
    Suburb(ZS_Rand(rand, 0), x1, z1, x, z2, iter+1);
    Suburb(ZS_Rand(rand, 0), x, z1, x2, z2, iter+1);

//    Road(ZS_Rand(rand, 0), x-3, z1+3, x+3, z2-3);

  } else {

    x = ZS_Rand_Tween(rand, x1+23, x2-15);
    z = ZS_Rand_Tween(rand, z1+23, z2-15);
    Suburb(ZS_Rand(rand, 0), x1, z1, x, z, iter+1);
    Suburb(ZS_Rand(rand, 0), x, z1, x2, z, iter+1);
    Suburb(ZS_Rand(rand, 0), x1, z, x, z2, iter+1);
    Suburb(ZS_Rand(rand, 0), x, z, x2, z2, iter+1);

//    Road(ZS_Rand(rand, 0), x-3, z1+3, x+3, z-3);
//    Road(ZS_Rand(rand, 0), x-3, z+3, x+3, z2-3);
//    Road(ZS_Rand(rand, 0), x1+3, z-3, x-3, z+3);
//    Road(ZS_Rand(rand, 0), x+3, z-3, x2-3, z+3);

    Cube(x-1, 0, z-1, x+1, 0.01, z+1, 0.4, 0.4, 0.4);
  }

  ZS_Rand_Delete(rand);
}



//---- ZSYSTEM OBJECT: CITY --------------------------------------------------//

void City(unsigned int seed, double x1, double z1, double x2, double z2)
{
  ZS_RAND *rand = ZS_Rand_Create(seed);

  //  Place floor poly

//  Cube(x1, -1, z1, x2, 0, z2, 0.1, 0.1, 0.1);

  //  Divide into blocks

  Suburb(ZS_Rand(rand, 0), x1, z1, x2, z2, 0);

  ZS_Rand_Delete(rand);
}



//---- TERRAIN STUFF ---------------------------------------------------------//

bool terrain_startup = false;


//---- Terrain_Startup

void Terrain_Startup()
{
  if(terrain_startup) return;
  terrain_startup = true;

  //- Do any startup stuff

}



//---- Terrain_PosRand

//  Returns numbers distributed [0.0, 1.0) seeded by two floats

float Terrain_PosRand(float x, float z)
{
  unsigned int a = x*984729;
  unsigned int b = z*735161;

  unsigned int r = (a^b)-(a*b) + ((a >> 10)&(b << 2)) - ((a << 2)|(b >> 9));

  return (r%18378276)/18378276.0;
}



//---- Terrain_GetHeight

//  Gets the height of the terrain at the given point

float Terrain_GetHeight(float x, float z)
{
  float scale = 20;

  float sx = scale*((int)(x/scale));
  float sz = scale*((int)(z/scale));
  
  float r00, r01, r10, r11;
  
  int i;

  //- Binary split in fractal terrain to find heights around wanted pos

  r00 = Terrain_PosRand(sx, sz);
  r01 = Terrain_PosRand(sx+scale, sz);
  r10 = Terrain_PosRand(sx, sz+scale);
  r11 = Terrain_PosRand(sx+scale, sz+scale);

  float hscale = 1;

  for(i=0; i<15; i++) {

    scale *= 0.5;

    //- If it's less than half way then bring the window back else move it forward

    float nr00, nr01, nr10, nr11;

    if(sx+scale > x) {
      if(sz+scale > z) {

        nr00 = r00;
        nr01 = 0.5*(r00+r01) + hscale*Terrain_PosRand(sx+scale, sz);
        nr10 = 0.5*(r00+r10) + hscale*Terrain_PosRand(sx, sz+scale);
        nr11 = 0.5*(r00+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale);
      
      } else {
      
        nr00 = 0.5*(r00+r10) + hscale*Terrain_PosRand(sx, sz+scale);
        nr01 = 0.5*(r00+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale);
        nr10 = r10;
        nr11 = 0.5*(r10+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale*2);
      
        sz += scale;
      }
    } else {
      if(sz+scale > z) {

        nr00 = 0.5*(r00+r01) + hscale*Terrain_PosRand(sx+scale, sz);
        nr01 = r01;
        nr10 = 0.5*(r00+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale);
        nr11 = 0.5*(r01+r11) + hscale*Terrain_PosRand(sx+scale*2, sz+scale);

        sx += scale;

      } else {

        nr00 = 0.5*(r00+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale);
        nr01 = 0.5*(r01+r11) + hscale*Terrain_PosRand(sx+scale*2, sz+scale);
        nr10 = 0.5*(r10+r11) + hscale*Terrain_PosRand(sx+scale, sz+scale*2);
        nr11 = r11;

        sx += scale; sz += scale;
      }
    }

    r00 = nr00; r01 = nr01; r10 = nr10; r11 = nr11;

    hscale *= 0.2;
  }

  //- TODO: Bilinear filter to get height

  float r = r00;

  //- Return height

  return 10*r;
}



//---- Terrain_DrawSquare

void Terrain_DrawSquare(float x, float y, float z)
{
  if(x < 0 || z < 0) return;

  float h00 = Terrain_GetHeight(x, z);
  float h01 = Terrain_GetHeight(x+1, z);
  float h10 = Terrain_GetHeight(x, z+1);
  float h11 = Terrain_GetHeight(x+1, z+1);

  glBegin(GL_TRIANGLE_FAN);
    glColor3f(0.3, 0.3, 0.3);
    glVertex3f(x, h00, z);
    glColor3f(0.6, 0.6, 0.6);
    glVertex3f(x+1, h01, z);
    glColor3f(0.9, 0.9, 0.9);
    glVertex3f(x+1, h11, z+1);
    glColor3f(0.6, 0.6, 0.6);
    glVertex3f(x, h10, z+1);
  glEnd();

/*
  glBegin(GL_TRIANGLE_FAN);
    glColor3f(h00, h00, h00); glVertex3f(x, 0, z);
    glColor3f(h01, h01, h01); glVertex3f(x+1, 0, z);
    glColor3f(h11, h11, h11); glVertex3f(x+1, 0, z+1);
    glColor3f(h10, h10, h10); glVertex3f(x, 0, z+1);
  glEnd();
*/

}



//---- Terrain_DrawShape

void Terrain_DrawTri(float x1, float z1, float x2, float z2, float x3, float z3)
{

  float h1 = Terrain_GetHeight(x1, z1);
  float h2 = Terrain_GetHeight(x2, z2);
  float h3 = Terrain_GetHeight(x3, z3);

/*
  glBegin(GL_TRIANGLE_FAN);
    glColor3f(0.3, 0.3, 0.3);
    glVertex3f(x1, h1, z1);
    glColor3f(0.6, 0.6, 0.6);
    glVertex3f(x2, h2, z2);
    glColor3f(0.9, 0.9, 0.9);
    glVertex3f(x3, h3, z3);
  glEnd();
*/

  glBegin(GL_TRIANGLE_FAN);
    glColor3f(h1, h1, h1);
    glVertex3f(x1, 0, z1);
    glColor3f(h2, h2, h2);
    glVertex3f(x2, 0, z2);
    glColor3f(h3, h3, h3);
    glVertex3f(x3, 0, z3);
  glEnd();

}



//---- Terrain_GetPoint

void Terrain_GetPoint(int i, int j, float xo, float zo, float *x, float *z)
{
  float d = i+i*(i-1)/14;
  float a = j*3.14159/16;

  *x = xo+d*sin(a); *z = zo+d*cos(a);
}



//---- Terrain_Draw

//  Draws the terrain in openGL at the given position

void Terrain_Draw(float x, float y, float z)
{
  int i, j;
/*
  for(j=-30; j<=30; j++) for(i=-30; i<=30; i++) Terrain_DrawSquare(x+i, 0, z+j);
*/

  for(j=0; j<=80; j++) for(i=0; i<=80; i++) Terrain_DrawSquare(x+i, 0, z+j);


/*
  float x00, z00, x01, z01, x10, z10, x11, z11;

  for(j=0; j<32; j++) {
    for(i=1; i<20; i++) {

      Terrain_GetPoint(i  , j  , x, z, &x00, &z00);
      Terrain_GetPoint(i+1, j  , x, z, &x01, &z01);
      Terrain_GetPoint(i  , j+1, x, z, &x10, &z10);
      Terrain_GetPoint(i+1, j+1, x, z, &x11, &z11);

      Terrain_DrawTri(x00, z00, x01, z01, x11, z11);
      Terrain_DrawTri(x11, z11, x10, z10, x00, z00);

    }
  }
*/

}



//---- OLD OPENGL STUFF ------------------------------------------------------//

void Initialise()
{

}



void GameDraw(HWND hwnd)
{
  static k=0;
  int citysize = 500;
//  k++;
 
  int i=0, j=0;

  zs_cubes = 0;
  zs_buildings = 0;

//  for(j=-2; j<=2; j++) for(i=-2; i<=2; i++)
    City(0xA749F86C + (i<<17) + (j<<5) + k, -citysize/2 + i*citysize, -citysize/2 + j*citysize, citysize/2 + i*citysize, citysize/2 + j*citysize);

  static int t = 0;
  if(GetTickCount()-t > 500) {
    t = GetTickCount();
    char buf[50];
    sprintf(buf, "City: %d buildings, %d cubes", zs_buildings, zs_cubes);
    SetWindowText(hwnd, buf);
  }

}



double r1=20/0.2, r2=-50/0.2;
double x=0, y=200, z=0;
int moving = 0;



void GameMain(HWND hwnd)
{
  static int s = 0;
  int t = GetTickCount();

  int timediff = t-s;
  if(timediff > 200) timediff = 200;
  s = t;

  {
    double vx = 0, vy = 0, vz = -timediff*0.03*moving;

    double wx, wy, wz;

    wx = vx;
    wy = vy*cos(0.2*r2*3.14159/180)-vz*sin(0.2*r2*3.14159/180);
    wz = -(vy*sin(0.2*r2*3.14159/180)+vz*cos(0.2*r2*3.14159/180));

    vx = wx*cos(0.2*r1*3.14159/180)-wz*sin(0.2*r1*3.14159/180);
    vy = wy;
    vz = -(wx*sin(0.2*r1*3.14159/180)+wz*cos(0.2*r1*3.14159/180));

    x += vx; y += vy; z += vz;
  }

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  drawBlack = false;

	glLoadIdentity();

	glRotatef(-r2*0.2, 1.0, 0.0, 0.0);
	glRotatef(-r1*0.2, 0.0, 1.0, 0.0);

	glTranslatef(-x, -y, -z);
	GameDraw(hwnd);
/*
  drawBlack = true;

	glLoadIdentity();
	glTranslatef(-1, 0, -10);
	glRotatef(-r2*0.2, 1.0, 0.0, 0.0);
	glRotatef(-r1*0.2, 0.0, 1.0, 0.0);
	glTranslatef(-x, -y, -z);
	GameDraw(hwnd);

	glLoadIdentity();
	glTranslatef( 1, 0, -10);
	glRotatef(-r2*0.2, 1.0, 0.0, 0.0);
	glRotatef(-r1*0.2, 0.0, 1.0, 0.0);
	glTranslatef(-x, -y, -z);
	GameDraw(hwnd);

	glLoadIdentity();
	glTranslatef(0, -1, -10);
	glRotatef(-r2*0.2, 1.0, 0.0, 0.0);
	glRotatef(-r1*0.2, 0.0, 1.0, 0.0);
	glTranslatef(-x, -y, -z);
	GameDraw(hwnd);

	glLoadIdentity();
	glTranslatef(0, 1, -10);
	glRotatef(-r2*0.2, 1.0, 0.0, 0.0);
	glRotatef(-r1*0.2, 0.0, 1.0, 0.0);
	glTranslatef(-x, -y, -z);
	GameDraw(hwnd);

*/

	SwapBuffers(gl_dc);
}



//---- END OF FILE -----------------------------------------------------------//