Initial check-in of project.

This commit is contained in:
Shamus Young 2009-05-03 11:05:03 +00:00
parent 92c25d37b3
commit 948502769c
42 changed files with 8709 additions and 0 deletions

848
Building.cpp Normal file
View File

@ -0,0 +1,848 @@
/*-----------------------------------------------------------------------------
Building.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This module contains the class to construct the buildings.
-----------------------------------------------------------------------------*/
#define MAX_VBUFFER 256
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include "glTypes.h"
#include "building.h"
#include "deco.h"
#include "light.h"
#include "mesh.h"
#include "macro.h"
#include "math.h"
#include "random.h"
#include "texture.h"
#include "world.h"
//This is used by the recursive roof builder to decide what items may be added.
enum
{
ADDON_NONE,
ADDON_LOGO,
ADDON_TRIM,
ADDON_LIGHTS,
ADDON_COUNT
};
static GLvector vector_buffer[MAX_VBUFFER];
/*-----------------------------------------------------------------------------
This is the constructor for our building constructor.
-----------------------------------------------------------------------------*/
CBuilding::CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color)
{
_x = x;
_y = y;
_width = width;
_depth = depth;
_height = height;
_center = glVector ((float)(_x + width / 2), 0.0f, (float)(_y + depth / 2));
_seed = seed;
_texture_type = RandomVal ();
_color = color;
_color.alpha = 0.1f;
_have_lights = false;
_have_logo = false;
_have_trim = false;
_roof_tiers = 0;
//Pick a color for logos & roof lights
//_trim_color = WorldLightColor (seed);
_trim_color = glRgbaFromHsl (0.5f, 1.0f, 0.9f);
_mesh = new CMesh; //The main textured mesh for the building
_mesh_flat = new CMesh; //Flat-color mesh for untextured detail items.
switch (type) {
case BUILDING_SIMPLE:
CreateSimple ();
break;
case BUILDING_MODERN:
CreateModern ();
break;
case BUILDING_TOWER:
CreateTower ();
break;
case BUILDING_BLOCKY:
CreateBlocky ();
break;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CBuilding::~CBuilding ()
{
if (_mesh)
delete _mesh;
if (_mesh_flat)
delete _mesh_flat;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned CBuilding::Texture ()
{
return TextureRandomBuilding (_texture_type);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int CBuilding::PolyCount ()
{
return _mesh->PolyCount () + _mesh_flat->PolyCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::Render ()
{
glColor3fv (&_color.red);
_mesh->Render ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::RenderFlat (bool colored)
{
if (colored)
glColor3fv (&_color.red);
_mesh_flat->Render ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::ConstructCube (int left, int right, int front, int back, int bottom, int top)
{
GLvertex p[10];
float x1, x2, z1, z2, y1, y2;
int i;
int index_list[10];
float u, v1, v2;
float mapping;
int base_index;
int height;
height = top - bottom;
x1 = (float)left;
x2 = (float)right;
y1 = (float)bottom;
y2 = (float)top;
z1 = (float)front;
z2 = (float)back;
base_index = _mesh->VertexCount ();
mapping = (float)SEGMENTS_PER_TEXTURE;
u = (float)(RandomVal () % SEGMENTS_PER_TEXTURE) / (float)SEGMENTS_PER_TEXTURE;
v1 = (float)bottom / (float)mapping;
v2 = (float)top / (float)mapping;
p[0].position = glVector (x1, y1, z1); p[0].uv = glVector (u, v1);
p[1].position = glVector (x1, y2, z1); p[1].uv = glVector (u, v2);
u += (float)_width / mapping;
p[2].position = glVector (x2, y1, z1); p[2].uv = glVector (u, v1);
p[3].position = glVector (x2, y2, z1); p[3].uv = glVector (u, v2);
u += (float)_depth / mapping;
p[4].position = glVector (x2, y1, z2); p[4].uv = glVector (u, v1);
p[5].position = glVector (x2, y2, z2); p[5].uv = glVector (u, v2);
u += (float)_width / mapping;
p[6].position = glVector (x1, y1, z2); p[6].uv = glVector (u, v1);
p[7].position = glVector (x1, y2, z2); p[7].uv = glVector (u, v2);
u += (float)_width / mapping;
p[8].position = glVector (x1, y1, z1); p[8].uv = glVector (u, v1);
p[9].position = glVector (x1, y2, z1); p[9].uv = glVector (u, v2);
for (i = 0; i < 10; i++) {
p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE;
_mesh->VertexAdd (p[i]);
index_list[i] = base_index + i;
}
_mesh->CubeAdd (&index_list[0]);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::ConstructCube (float left, float right, float front, float back, float bottom, float top)
{
GLvertex p[10];
float x1, x2, z1, z2, y1, y2;
int i;
int index_list[10];
int base_index;
x1 = left;
x2 = right;
y1 = bottom;
y2 = top;
z1 = front;
z2 = back;
base_index = _mesh_flat->VertexCount ();
p[0].position = glVector (x1, y1, z1); p[0].uv = glVector (0.0f, 0.0f);
p[1].position = glVector (x1, y2, z1); p[1].uv = glVector (0.0f, 0.0f);
p[2].position = glVector (x2, y1, z1); p[2].uv = glVector (0.0f, 0.0f);
p[3].position = glVector (x2, y2, z1); p[3].uv = glVector (0.0f, 0.0f);
p[4].position = glVector (x2, y1, z2); p[4].uv = glVector (0.0f, 0.0f);
p[5].position = glVector (x2, y2, z2); p[5].uv = glVector (0.0f, 0.0f);
p[6].position = glVector (x1, y1, z2); p[6].uv = glVector (0.0f, 0.0f);
p[7].position = glVector (x1, y2, z2); p[7].uv = glVector (0.0f, 0.0f);
p[8].position = glVector (x1, y1, z1); p[8].uv = glVector (0.0f, 0.0f);
p[9].position = glVector (x1, y2, z1); p[9].uv = glVector (0.0f, 0.0f);
for (i = 0; i < 10; i++) {
p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE;
_mesh_flat->VertexAdd (p[i]);
index_list[i] = base_index + i;
}
_mesh_flat->CubeAdd (&index_list[0]);
}
/*-----------------------------------------------------------------------------
This will take the given area and populate it with rooftop stuff like
air conditioners or light towers.
-----------------------------------------------------------------------------*/
void CBuilding::ConstructRoof (float left, float right, float front, float back, float bottom)
{
int air_conditioners;
int i;
int width, depth, height;
int face;
int addon;
int max_tiers;
float ac_x;
float ac_y;
float ac_base;
float ac_size;
float ac_height;
float tower_height;
float logo_offset;
CDeco* d;
GLvector2 start, end;
_roof_tiers++;
max_tiers = _height / 10;
width = (int)(right - left);
depth = (int)(back - front);
height = 5 - _roof_tiers;
logo_offset = 0.2f;
//See if this building is special and worthy of fancy roof decorations.
if (bottom > 35.0f)
addon = RandomVal (ADDON_COUNT);
//Build the roof slab
ConstructCube (left, right, front, back, bottom, bottom + (float)height);
//Consider putting a logo on the roof, if it's tall enough
if (addon == ADDON_LOGO && !_have_logo) {
d = new CDeco;
if (width > depth)
face = COIN_FLIP ? NORTH : SOUTH;
else
face = COIN_FLIP ? EAST : WEST;
switch (face) {
case NORTH:
start = glVector ((float)left, (float)back + logo_offset);
end = glVector ((float)right, (float)back + logo_offset);
break;
case SOUTH:
start = glVector ((float)right, (float)front - logo_offset);
end = glVector ((float)left, (float)front - logo_offset);
break;
case EAST:
start = glVector ((float)right + logo_offset, (float)back);
end = glVector ((float)right + logo_offset, (float)front);
break;
case WEST:
default:
start = glVector ((float)left - logo_offset, (float)front);
end = glVector ((float)left - logo_offset, (float)back);
break;
}
d->CreateLogo (start, end, bottom, WorldLogoIndex (), _trim_color);
_have_logo = true;
} else if (addon == ADDON_TRIM) {
d = new CDeco;
vector_buffer[0] = glVector (left, bottom, back);
vector_buffer[1] = glVector (left, bottom, front);
vector_buffer[2] = glVector (right, bottom, front);
vector_buffer[3] = glVector (right, bottom, back);
d->CreateLightTrim (vector_buffer, 4, (float)RandomVal (2) + 1.0f, _seed, _trim_color);
} else if (addon == ADDON_LIGHTS && !_have_lights) {
new CLight (glVector (left, (float)(bottom + 2), front), _trim_color, 2);
new CLight (glVector (right, (float)(bottom + 2), front), _trim_color, 2);
new CLight (glVector (right, (float)(bottom + 2), back), _trim_color, 2);
new CLight (glVector (left, (float)(bottom + 2), back), _trim_color, 2);
_have_lights = true;
}
bottom += (float)height;
//If the roof is big enough, consider making another layer
if (width > 7 && depth > 7 && _roof_tiers < max_tiers) {
ConstructRoof (left + 1, right - 1, front + 1, back - 1, bottom);
return;
}
//1 air conditioner block for every 15 floors sounds reasonble
air_conditioners = _height / 15;
for (i = 0; i < air_conditioners; i++) {
ac_size = (float)(10 + RandomVal (30)) / 10;
ac_height = (float)RandomVal (20) / 10 + 1.0f;
ac_x = left + (float)RandomVal (width);
ac_y = front + (float)RandomVal (depth);
//make sure the unit doesn't hang off the right edge of the building
if (ac_x + ac_size > (float)right)
ac_x = (float)right - ac_size;
//make sure the unit doesn't hang off the back edge of the building
if (ac_y + ac_size > (float)back)
ac_y = (float)back - ac_size;
ac_base = (float)bottom;
//make sure it doesn't hang off the edge
ConstructCube (ac_x, ac_x + ac_size, ac_y, ac_y + ac_size, ac_base, ac_base + ac_height);
}
if (_height > 45) {
d = new CDeco;
tower_height = (float)(12 + RandomVal (8));
d->CreateRadioTower (glVector ((float)(left + right) / 2.0f, (float)bottom, (float)(front + back) / 2.0f), 15.0f);
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::ConstructSpike (int left, int right, int front, int back, int bottom, int top)
{
GLvertex p;
int index_list[6];
int i;
GLvector center;
for (i = 0; i < 5; i++)
index_list[i] = _mesh_flat->VertexCount () + i;
index_list[5] = index_list[1];
p.uv = glVector (0.0f, 0.0f);
center.x = ((float)left + (float)right) / 2.0f;
center.z = ((float)front + (float)back) / 2.0f;
p.position = glVector (center.x, (float)top, center.z);
_mesh_flat->VertexAdd (p);
p.position = glVector ((float)left, (float)bottom, (float)back);
_mesh_flat->VertexAdd (p);
p.position = glVector ((float)right, (float)bottom, (float)back);
_mesh_flat->VertexAdd (p);
p.position = glVector ((float)right, (float)bottom, (float)front);
_mesh_flat->VertexAdd (p);
p.position = glVector ((float)left, (float)bottom, (float)front);
_mesh_flat->VertexAdd (p);
_mesh_flat->FanAdd (&index_list[0], 6);
}
/*-----------------------------------------------------------------------------
This builds an outer wall of a building, with blank (windowless) areas
deliberately left. It creates a chain of segments that alternate
between windowed and windowless, and it always makes sure the wall
is symetrical. window_groups tells it how many windows to place in a row.
-----------------------------------------------------------------------------*/
float CBuilding::ConstructWall (int start_x, int start_y, int start_z, int direction, int length, int height, int window_groups, float uv_start, bool blank_corners)
{
int x, z;
int step_x, step_z;
int i;
int index_list[100];
int current_index;
int column;
int mid;
int odd;
GLvertex v;
bool blank;
bool last_blank;
switch (direction) {
case NORTH:
step_z = 1; step_x = 0; break;
case WEST:
step_z = 0; step_x = -1; break;
case SOUTH:
step_z = -1; step_x = 0; break;
case EAST:
step_z = 0; step_x = 1; break;
}
x = start_x;;
z = start_z;
current_index = 0;
mid = (length / 2) - 1;
odd = 1 - (length % 2);
if (length % 2)
mid++;
//mid = (length / 2);
v.uv.x = (float)(x + z) / SEGMENTS_PER_TEXTURE;
v.uv.x = uv_start;
blank = false;
for (i = 0; i <= length; i++) {
//column counts up to the mid point, then back down, to make it symetrical
if (i <= mid)
column = i - odd;
else
column = (mid) - (i - (mid));
last_blank = blank;
blank = (column % window_groups) > window_groups / 2;
if (blank_corners && i == 0)
blank = true;
if (blank_corners && i == (length - 1))
blank = true;
if (last_blank != blank || i == 0 || i == length) {
v.position = glVector ((float)x, (float)start_y, (float)z);
v.uv.y = (float)start_y / SEGMENTS_PER_TEXTURE;
_mesh->VertexAdd (v);
index_list[current_index] = _mesh->VertexCount () - 1;
current_index++;
v.position.y = (float)(start_y + height);
v.uv.y = (float)(start_y + height) / SEGMENTS_PER_TEXTURE;;
_mesh->VertexAdd (v);
index_list[current_index] = _mesh->VertexCount () - 1;
current_index++;
}
//if (!blank && i != 0 && i != (length - 1))
if (!blank && i != length)
v.uv.x += 1.0f / SEGMENTS_PER_TEXTURE;
x += step_x;
z += step_z;
}
_mesh->QuadStripAdd (&index_list[0], current_index);
return v.uv.x;
}
static int maxt;
/*-----------------------------------------------------------------------------
This makes a big chunky building of intersecting cubes.
-----------------------------------------------------------------------------*/
void CBuilding::CreateBlocky ()
{
int min_height;
int left, right, front, back;
int max_left, max_right, max_front, max_back;
int height;
int mid_x, mid_z;
int half_depth, half_width;
int tiers;
int max_tiers;
int grouping;
float lid_height;
float uv_start;
bool skip;
bool blank_corners;
//Choose if the corners of the building are to be windowless.
blank_corners = COIN_FLIP;
//Choose a random column on our texture;
uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE;
//Choose how the windows are grouped
grouping = 2 + RandomVal (4);
//Choose how tall the lid should be on top of each section
lid_height = (float)(RandomVal (3) + 1);
//find the center of the building.
mid_x = _x + _width / 2;
mid_z = _y + _depth / 2;
max_left = max_right = max_front = max_back = 1;
height = _height;
min_height = _height / 2;
min_height = 3;
half_depth = _depth / 2;
half_width = _width / 2;
tiers = 0;
if (_height > 40)
max_tiers = 15;
else if (_height > 30)
max_tiers = 10;
else if (_height > 20)
max_tiers = 5;
else if (_height > 10)
max_tiers = 2;
else
max_tiers = 1;
max_tiers = MIN (maxt, max_tiers);
maxt++;
maxt %= 8;
//We begin at the top of the building, and work our way down.
//Viewed from above, the sections of the building are randomly sized
//rectangles that ALWAYS include the center of the building somewhere within
//their area.
while (1) {
if (height < min_height)
break;
if (tiers >= max_tiers)
break;
//pick new locationsfor our four outer walls
left = (RandomVal () % half_width) + 1;
right = (RandomVal () % half_width) + 1;
front = (RandomVal () % half_depth) + 1;
back = (RandomVal () % half_depth) + 1;
skip = false;
//At least ONE of the walls must reach out beyond a previous maximum.
//Otherwise, this tier would be completely hidden within a previous one.
if (left <= max_left && right <= max_right && front <= max_front && back <= max_back)
skip = true;
//If any of the four walls is in the same position as the previous max,then
//skip this tier, or else the two walls will end up z-fightng.
if (left == max_left || right == max_right || front == max_front || back == max_back)
skip = true;
if (!skip) {
//if this is the top, then put some lights up here
max_left = MAX (left, max_left);
max_right = MAX (right, max_right);
max_front = MAX (front, max_front);
max_back = MAX (back, max_back);
//Now build the four walls of this part
uv_start = ConstructWall (mid_x - left, 0, mid_z + back, SOUTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (mid_x - left, 0, mid_z - front, EAST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (mid_x + right, 0, mid_z - front, NORTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (mid_x + right, 0, mid_z + back, WEST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
if (!tiers)
ConstructRoof ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height);
else //add a flat-color lid onto this section
ConstructCube ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height, (float)height + lid_height);
height -= (RandomVal () % 10) + 1;
tiers++;
}
height--;
}
ConstructCube (mid_x - half_width, mid_x + half_width, mid_z - half_depth, mid_z + half_depth, 0, 2);
_mesh->Compile ();
_mesh_flat->Compile ();
}
/*-----------------------------------------------------------------------------
A single-cube building. Good for low-rise buildings and stuff that will be
far from the camera;
-----------------------------------------------------------------------------*/
void CBuilding::CreateSimple ()
{
GLvertex p;
float x1, x2, z1, z2, y1, y2;
int index_list[] = {0,1,2,3,4,5,6,7,8,9,10};
float u, v1, v2;
float cap_height;
float ledge;
//How tall the flat-color roof is
cap_height = (float)(1 + RandomVal (4));
//how much the ledge sticks out
ledge = (float)RandomVal (10) / 30.0f;
x1 = (float)_x;
x2 = (float)(_x + _width);
y1 = (float)0.0f;
y2 = (float)_height;
z2 = (float)_y;
z1 = (float)(_y + _depth);
u = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE;
v1 = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE;
v2 = v1 + (float)_height * ONE_SEGMENT;
p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
u += (float)_depth / SEGMENTS_PER_TEXTURE;
p.position = glVector (x1, y1, z2); p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
p.position = glVector (x1, y2, z2); p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
u += (float)_width / SEGMENTS_PER_TEXTURE;
p.position = glVector (x2, y1, z2); p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
p.position = glVector (x2, y2, z2); p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
u += (float)_depth / SEGMENTS_PER_TEXTURE;
p.position = glVector (x2, y1, z1); p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
p.position = glVector (x2, y2, z1); p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
u += (float)_depth / SEGMENTS_PER_TEXTURE;
p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
_mesh->QuadStripAdd (index_list, 10);
ConstructCube (x1 - ledge, x2 + ledge, z2 - ledge, z1 + ledge, (float)_height, (float)_height + cap_height);
_mesh->Compile ();
}
/*-----------------------------------------------------------------------------
This makes a deformed cylinder building.
-----------------------------------------------------------------------------*/
void CBuilding::CreateModern ()
{
GLvertex p;
GLvector center;
GLvector pos;
GLvector2 radius;
GLvector2 start, end;
int angle;
int windows;
int cap_height;
int half_depth, half_width;
float dist;
float length;
int* index_list;
int points;
int skip_interval;
int skip_counter;
int skip_delta;
bool logo_done;
bool do_trim;
CDeco* d;
logo_done = false;
//How tall the windowless section on top will be.
cap_height = 1 + RandomVal (5);
//How many 10-degree segments to build before the next skip.
skip_interval = 1 + RandomVal (8);
//When a skip happens, how many degrees should be skipped
skip_delta = (1 + RandomVal (2)) * 30; //30 60 or 90
//See if this is eligible for fancy lighting trim on top
if (_height > 48 && RandomVal (3) == 0)
do_trim = true;
else
do_trim = false;
//Get the center and radius of the circle
half_depth = _depth / 2;
half_width = _width / 2;
center = glVector ((float)(_x + half_width), 0.0f, (float)(_y + half_depth));
radius = glVector ((float)half_width, (float)half_depth);
dist = 0;
windows = 0;
p.uv.x = 0.0f;
points = 0;
skip_counter = 0;
for (angle = 0; angle <= 360; angle += 10) {
if (skip_counter >= skip_interval && (angle + skip_delta < 360)) {
angle += skip_delta;
skip_counter = 0;
}
pos.x = center.x - sinf ((float)angle * DEGREES_TO_RADIANS) * radius.x;
pos.z = center.z + cosf ((float)angle * DEGREES_TO_RADIANS) * radius.y;
if (angle > 0 && skip_counter == 0) {
length = MathDistance (p.position.x, p.position.z, pos.x, pos.z);
windows += (int)length;
if (length > 10 && !logo_done) {
logo_done = true;
start = glVector (pos.x, pos.z);
end = glVector (p.position.x, p.position.z);
d = new CDeco;
d->CreateLogo (start, end, (float)_height, WorldLogoIndex (), RANDOM_COLOR);
}
} else if (skip_counter != 1)
windows++;
p.position = pos;
p.uv.x = (float)windows / (float)SEGMENTS_PER_TEXTURE;
p.uv.y = 0.0f;
p.position.y = 0.0f;
_mesh->VertexAdd (p);
p.position.y = (float)_height;
p.uv.y = (float)_height / (float)SEGMENTS_PER_TEXTURE;
_mesh->VertexAdd (p);
_mesh_flat->VertexAdd (p);
p.position.y += (float)cap_height;
_mesh_flat->VertexAdd (p);
vector_buffer[points / 2] = p.position;
vector_buffer[points / 2].y = (float)_height + cap_height / 4;
points += 2;
skip_counter++;
}
//if this is a big building and it didn't get a logo, consider giving it a light strip
if (!logo_done && do_trim) {
d = new CDeco;
d->CreateLightTrim (vector_buffer, (points / 2) - 2, (float)cap_height / 2, _seed, RANDOM_COLOR);
}
index_list = new int[points];
//Add the outer walls
for (int i = 0; i < points; i++)
index_list[i] = i;
_mesh->QuadStripAdd (index_list, points);
_mesh_flat->QuadStripAdd (index_list, points);
//add the fan to cap the top of the buildings
for (i = 0; i < points / 2; i++)
index_list[i + 1] = points - (1 + i * 2);
p.position.x = _center.x;
p.position.z = _center.z;
_mesh_flat->VertexAdd (p);
index_list[0] = points;
_mesh_flat->FanAdd (index_list, 1 + points / 2);
delete index_list;
radius /= 2.0f;
//ConstructRoof ((int)(_center.x - radius), (int)(_center.x + radius), (int)(_center.z - radius), (int)(_center.z + radius), _height + cap_height);
_mesh->Compile ();
_mesh_flat->Compile ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CBuilding::CreateTower ()
{
int left, right, front, back, bottom;
int section_height, section_width, section_depth;
int remaining_height;
int ledge_height;
int tier_fraction;
int grouping;
int foundation;
float ledge;
float uv_start;
bool blank_corners;
bool roof_spike;
bool narrowing;
bool tower;
//How much ledges protrude from the building
ledge = (float)RandomVal (3) * 0.25f;
//How tall the ledges are, in stories
ledge_height = RandomVal (3) + 1;
//How the windows are grouped
grouping = RandomVal (3) + 2;
//if the corners of the building have no windows
blank_corners = COIN_FLIP;
//if the roof is pointed or has infrastructure on it
roof_spike = RandomVal (3) == 0;
//What fraction of the remaining height should be given to each tier
tier_fraction = 2 + RandomVal (3);
//Does the tower get narrower towards the top?
narrowing = RandomVal (3) == 0;
//The height of the windowsless slab at the bottom
foundation = 2 + RandomVal (3);
//The odds that we'll have a big fancy spikey top
tower = RandomVal (5) != 0 && _height > 40;
//set our initial parameters
left = _x;
right = _x + _width;
front = _y;
back = _y + _depth;
bottom = 0;
//build the foundations.
ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)foundation);
bottom += foundation;
//now add tiers until we reach the top
while (1) {
remaining_height = _height - bottom;
section_depth = back - front;
section_width = right - left;
section_height = MAX (remaining_height / tier_fraction, 2);
if (remaining_height < 10)
section_height = remaining_height;
//Build the four walls
uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE;
uv_start = ConstructWall (left, bottom, back, SOUTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (left, bottom, front, EAST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (right, bottom, front, NORTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
uv_start = ConstructWall (right, bottom, back, WEST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT;
bottom += section_height;
//Build the slab / ledges to cap this section.
if (bottom + ledge_height > _height)
break;
ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)(bottom + ledge_height));
bottom += ledge_height;
if (bottom > _height)
break;
if (ledge_height > 1 && narrowing)
ledge_height--;
if (narrowing) {
if (section_width > 7) {
left+=1;
right-=1;
}
if (section_depth > 7) {
front+=1;
back-=1;
}
}
}
ConstructRoof ((float)left, (float)right, (float)front, (float)back, (float)bottom);
_mesh->Compile ();
_mesh_flat->Compile ();
}

53
Building.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef ENTITY
#include "entity.h"
#endif
enum
{
BUILDING_SIMPLE,
BUILDING_BLOCKY,
BUILDING_MODERN,
BUILDING_TOWER
};
class CBuilding : public CEntity
{
private:
int _x;
int _y;
int _width;
int _depth;
int _height;
int _texture_type;
int _seed;
int _roof_tiers;
GLrgba _color;
GLrgba _trim_color;
class CMesh* _mesh;
class CMesh* _mesh_flat;
bool _have_lights;
bool _have_trim;
bool _have_logo;
void CreateSimple ();
void CreateBlocky ();
void CreateModern ();
void CreateTower ();
float ConstructWall (int start_x, int start_y, int start_z, int direction, int length, int height, int window_groups, float uv_start, bool blank_corners);
void ConstructSpike (int left, int right, int front, int back, int bottom, int top);
void ConstructCube (int left, int right, int front, int back, int bottom, int top);
void ConstructCube (float left, float right, float front, float back, float bottom, float top);
void ConstructRoof (float left, float right, float front, float back, float bottom);
public:
CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color);
~CBuilding ();
void Render (void);
int PolyCount ();
void RenderFlat (bool colored);
unsigned Texture ();
};

403
Camera.cpp Normal file
View File

@ -0,0 +1,403 @@
/*-----------------------------------------------------------------------------
Camera.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This tracks the position and oritentation of the camera. In screensaver
mode, it moves the camera around the world in order to create dramatic
views of the hot zone.
-----------------------------------------------------------------------------*/
#define EYE_HEIGHT 2.0f
#define MAX_PITCH 85
#define FLYCAM_CIRCUT 60000
#define FLYCAM_CIRCUT_HALF (FLYCAM_CIRCUT / 2)
#define FLYCAM_LEG (FLYCAM_CIRCUT / 4)
#define ONE_SECOND 1000
#define CAMERA_CHANGE_INTERVAL 15
#define CAMERA_CYCLE_LENGTH (CAMERA_MODES*CAMERA_CHANGE_INTERVAL)
#include <windows.h>
#include <math.h>
#include <time.h>
#include "glTypes.h"
#include "ini.h"
#include "macro.h"
#include "math.h"
#include "world.h"
#include "win.h"
enum
{
CAMERA_FLYCAM1,
CAMERA_ORBIT_INWARD,
CAMERA_ORBIT_OUTWARD,
CAMERA_ORBIT_ELLIPTICAL,
CAMERA_FLYCAM2,
CAMERA_SPEED,
CAMERA_SPIN,
CAMERA_FLYCAM3,
CAMERA_MODES
};
static GLvector angle;
static GLvector position;
static GLvector auto_angle;
static GLvector auto_position;
static float distance;
static float movement;
static bool moving;
static bool cam_auto;
static float tracker;
static unsigned last_update;
static int camera_behavior;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static GLvector flycam_position (unsigned t)
{
unsigned leg;
float delta;
GLvector start, end;
GLbbox hot_zone;
hot_zone = WorldHotZone ();
t %= FLYCAM_CIRCUT;
leg = t / FLYCAM_LEG;
delta = (float)(t % FLYCAM_LEG) / FLYCAM_LEG;
switch (leg) {
case 0:
start = glVector (hot_zone.min.x, 25.0f, hot_zone.min.z);
end = glVector (hot_zone.min.x, 60.0f, hot_zone.max.z);
break;
case 1:
start = glVector (hot_zone.min.x, 60.0f, hot_zone.max.z);
end = glVector (hot_zone.max.x, 25.0f, hot_zone.max.z);
break;
case 2:
start = glVector (hot_zone.max.x, 25.0f, hot_zone.max.z);
end = glVector (hot_zone.max.x, 60.0f, hot_zone.min.z);
break;
case 3:
start = glVector (hot_zone.max.x, 60.0f, hot_zone.min.z);
end = glVector (hot_zone.min.x, 25.0f, hot_zone.min.z);
break;
}
delta = MathScalarCurve (delta);
return glVectorInterpolate (start, end, delta);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_auto_cam ()
{
float dist;
unsigned t;
unsigned elapsed;
unsigned now;
int behavior;
GLvector target;
now = GetTickCount ();
elapsed = now - last_update;
elapsed = MIN (elapsed, 1000); //limit to 1 second worth of time
if (elapsed == 0)
return;
last_update = now;
t = time (NULL) % CAMERA_CYCLE_LENGTH;
#if SCREENSAVER
behavior = t / CAMERA_CHANGE_INTERVAL;
#else
behavior = camera_behavior;
#endif
tracker += (float)elapsed / 100.0f;
//behavior = CAMERA_FLYCAM1;
switch (behavior) {
case CAMERA_ORBIT_INWARD:
auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 150.0f;
auto_position.y = 60.0f;
auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 150.0f;
target = glVector (WORLD_HALF, 40.0f, WORLD_HALF);
break;
case CAMERA_ORBIT_OUTWARD:
auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 250.0f;
auto_position.y = 60.0f;
auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 250.0f;
target = glVector (WORLD_HALF, 30.0f, WORLD_HALF);
break;
case CAMERA_ORBIT_ELLIPTICAL:
dist = 150.0f + sinf (tracker * DEGREES_TO_RADIANS / 1.1f) * 50;
auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * dist;
auto_position.y = 60.0f;
auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * dist;
target = glVector (WORLD_HALF, 50.0f, WORLD_HALF);
break;
case CAMERA_FLYCAM1:
case CAMERA_FLYCAM2:
case CAMERA_FLYCAM3:
auto_position = (flycam_position (now) + flycam_position (now + 4000)) / 2.0f;
target = flycam_position (now + FLYCAM_CIRCUT_HALF - ONE_SECOND * 3);
break;
case CAMERA_SPEED:
auto_position = (flycam_position (now) + flycam_position (now + 500)) / 2.0f;
target = flycam_position (now + ONE_SECOND * 5);
auto_position.y /= 2;
target.y /= 2;
break;
case CAMERA_SPIN:
default:
target.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 300.0f;
target.y = 30.0f;
target.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 300.0f;
auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 50.0f;
auto_position.y = 60.0f;
auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 50.0f;
}
dist = MathDistance (auto_position.x, auto_position.z, target.x, target.z);
auto_angle.y = MathAngle (-MathAngle (auto_position.x, auto_position.z, target.x, target.z));
auto_angle.x = 90.0f + MathAngle (0, auto_position.y, dist, target.y);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraAutoToggle ()
{
cam_auto = !cam_auto;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraNextBehavior ()
{
camera_behavior++;
camera_behavior %= CAMERA_MODES;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraYaw (float delta)
{
moving = true;
angle.y -= delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraPitch (float delta)
{
moving = true;
angle.x -= delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraPan (float delta)
{
float move_x, move_y;
moving = true;
move_x = (float)sin (-angle.y * DEGREES_TO_RADIANS) / 10.0f;
move_y = (float)cos (-angle.y * DEGREES_TO_RADIANS) / 10.0f;
position.x -= move_y * delta;
position.z -= -move_x * delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraForward (float delta)
{
float move_x, move_y;
moving = true;
move_y = (float)sin (-angle.y * DEGREES_TO_RADIANS) / 10.0f;
move_x = (float)cos (-angle.y * DEGREES_TO_RADIANS) / 10.0f;
position.x -= move_y * delta;
position.z -= move_x * delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraSelectionPitch (float delta)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraSelectionZoom (float delta)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraSelectionYaw (float delta)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector CameraPosition (void)
{
if (cam_auto)
return auto_position;
return position;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraReset ()
{
position.y = 50.0f;
position.x = WORLD_HALF;
position.z = WORLD_HALF;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraPositionSet (GLvector new_pos)
{
position = new_pos;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector CameraAngle (void)
{
if (cam_auto)
return auto_angle;
return angle;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraAngleSet (GLvector new_angle)
{
angle = new_angle;
angle.x = CLAMP (angle.x, -80.0f, 80.0f);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraInit (void)
{
angle = IniVector ("CameraAngle");
position = IniVector ("CameraPosition");
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraUpdate (void)
{
#if SCREENSAVER
cam_auto = true;
#endif
if (cam_auto)
do_auto_cam ();
if (moving)
movement *= 1.1f;
else
movement = 0.0f;
movement = CLAMP (movement, 0.01f, 1.0f);
if (angle.y < 0.0f)
angle.y = 360.0f - (float)fmod (fabs (angle.y), 360.0f);
angle.y = (float)fmod (angle.y, 360.0f);
angle.x = CLAMP (angle.x, -MAX_PITCH, MAX_PITCH);
moving = false;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraTerm (void)
{
//just store our most recent position in the ini
IniVectorSet ("CameraAngle", angle);
IniVectorSet ("CameraPosition", position);
}

24
Camera.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef TYPES
#include "glTypes.h"
#endif
GLvector CameraAngle (void);
void CameraAngleSet (GLvector new_angle);
void CameraAutoToggle ();
float CameraDistance (void);
void CameraDistanceSet (float new_distance);
void CameraInit (void);
void CameraNextBehavior (void);
GLvector CameraPosition (void);
void CameraPositionSet (GLvector new_pos);
void CameraReset ();
void CameraUpdate (void);
void CameraTerm (void);
void CameraForward (float delta);
void CameraSelectionPitch (float delta_y);
void CameraSelectionYaw (float delta_x);
void CameraSelectionZoom (float delta_y);
void CameraPan (float delta_x);
void CameraPitch (float delta_y);
void CameraYaw (float delta_x);

322
Car.cpp Normal file
View File

@ -0,0 +1,322 @@
/*-----------------------------------------------------------------------------
Car.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This creates the little two-triangle cars and moves them around the map.
-----------------------------------------------------------------------------*/
#define DEAD_ZONE 200
#define STUCK_TIME 230
#define UPDATE_INTERVAL 50 //milliseconds
#define MOVEMENT_SPEED 0.61f
#define CAR_SIZE 3.0f
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "glTypes.h"
#include "building.h"
#include "car.h"
#include "camera.h"
#include "mesh.h"
#include "macro.h"
#include "math.h"
#include "random.h"
#include "render.h"
#include "texture.h"
#include "world.h"
#include "visible.h"
static GLvector direction[] =
{
0.0f, 0.0f, -1.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
-1.0f, 0.0f, 0.0f,
};
static int dangles[] = { 0, 90, 180, 270};
static GLvector2 angles[360];
static bool angles_done;
static unsigned char carmap[WORLD_SIZE][WORLD_SIZE];
static CCar* head;
static unsigned next_update;
static int count;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int CarCount ()
{
return count;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CarClear ()
{
CCar* c;
for (c = head; c; c = c->m_next)
c->Park ();
ZeroMemory (carmap, sizeof (carmap));
count = 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CarRender ()
{
CCar* c;
if (!angles_done) {
for (int i = 0 ;i < 360; i++) {
angles[i].x = cosf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE;
angles[i].y = sinf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE;
}
}
glDepthMask (false);
glEnable (GL_BLEND);
glDisable (GL_CULL_FACE);
glBlendFunc (GL_ONE, GL_ONE);
glBindTexture (GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_HEADLIGHT));
for (c = head; c; c = c->m_next)
c->Render ();
glDepthMask (true);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CarUpdate ()
{
CCar* c;
unsigned now;
if (!TextureReady () || !EntityReady ())
return;
now = GetTickCount ();
if (next_update > now)
return;
next_update = now + UPDATE_INTERVAL;
for (c = head; c; c = c->m_next)
c->Update ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CCar::CCar ()
{
m_ready = false;
m_next = head;
head = this;
count++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool CCar::TestPosition (int row, int col)
{
//test the given position and see if it's already occupied
if (carmap[row][col])
return false;
//now make sure that the lane is going the right direction
if (WorldCell (row, col) != WorldCell (m_row, m_col))
return false;
return true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CCar::Update (void)
{
int new_row, new_col;
GLvector old_pos;
GLvector camera;
//If the car isn't ready, place it on the map and get it moving
camera = CameraPosition ();
if (!m_ready) {
//if the car isn't ready, we need to place it somewhere on the map
m_row = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2);
m_col = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2);
//if there is already a car here, forget it.
if (carmap[m_row][m_col] > 0)
return;
//if this spot is not a road, forget it
if (!(WorldCell (m_row, m_col) & CLAIM_ROAD))
return;
if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col)))
return;
//good spot. place the car
m_position = glVector ((float)m_row, 0.1f, (float)m_col);
m_drive_position = m_position;
m_ready = true;
if (WorldCell (m_row, m_col) & MAP_ROAD_NORTH)
m_direction = NORTH;
if (WorldCell (m_row, m_col) & MAP_ROAD_EAST)
m_direction = EAST;
if (WorldCell (m_row, m_col) & MAP_ROAD_SOUTH)
m_direction = SOUTH;
if (WorldCell (m_row, m_col) & MAP_ROAD_WEST)
m_direction = WEST;
m_drive_angle = dangles[m_direction];
m_max_speed = (float)(4 + RandomVal (6)) / 10.0f;
m_speed = 0.0f;
m_change = 3;
m_stuck = 0;
carmap[m_row][m_col]++;
}
//take the car off the map and move it
carmap[m_row][m_col]--;
old_pos = m_position;
m_speed += m_max_speed * 0.05f;
m_speed = MIN (m_speed, m_max_speed);
m_position += direction[m_direction] * MOVEMENT_SPEED * m_speed;
//If the car has moved out of view, there's no need to keep simulating it.
if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col)))
m_ready = false;
//if the car is far away, remove it. We use manhattan units because buildings almost always
//block views of cars on the diagonal.
if (fabs (camera.x - m_position.x) + fabs (camera.z - m_position.z) > RenderFogDistance ())
m_ready = false;
//if the car gets too close to the edge of the map, take it out of play
if (m_position.x < DEAD_ZONE || m_position.x > (WORLD_SIZE - DEAD_ZONE))
m_ready = false;
if (m_position.z < DEAD_ZONE || m_position.z > (WORLD_SIZE - DEAD_ZONE))
m_ready = false;
if (m_stuck >= STUCK_TIME)
m_ready = false;
if (!m_ready)
return;
//Check the new position and make sure its not in another car
new_row = (int)m_position.x;
new_col = (int)m_position.z;
if (new_row != m_row || new_col != m_col) {
//see if the new position places us on top of another car
if (carmap[new_row][new_col]) {
m_position = old_pos;
m_speed = 0.0f;
m_stuck++;
} else {
//look at the new position and decide if we're heading towards or away from the camera
m_row = new_row;
m_col = new_col;
m_change--;
m_stuck = 0;
if (m_direction == NORTH)
m_front = camera.z < m_position.z;
else if (m_direction == SOUTH)
m_front = camera.z > m_position.z;
else if (m_direction == EAST)
m_front = camera.x > m_position.x;
else
m_front = camera.x < m_position.x;
}
}
m_drive_position = (m_drive_position + m_position) / 2.0f;
//place the car back on the map
carmap[m_row][m_col]++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CCar::Render ()
{
GLvector pos;
int angle;
int turn;
if (!m_ready)
return;
if (!Visible (m_drive_position))
return;
if (m_front)
glColor3f (1, 1, 0.8f);
else
glColor3f (1, 0.2f, 0);
glBegin (GL_QUADS);
angle = dangles[m_direction];
pos = m_drive_position;//
angle = 360 - (int)MathAngle (m_position.x, m_position.z, pos.x, pos.z);
angle %= 360;
turn = (int)MathAngleDifference ((float)m_drive_angle, (float)angle);
m_drive_angle += SIGN (turn);
pos += glVector (0.5f, 0.0f, 0.5f);
glTexCoord2f (0, 0);
glVertex3f (pos.x + angles[angle].x, -CAR_SIZE, pos.z + angles[angle].y);
glTexCoord2f (1, 0);
glVertex3f (pos.x - angles[angle].x, -CAR_SIZE, pos.z - angles[angle].y);
glTexCoord2f (1, 1);
glVertex3f (pos.x - angles[angle].x, CAR_SIZE, pos.z - angles[angle].y);
glTexCoord2f (0, 1);
glVertex3f (pos.x + angles[angle].x, CAR_SIZE, pos.z + angles[angle].y);
/*
glVertex3f (m_position.x, m_position.y, m_position.z);
glVertex3f (m_position.x, m_position.y, m_position.z + 1);
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1);
glVertex3f (m_position.x + 1, m_position.y, m_position.z);
*/
/*
glTexCoord2f (0, 0);
glVertex3f (m_position.x, m_position.y, m_position.z + 0.2f);
glTexCoord2f (0, 2);
glVertex3f (m_position.x, m_position.y, m_position.z + 1 - 0.2f);
glTexCoord2f (1, 2);
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1 - 0.2f);
glTexCoord2f (1, 0);
glVertex3f (m_position.x + 1, m_position.y, m_position.z + 0.2f);
*/
glEnd ();
}

30
Car.h Normal file
View File

@ -0,0 +1,30 @@
class CCar
{
GLvector m_position;
GLvector m_drive_position;
bool m_ready;
bool m_front;
int m_drive_angle;
int m_row;
int m_col;
int m_direction;
int m_change;
int m_stuck;
float m_speed;
float m_max_speed;
public:
CCar ();
bool TestPosition (int row, int col);
void Render ();
void Update ();
void Park () { m_ready = false;}
class CCar* m_next;
};
void CarClear ();
int CarCount ();
void CarRender ();
void CarUpdate ();

285
Deco.cpp Normal file
View File

@ -0,0 +1,285 @@
/*-----------------------------------------------------------------------------
Deco.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This handles building and rendering decoration objects - infrastructure &
such around the city.
-----------------------------------------------------------------------------*/
#define LOGO_OFFSET 0.2f //How far a logo sticks out from the given surface
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "glTypes.h"
#include "deco.h"
#include "light.h"
#include "mesh.h"
#include "macro.h"
#include "math.h"
#include "random.h"
#include "render.h"
#include "texture.h"
#include "world.h"
#include "visible.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CDeco::CDeco ()
{
_mesh = new CMesh ();
_use_alpha = false;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::Render ()
{
glColor3fv (&_color.red);
_mesh->Render ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::RenderFlat (bool colored)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool CDeco::Alpha ()
{
return _use_alpha;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int CDeco::PolyCount ()
{
return _mesh->PolyCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned CDeco::Texture ()
{
return _texture;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::CreateRadioTower (GLvector pos, float height)
{
CLight* l;
float offset;
GLvertex v;
int index_list[] = {0,1,2,3,4,5};
offset = height / 15.0f;
_center = pos;
_use_alpha = true;
//Radio tower
v.position = glVector (_center.x, _center.y + height, _center.z); v.uv = glVector (0,1);
_mesh->VertexAdd (v);
v.position = glVector (_center.x - offset, _center.y, _center.z - offset); v.uv = glVector (1,0);
_mesh->VertexAdd (v);
v.position = glVector (_center.x + offset, _center.y, _center.z - offset); v.uv = glVector (0,0);
_mesh->VertexAdd (v);
v.position = glVector (_center.x + offset, _center.y, _center.z + offset); v.uv = glVector (1,0);
_mesh->VertexAdd (v);
v.position = glVector (_center.x - offset, _center.y, _center.z + offset); v.uv = glVector (0,0);
_mesh->VertexAdd (v);
v.position = glVector (_center.x - offset, _center.y, _center.z - offset); v.uv = glVector (1,0);
_mesh->VertexAdd (v);
_mesh->FanAdd (&index_list[0], 6);
l = new CLight (glVector (_center.x, _center.y + height + 1.0f, _center.z), glRgba (255,192,160), 1);
l->Blink ();
_texture = TextureId (TEXTURE_LATTICE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::CreateLogo (GLvector2 start, GLvector2 end, float bottom, int seed, GLrgba color)
{
GLvertex p;
int index_list[] = {0,1,3,2};
float u1, u2, v1, v2;
float top;
float height, length;
GLvector2 center2d;
GLvector to;
GLvector out;
int logo_index;
_use_alpha = true;
_color = color;
logo_index = seed % LOGO_ROWS;
to = glVector (start.x, 0.0f, start.y) - glVector (end.x, 0.0f, end.y);
to = glVectorNormalize (to);
out = glVectorCrossProduct (glVector (0.0f, 1.0f, 0.0f), to) * LOGO_OFFSET;
center2d = (start + end) / 2;
_center = glVector (center2d.x, bottom, center2d.y);
length = glVectorLength (start - end);
height = (length / 8.0f) * 1.5f;
top = bottom + height;
u1 = 0.0f;
u2 = 0.5f;//We actually only use the left half of the texture
v1 = (float)logo_index / LOGO_ROWS;
v2 = v1 + (1.0f / LOGO_ROWS);
p.position = glVector (start.x, bottom, start.y) + out; p.uv = glVector (u1,v1);
_mesh->VertexAdd (p);
p.position = glVector (end.x, bottom, end.y) + out; p.uv = glVector (u2, v1);
_mesh->VertexAdd (p);
p.position = glVector (end.x, top, end.y) + out; p.uv = glVector (u2, v2);
_mesh->VertexAdd (p);
p.position = glVector (start.x, top, start.y) + out; p.uv = glVector (u1, v2);
_mesh->VertexAdd (p);
_mesh->QuadStripAdd (&index_list[0], 4);
_texture = TextureId (TEXTURE_LOGOS);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::CreateLightStrip (float x, float z, float width, float depth, float height, GLrgba color)
{
GLvertex p;
int index_list1[] = {0,1,3,2};
int index_list2[] = {4,5,7,6};
float u, v;
_color = color;
_use_alpha = true;
_center = glVector (x + width / 2, height, z + depth / 2);
if (width < depth) {
u = 1.0f;
v = (float)((int)(depth / width));
} else {
v = 1.0f;
u = (float)((int)(width / depth));
}
//u = MAX (width, 1);
//v = MAX (depth, 1);
_texture = TextureId (TEXTURE_LIGHT);
p.position = glVector (x, height, z); p.uv = glVector (0.0f, 0.0f);
_mesh->VertexAdd (p);
p.position = glVector (x, height, z + depth); p.uv = glVector (0.0f, v);
_mesh->VertexAdd (p);
p.position = glVector (x + width, height, z + depth); p.uv = glVector (u, v);
_mesh->VertexAdd (p);
p.position = glVector (x + width, height, z); p.uv = glVector (u, 0.0f);
_mesh->VertexAdd (p);
p.position = glVector (x - 1, height, z - 1); p.uv = glVector (0, 0);
_mesh->VertexAdd (p);
p.position = glVector (x - 1, height, z + depth + 1); p.uv = glVector (0, 1);
_mesh->VertexAdd (p);
p.position = glVector (x + width + 1, height, z + depth + 1); p.uv = glVector (1, 1);
_mesh->VertexAdd (p);
p.position = glVector (x + width + 1, height, z - 1); p.uv = glVector (1, 0);
_mesh->VertexAdd (p);
_mesh->QuadStripAdd (&index_list1[0], 4);
//_mesh->QuadStripAdd (&index_list2[0], 4);
_mesh->Compile ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::CreateLightTrim (GLvector* chain, int count, float height, int seed, GLrgba color)
{
GLvertex p;
GLvector to;
GLvector out;
int i;
int index;
int prev, next;
float u, v1, v2;
float row;
int* index_list;
_color = color;
_center = glVector (0.0f, 0.0f, 0.0f);
index_list = new int[count * 2 + 2];
for (i = 0; i < count; i++)
_center += chain[i];
_center /= (float)count;
row = (float)(seed % TRIM_ROWS);
v1 = row * TRIM_SIZE;
v2 = (row + 1.0f) * TRIM_SIZE;
index = 0;
u = 0.0f;
for (i = 0; i < count + 1; i++) {
if (i)
u += glVectorLength (chain[i % count] - p.position) * 0.1f;
//Add the bottom point
prev = i - 1;
if (prev < 0)
prev = count + prev;
next = (i + 1) % count;
to = glVectorNormalize (chain[next] - chain[prev]);
out = glVectorCrossProduct (glVector (0.0f, 1.0f, 0.0f), to) * LOGO_OFFSET;
p.position = chain[i % count] + out; p.uv = glVector (u, v2);
_mesh->VertexAdd (p);
index_list[index] = index;
index++;
//Top point
p.position.y += height;p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
index_list[index] = index;
index++;
}
_mesh->QuadStripAdd (index_list, index);
delete index_list;
_texture = TextureId (TEXTURE_TRIM);
_mesh->Compile ();
}

28
Deco.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef ENTITY
#include "entity.h"
#endif
class CDeco : CEntity
{
// CDeco* _next;
GLrgba _color;
class CMesh* _mesh;
int _type;
unsigned _texture;
bool _use_alpha;
public:
CDeco ();
void CreateLogo (GLvector2 start, GLvector2 end, float base, int seed, GLrgba color);
void CreateLightStrip (float x, float z, float width, float depth, float height, GLrgba color);
void CreateLightTrim (GLvector* chain, int count, float height, int seed, GLrgba color);
void CreateRadioTower (GLvector pos, float height);
void Render (void);
void RenderFlat (bool colored);
bool Alpha ();
int PolyCount ();
unsigned Texture ();
};

412
Entity.cpp Normal file
View File

@ -0,0 +1,412 @@
/*-----------------------------------------------------------------------------
Entity.cpp
Copyright (c) 2005 Shamus Young
All Rights Reserved
-------------------------------------------------------------------------------
An entity is any renderable stationary object in the world. This is an
abstract class. This module gathers up the Entities, sorts them by
texture use and location, and then stores them in OpenGL render lists
for faster rendering.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include "camera.h"
#include "entity.h"
#include "macro.h"
#include "math.h"
#include "render.h"
#include "texture.h"
#include "world.h"
#include "visible.h"
struct entity
{
CEntity* object;
};
struct cell
{
unsigned list_textured;
unsigned list_flat;
unsigned list_flat_wireframe;
unsigned list_alpha;
GLvector pos;
};
static cell cell_list[GRID_SIZE][GRID_SIZE];
static int entity_count;
static entity* entity_list;
static bool sorted;
static bool compiled;
static int polycount;
static int compile_x;
static int compile_y;
static int compile_count;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static int do_compare (const void *arg1, const void *arg2 )
{
struct entity* e1 = (struct entity*)arg1;
struct entity* e2 = (struct entity*)arg2;
if (e1->object->Alpha () && !e2->object->Alpha ())
return 1;
if (!e1->object->Alpha () && e2->object->Alpha ())
return -1;
if (e1->object->Texture () > e2->object->Texture ())
return 1;
else if (e1->object->Texture () < e2->object->Texture ())
return -1;
return 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void add (CEntity* b)
{
entity_list = (entity*)realloc (entity_list, sizeof (entity) * (entity_count + 1));
entity_list[entity_count].object = b;
entity_count++;
polycount = 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_compile ()
{
int i;
int x, y;
if (compiled)
return;
x = compile_x;
y = compile_y;
//Changing textures is pretty expensive, and thus sorting the entites so that
//they are grouped by texture used can really improve framerate.
//qsort (entity_list, entity_count, sizeof (struct entity), do_compare);
//sorted = true;
//Now group entites on the grid
//make a list for the textured objects in this region
if (!cell_list[x][y].list_textured)
cell_list[x][y].list_textured = glGenLists(1);
glNewList (cell_list[x][y].list_textured, GL_COMPILE);
cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION);
for (i = 0; i < entity_count; i++) {
GLvector pos = entity_list[i].object->Center ();
if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) {
glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ());
entity_list[i].object->Render ();
}
}
glEndList();
//Make a list of flat-color stuff (A/C units, ledges, roofs, etc.)
if (!cell_list[x][y].list_flat)
cell_list[x][y].list_flat = glGenLists(1);
glNewList (cell_list[x][y].list_flat, GL_COMPILE);
glEnable (GL_CULL_FACE);
cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION);
for (i = 0; i < entity_count; i++) {
GLvector pos = entity_list[i].object->Center ();
if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) {
entity_list[i].object->RenderFlat (false);
}
}
glEndList();
//Now a list of flat-colored stuff that will be wireframe friendly
if (!cell_list[x][y].list_flat_wireframe)
cell_list[x][y].list_flat_wireframe = glGenLists(1);
glNewList (cell_list[x][y].list_flat_wireframe, GL_COMPILE);
glEnable (GL_CULL_FACE);
cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION);
for (i = 0; i < entity_count; i++) {
GLvector pos = entity_list[i].object->Center ();
if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) {
entity_list[i].object->RenderFlat (true);
}
}
glEndList();
//Now a list of stuff to be alpha-blended, and thus rendered last
if (!cell_list[x][y].list_alpha)
cell_list[x][y].list_alpha = glGenLists(1);
glNewList (cell_list[x][y].list_alpha, GL_COMPILE);
cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION);
glDepthMask (false);
glEnable (GL_BLEND);
glDisable (GL_CULL_FACE);
for (i = 0; i < entity_count; i++) {
GLvector pos = entity_list[i].object->Center ();
if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && entity_list[i].object->Alpha ()) {
glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ());
entity_list[i].object->Render ();
}
}
glDepthMask (true);
glEndList();
//now walk the grid
compile_x++;
if (compile_x == GRID_SIZE) {
compile_x = 0;
compile_y++;
if (compile_y == GRID_SIZE)
compiled = true;
}
compile_count++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool EntityReady ()
{
return compiled;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float EntityProgress ()
{
return (float)compile_count / (GRID_SIZE * GRID_SIZE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityUpdate ()
{
if (!TextureReady ()) {
sorted = false;
return;
}
if (!sorted) {
qsort (entity_list, entity_count, sizeof (struct entity), do_compare);
sorted = true;
}
if (!compiled)
for (int i = 0; i < 10; i++)
do_compile ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void xEntityRender ()
{
int i;
bool wireframe;
int polymode[2];
glGetIntegerv (GL_POLYGON_MODE, &polymode[0]);
wireframe = polymode[0] != GL_FILL;
for (i = 0; i < entity_count; i++) {
if (Visible (entity_list[i].object->Center ())) {
glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ());
entity_list[i].object->Render ();
}
}
glBindTexture(GL_TEXTURE_2D, 0);
glColor3f (0,0,0);
for (i = 0; i < entity_count; i++) {
if (Visible (entity_list[i].object->Center ())) {
entity_list[i].object->RenderFlat (wireframe);
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityRender ()
{
int polymode[2];
bool wireframe;
int x, y;
//Draw all textured objects
glGetIntegerv (GL_POLYGON_MODE, &polymode[0]);
wireframe = polymode[0] != GL_FILL;
if (RenderFlat ())
glDisable (GL_TEXTURE_2D);
for (x = 0; x < GRID_SIZE; x++) {
for (y = 0; y < GRID_SIZE; y++) {
if (Visible (x,y))
glCallList (cell_list[x][y].list_textured);
}
}
//draw all flat colored objects
glBindTexture(GL_TEXTURE_2D, 0);
glColor3f (0, 0, 0);
for (x = 0; x < GRID_SIZE; x++) {
for (y = 0; y < GRID_SIZE; y++) {
if (Visible (x, y)) {
if (wireframe)
glCallList (cell_list[x][y].list_flat_wireframe);
else
glCallList (cell_list[x][y].list_flat);
}
}
}
//draw all alpha-blended objects
glBindTexture(GL_TEXTURE_2D, 0);
glColor3f (0, 0, 0);
glEnable (GL_BLEND);
for (x = 0; x < GRID_SIZE; x++) {
for (y = 0; y < GRID_SIZE; y++) {
if (Visible (x,y)) {
glCallList (cell_list[x][y].list_alpha);
}
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityClear ()
{
for (int i = 0; i < entity_count; i++) {
delete entity_list[i].object;
}
if (entity_list)
free (entity_list);
entity_list = NULL;
entity_count = 0;
compile_x = 0;
compile_y = 0;
compile_count = 0;
compiled = false;
sorted = false;
int x, y;
for (x = 0; x < GRID_SIZE; x++) {
for (y = 0; y < GRID_SIZE; y++) {
glNewList (cell_list[x][y].list_textured, GL_COMPILE);
glEndList();
glNewList (cell_list[x][y].list_alpha, GL_COMPILE);
glEndList();
glNewList (cell_list[x][y].list_flat_wireframe, GL_COMPILE);
glEndList();
glNewList (cell_list[x][y].list_flat, GL_COMPILE);
glEndList();
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int EntityCount ()
{
return entity_count;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityInit (void)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int EntityPolyCount (void)
{
if (!sorted)
return 0;
if (polycount)
return polycount;
for (int i = 0; i < entity_count; i++)
polycount += entity_list[i].object->PolyCount ();
return polycount;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CEntity::CEntity (void)
{
add (this);
}
void CEntity::Render (void)
{
}
void CEntity::RenderFlat (bool wireframe)
{
}
void CEntity::Update (void)
{
}

36
Entity.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef TYPES
#include "glTypes.h"
#endif
#ifndef ENTITY
#define ENTITY
class CEntity
{
private:
protected:
GLvector _center;
public:
CEntity (void);
GLvector Center () { return _center; }
virtual void Render (void);
virtual void RenderFlat (bool wirefame);
virtual unsigned Texture () { return 0; }
virtual void Update (void);
virtual bool Alpha () { return false; }
virtual int PolyCount () { return 0; }
};
void EntityClear ();
int EntityCount (void);
float EntityProgress ();
bool EntityReady ();
void EntityRender (void);
void EntityUpdate (void);
int EntityPolyCount (void);
#endif

137
Ini.cpp Normal file
View File

@ -0,0 +1,137 @@
/*-----------------------------------------------------------------------------
Ini.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This takes various types of data and dumps them into a predefined ini file.
-----------------------------------------------------------------------------*/
#define FORMAT_VECTOR "%f %f %f"
#define MAX_RESULT 256
#define FORMAT_FLOAT "%1.2f"
#define INI_FILE ".\\" APP ".ini"
#define SECTION "Settings"
#include <windows.h>
#include <stdio.h>
#include "glTypes.h"
#include "ini.h"
#include "win.h"
static char result[MAX_RESULT];
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int IniInt (char* entry)
{
int result;
result = GetPrivateProfileInt (SECTION, entry, 0, INI_FILE);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void IniIntSet (char* entry, int val)
{
char buf[20];
sprintf (buf, "%d", val);
WritePrivateProfileString (SECTION, entry, buf, INI_FILE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float IniFloat (char* entry)
{
float f;
GetPrivateProfileString (SECTION, entry, "", result, MAX_RESULT, INI_FILE);
f = (float)atof (result);
return f;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void IniFloatSet (char* entry, float val)
{
char buf[20];
sprintf (buf, FORMAT_FLOAT, val);
WritePrivateProfileString (SECTION, entry, buf, INI_FILE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
char* IniString (char* entry)
{
GetPrivateProfileString (SECTION, entry, "", result, MAX_RESULT, INI_FILE);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void IniStringSet (char* entry, char* val)
{
WritePrivateProfileString (SECTION, entry, val, INI_FILE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void IniVectorSet (char* entry, GLvector v)
{
sprintf (result, FORMAT_VECTOR, v.x, v.y, v.z);
WritePrivateProfileString (SECTION, entry, result, INI_FILE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector IniVector (char* entry)
{
GLvector v;
v.x = v.y = v.z = 0.0f;
GetPrivateProfileString (SECTION, entry, "0 0 0", result, MAX_RESULT, INI_FILE);
sscanf (result, FORMAT_VECTOR, &v.x, &v.y, &v.z);
return v;
}

8
Ini.h Normal file
View File

@ -0,0 +1,8 @@
int IniInt (char* entry);
void IniIntSet (char* entry, int val);
float IniFloat (char* entry);
void IniFloatSet (char* entry, float val);
char* IniString (char* entry);
void IniStringSet (char* entry, char* val);
void IniVectorSet (char* entry, GLvector v);
GLvector IniVector (char* entry);

174
Light.cpp Normal file
View File

@ -0,0 +1,174 @@
/*-----------------------------------------------------------------------------
Light.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
This tracks and renders the light sources. (Note that they do not really
CAST light in the OpenGL sense of the world, these are just simple panels.)
These are NOT subclassed to entities because these are dynamic. Some lights
blink, and thus they can't go into the fixed render lists managed by
Entity.cpp.
-----------------------------------------------------------------------------*/
#define MAX_SIZE 5
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "glTypes.h"
#include "camera.h"
#include "light.h"
#include "macro.h"
#include "math.h"
#include "random.h"
#include "render.h"
#include "texture.h"
#include "visible.h"
static GLvector2 angles[5][360];
static CLight* head;
static bool angles_done;
static int count;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void LightClear ()
{
CLight* l;
while (head) {
l = head;
head = l->_next;
delete l;
}
count = 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int LightCount ()
{
return count;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void LightRender ()
{
CLight* l;
if (!angles_done) {
for (int size = 0; size < MAX_SIZE; size++) {
for (int i = 0 ;i < 360; i++) {
angles[size][i].x = cosf ((float)i * DEGREES_TO_RADIANS) * ((float)size + 0.5f);
angles[size][i].y = sinf ((float)i * DEGREES_TO_RADIANS) * ((float)size + 0.5f);
}
}
}
glDepthMask (false);
glEnable (GL_BLEND);
glDisable (GL_CULL_FACE);
glBlendFunc (GL_ONE, GL_ONE);
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_LIGHT));
glDisable (GL_CULL_FACE);
glBegin (GL_QUADS);
for (l = head; l; l = l->_next)
l->Render ();
glEnd ();
glDepthMask (true);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CLight::CLight (GLvector pos, GLrgba color, int size)
{
_position = pos;
_color = color * 0.5f;
_size = CLAMP (size, 0, (MAX_SIZE - 1));
_vert_size = (float)_size + 0.5f;
_flat_size = _vert_size + 0.5f;
_blink = false;
_cell_x = WORLD_TO_GRID(pos.x);
_cell_z = WORLD_TO_GRID(pos.z);
_next = head;
head = this;
count++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CLight::Blink ()
{
_blink = true;
//we don't want blinkers to be in sync, so have them blink at
//slightly different rates. (Milliseconds)
_blink_interval = 1500 + RandomVal (500);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CLight::Render ()
{
int angle;
GLvector pos;
GLvector camera;
GLvector camera_position;
GLvector2 offset;
if (!Visible (_cell_x, _cell_z))
return;
camera = CameraAngle ();
camera_position = CameraPosition ();
if (fabs (camera_position.x - _position.x) > RenderFogDistance ())
return;
if (fabs (camera_position.z - _position.z) > RenderFogDistance ())
return;
if (_blink && (GetTickCount () % _blink_interval) > 200)
return;
angle = (int)MathAngle (camera.y);
offset = angles[_size][angle];
pos = _position;
//m_color.alpha = 0.25f;
glColor4fv (&_color.red);
glTexCoord2f (0, 0);
glVertex3f (pos.x + offset.x, pos.y - _vert_size, pos.z + offset.y);
glTexCoord2f (0, 1);
glVertex3f (pos.x - offset.x, pos.y - _vert_size, pos.z - offset.y);
glTexCoord2f (1, 1);
glVertex3f (pos.x - offset.x, pos.y + _vert_size, pos.z - offset.y);
glTexCoord2f (1, 0);
glVertex3f (pos.x + offset.x, pos.y + _vert_size, pos.z + offset.y);
}

23
Light.h Normal file
View File

@ -0,0 +1,23 @@
class CLight
{
GLvector _position;
GLrgba _color;
int _size;
float _vert_size;
float _flat_size;
bool _blink;
unsigned _blink_interval;
int _cell_x;
int _cell_z;
public:
CLight(GLvector pos, GLrgba color, int size);
class CLight* _next;
void Render ();
void Blink ();
};
void LightRender ();
void LightClear ();
int LightCount ();

15
Macro.h Normal file
View File

@ -0,0 +1,15 @@
#define LIMIT_INTERVAL(interval) { static unsigned next_update; if (next_update > GetTickCount ()) return; next_update = GetTickCount () + interval;}
#define DEGREES_TO_RADIANS .017453292F
#define RADIANS_TO_DEGREES 57.29577951F
#define PI ((double)3.1415926535F)
#define PI2 PI*PI
#define GRAVITY 9.5f
#define CLAMP(a,b,c) (a < b ? b : (a > c ? c : a))
#define WRAP(x,y) ((unsigned)x % y)
#define SIGN(x) (((x) > 0) ? 1 : ((x) < 0) ? -1 : 0)
#define ABS(x) (((x) < 0 ? (-x) : (x)))
#define SMALLEST(x,y) (ABS(x) < ABS(y) ? 0 : x)
#define MIN(x,y) ((x) < (y) ? x : y)
#define MAX(x,y) ((x) > (y) ? x : y)
#define POW(x,y) (float)pow(x,y)
#define SWAP(a,b) {int temp = a;a = b; b = temp;}

181
Math.cpp Normal file
View File

@ -0,0 +1,181 @@
/*-----------------------------------------------------------------------------
Math.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
Various useful math functions.
-----------------------------------------------------------------------------*/
#include <math.h>
#include "macro.h"
#include "math.h"
/*-----------------------------------------------------------------------------
Keep an angle between 0 and 360
-----------------------------------------------------------------------------*/
float MathAngle (float angle)
{
if (angle < 0.0f)
angle = 360.0f - (float)fmod (fabs (angle), 360.0f);
else
angle = (float)fmod (angle, 360.0f);
return angle;
}
/*-----------------------------------------------------------------------------
Get an angle between two given points on a grid
-----------------------------------------------------------------------------*/
float MathAngle (float x1, float y1, float x2, float y2)
{
float x_delta;
float z_delta;
float angle;
z_delta = (y1 - y2);
x_delta = (x1 - x2);
if (x_delta == 0) {
if (z_delta > 0)
return 0.0f;
else
return 180.0f;
}
if (fabs (x_delta) < fabs (z_delta)) {
angle = 90 - (float)atan (z_delta / x_delta) * RADIANS_TO_DEGREES;
if (x_delta < 0)
angle -= 180.0f;
} else {
angle = (float)atan (x_delta / z_delta) * RADIANS_TO_DEGREES;
if (z_delta < 0.0f)
angle += 180.0f;
}
if (angle< 0.0f)
angle += 360.0f;
return angle;
}
/*-----------------------------------------------------------------------------
Get distance (squared) between 2 points on a plane
-----------------------------------------------------------------------------*/
float MathDistance2 (float x1, float y1, float x2, float y2)
{
float dx;
float dy;
dx = x1 - x2;
dy = y1 - y2;
return dx * dx + dy * dy;
}
/*-----------------------------------------------------------------------------
Get distance between 2 points on a plane. This is slightly slower than
MathDistance2 ()
-----------------------------------------------------------------------------*/
float MathDistance (float x1, float y1, float x2, float y2)
{
float dx;
float dy;
dx = x1 - x2;
dy = y1 - y2;
return (float)sqrt (dx * dx + dy * dy);
}
/*-----------------------------------------------------------------------------
difference between two angles
-----------------------------------------------------------------------------*/
float MathAngleDifference (float a1, float a2)
{
float result;
result = (float)fmod (a1 - a2, 360.0);
if (result > 180.0)
return result - 360.0F;
if (result < -180.0)
return result + 360.0F;
return result;
}
/*-----------------------------------------------------------------------------
interpolate between two values
-----------------------------------------------------------------------------*/
float MathInterpolate (float n1, float n2, float delta)
{
return n1 * (1.0f - delta) + n2 * delta;
}
/*-----------------------------------------------------------------------------
return a scalar of 0.0 to 1.0, based an the given values position within a range
-----------------------------------------------------------------------------*/
float MathSmoothStep (float val, float a, float b)
{
if (b == a)
return 0.0f;
val -= a;
val /= (b - a);
return CLAMP (val, 0.0f, 1.0f);
}
/*-----------------------------------------------------------------------------
Average two values
-----------------------------------------------------------------------------*/
float MathAverage (float n1, float n2)
{
return (n1 + n2) / 2.0f;
}
/*-----------------------------------------------------------------------------
This will take linear input values from 0.0 to 1.0 and convert them to
values along a curve. This could also be acomplished with sin (), but this
way avoids converting to radians and back.
-----------------------------------------------------------------------------*/
float MathScalarCurve (float val)
{
float sign;
val = (val - 0.5f) * 2.0f;
if (val < 0.0f)
sign = -1.0f;
else
sign = 1.0f;
if (val < 0.0f)
val = -val;
val = 1.0f - val;
val *= val;
val = 1.0f - val;
val *= sign;
val = (val + 1.0f) / 2.0f;
return val;
}

10
Math.h Normal file
View File

@ -0,0 +1,10 @@
float MathAngle (float angle);
float MathAngle (float x1, float y1, float x2, float y2);
float MathAngleDifference (float a1, float a2);
float MathAverage (float n1, float n2);
float MathInterpolate (float n1, float n2, float delta);
float MathLine_distance (float x1, float y1, float x2, float y2, float px, float py);
float MathDistance (float x1, float y1, float x2, float y2);
float MathDistance2 (float x1, float y1, float x2, float y2);
float MathSmoothStep (float val, float a, float b);
float MathScalarCurve (float val);

216
Mesh.cpp Normal file
View File

@ -0,0 +1,216 @@
/*-----------------------------------------------------------------------------
Mesh.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This class is used to make constructing objects easier. It handles
allocating vertex lists, polygon lists, and suchlike.
If you were going to implement vertex buffers, this would be the place to
do it. Take away the _vertex member variable and store verts for ALL meshes
in a common list, which could then be unloaded onto the good 'ol GPU.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "glTypes.h"
#include "mesh.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CMesh::CMesh ()
{
_vertex_count = 0;
_triangle_count = 0;
_quad_strip_count = 0;
_fan_count = 0;
_cube_count = 0;
_polycount = 0;
_list = 0;
_compiled = false;
_vertex = NULL;
_normal = NULL;
_triangle = NULL;
_cube = NULL;
_quad_strip = NULL;
_fan = NULL;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CMesh::~CMesh ()
{
unsigned i;
if (_vertex)
free (_vertex);
if (_normal)
free (_normal);
if (_triangle)
free (_triangle);
if (_cube)
free (_cube);
for (i = 0; i < _quad_strip_count; i++)
delete _quad_strip[i].index_list;
delete _quad_strip;
for (i = 0; i < _fan_count; i++)
delete _fan[i].index_list;
delete _fan;
if (_list)
glDeleteLists (_list, 1);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::VertexAdd (GLvertex v)
{
_vertex = (GLvertex*)realloc (_vertex, sizeof (GLvertex) * (_vertex_count + 1));
_vertex[_vertex_count] = v;
_vertex_count++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::CubeAdd (int* index)
{
_cube = (cube*)realloc (_cube, sizeof (cube) * (_cube_count + 1));
memcpy (&_cube[_cube_count].index_list[0], index, sizeof (int) * 10);
_cube_count++;
_polycount += 5;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::QuadStripAdd (int* index, int count)
{
_quad_strip = (quad_strip*)realloc (_quad_strip, sizeof (quad_strip) * (_quad_strip_count + 1));
_quad_strip[_quad_strip_count].index_list = (int*)malloc (sizeof (int) * count);
_quad_strip[_quad_strip_count].count = count;
memcpy (&_quad_strip[_quad_strip_count].index_list[0], &index[0], sizeof (int) * count);
_quad_strip_count++;
_polycount += (count - 2) / 2;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::FanAdd (int* index, int count)
{
_fan = (fan*)realloc (_fan, sizeof (fan) * (_fan_count + 1));
_fan[_fan_count].index_list = (int*)malloc (sizeof (int) * count);
_fan[_fan_count].count = count;
memcpy (&_fan[_fan_count].index_list[0], &index[0], sizeof (int) * count);
_fan_count++;
_polycount += count - 2;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::Render ()
{
unsigned i, n;
int* index;
if (_compiled) {
glCallList (_list);
return;
}
for (i = 0; i < _quad_strip_count; i++) {
index = &_quad_strip[i].index_list[0];
glBegin (GL_QUAD_STRIP);
for (n = 0; n < _quad_strip[i].count; n++) {
glTexCoord2fv (&_vertex[index[n]].uv.x);
glVertex3fv (&_vertex[index[n]].position.x);
}
glEnd ();
}
for (i = 0; i < _cube_count; i++) {
index = &_cube[i].index_list[0];
glBegin (GL_QUAD_STRIP);
for (n = 0; n < 10; n++) {
glTexCoord2fv (&_vertex[index[n]].uv.x);
glVertex3fv (&_vertex[index[n]].position.x);
}
glEnd ();
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[index[7]].uv.x);
glVertex3fv (&_vertex[index[7]].position.x);
glVertex3fv (&_vertex[index[5]].position.x);
glVertex3fv (&_vertex[index[3]].position.x);
glVertex3fv (&_vertex[index[1]].position.x);
glEnd ();
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[index[6]].uv.x);
glVertex3fv (&_vertex[index[0]].position.x);
glVertex3fv (&_vertex[index[2]].position.x);
glVertex3fv (&_vertex[index[4]].position.x);
glVertex3fv (&_vertex[index[6]].position.x);
glEnd ();
}
for (i = 0; i < _fan_count; i++) {
index = &_fan[i].index_list[0];
glBegin (GL_TRIANGLE_FAN);
for (n = 0; n < _fan[i].count; n++) {
glTexCoord2fv (&_vertex[index[n]].uv.x);
glVertex3fv (&_vertex[index[n]].position.x);
}
glEnd ();
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::Compile ()
{
if (!_list)
_list = glGenLists(1);
glNewList (_list, GL_COMPILE);
Render ();
glEndList();
_compiled = true;
}

54
Mesh.h Normal file
View File

@ -0,0 +1,54 @@
struct cube
{
int index_list[10];
};
struct quad_strip
{
int* index_list;
unsigned count;
};
struct fan
{
int* index_list;
unsigned count;
};
class CMesh
{
public:
CMesh ();
~CMesh ();
unsigned _vertex_count;
unsigned _triangle_count;
unsigned _cube_count;
unsigned _quad_strip_count;
unsigned _fan_count;
unsigned _normal_count;
unsigned _list;
int _polycount;
GLvertex* _vertex;
GLvector* _normal;
GLtriangle* _triangle;
cube* _cube;
quad_strip* _quad_strip;
fan* _fan;
bool _compiled;
//void TriangleRender (unsigned n);
//GLtriangle* TriangleAdd (unsigned v1, int unsigned, int unsigned);
//GLtriangle* TriangleAdd (GLtriangle c);
void NormalAdd (GLvector n);
void VertexAdd (GLvertex v);
int VertexCount () { return _vertex_count; }
int PolyCount () { return _polycount; }
void CubeAdd (int* index);
void QuadStripAdd (int* index, int count);
void FanAdd (int* index, int count);
void Render ();
void Compile ();
};

266
PixelCity.dsp Normal file
View File

@ -0,0 +1,266 @@
# Microsoft Developer Studio Project File - Name="PixelCity" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=PixelCity - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "PixelCity.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "PixelCity.mak" CFG="PixelCity - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "PixelCity - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "PixelCity - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "PixelCity"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "PixelCity - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/PixelCity.scr"
!ELSEIF "$(CFG)" == "PixelCity - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "PixelCity - Win32 Release"
# Name "PixelCity - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Group "glTypes"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\glBbox.cpp
# End Source File
# Begin Source File
SOURCE=.\glMatrix.cpp
# End Source File
# Begin Source File
SOURCE=.\glQuat.cpp
# End Source File
# Begin Source File
SOURCE=.\glRgba.cpp
# End Source File
# Begin Source File
SOURCE=.\glVector2.cpp
# End Source File
# Begin Source File
SOURCE=.\glVector3.cpp
# End Source File
# End Group
# Begin Source File
SOURCE=.\Building.cpp
# End Source File
# Begin Source File
SOURCE=.\Camera.cpp
# End Source File
# Begin Source File
SOURCE=.\Car.cpp
# End Source File
# Begin Source File
SOURCE=.\Deco.cpp
# End Source File
# Begin Source File
SOURCE=.\Entity.cpp
# End Source File
# Begin Source File
SOURCE=.\Ini.cpp
# End Source File
# Begin Source File
SOURCE=.\Light.cpp
# End Source File
# Begin Source File
SOURCE=.\Math.cpp
# End Source File
# Begin Source File
SOURCE=.\Mesh.cpp
# End Source File
# Begin Source File
SOURCE=.\Random.cpp
# End Source File
# Begin Source File
SOURCE=.\Render.cpp
# End Source File
# Begin Source File
SOURCE=.\Sky.cpp
# End Source File
# Begin Source File
SOURCE=.\Texture.cpp
# End Source File
# Begin Source File
SOURCE=.\Visible.cpp
# End Source File
# Begin Source File
SOURCE=.\Win.cpp
# End Source File
# Begin Source File
SOURCE=.\World.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\Building.h
# End Source File
# Begin Source File
SOURCE=.\Camera.h
# End Source File
# Begin Source File
SOURCE=.\Car.h
# End Source File
# Begin Source File
SOURCE=.\Deco.h
# End Source File
# Begin Source File
SOURCE=.\Entity.h
# End Source File
# Begin Source File
SOURCE=.\glTypes.h
# End Source File
# Begin Source File
SOURCE=.\Ini.h
# End Source File
# Begin Source File
SOURCE=.\Light.h
# End Source File
# Begin Source File
SOURCE=.\Macro.h
# End Source File
# Begin Source File
SOURCE=.\Math.h
# End Source File
# Begin Source File
SOURCE=.\Mesh.h
# End Source File
# Begin Source File
SOURCE=.\Random.h
# End Source File
# Begin Source File
SOURCE=.\Render.h
# End Source File
# Begin Source File
SOURCE=.\Sky.h
# End Source File
# Begin Source File
SOURCE=.\Texture.h
# End Source File
# Begin Source File
SOURCE=.\Visible.h
# End Source File
# Begin Source File
SOURCE=.\Win.h
# End Source File
# Begin Source File
SOURCE=.\World.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

93
Random.cpp Normal file
View File

@ -0,0 +1,93 @@
/*-----------------------------------------------------------------------------
r a n d o m
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
The Mersenne Twister by Matsumoto and Nishimura <matumoto@math.keio.ac.jp>.
It sets new standards for the period, quality and speed of random number
generators. The incredible period is 2^19937 - 1, a number with about 6000
digits; the 32-bit random numbers exhibit best possible equidistribution
properties in dimensions up to 623; and it's fast, very fast.
-----------------------------------------------------------------------------*/
#define LOWER_MASK 0x7fffffff
#define M 397
#define MATRIX_A 0x9908b0df
#define N 624
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_L(y) (y >> 18)
#define TEMPERING_SHIFT_S(y) (y << 7)
#define TEMPERING_SHIFT_T(y) (y << 15)
#define TEMPERING_SHIFT_U(y) (y >> 11)
#define UPPER_MASK 0x80000000
#include <memory.h>
#include "random.h"
static int k = 1;
static unsigned long mag01[2] = {0x0, MATRIX_A};
static unsigned long ptgfsr[N];
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned long RandomVal (void)
{
int kk;
unsigned long y;
if (k == N) {
for (kk = 0; kk < N - M; kk++) {
y = (ptgfsr[kk] & UPPER_MASK) | (ptgfsr[kk + 1] & LOWER_MASK);
ptgfsr[kk] = ptgfsr[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (; kk < N - 1; kk++) {
y = (ptgfsr[kk] & UPPER_MASK) | (ptgfsr[kk + 1] & LOWER_MASK);
ptgfsr[kk] = ptgfsr[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (ptgfsr[N - 1] & UPPER_MASK) | (ptgfsr[0] & LOWER_MASK);
ptgfsr[N - 1] = ptgfsr[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];
k = 0;
}
y = ptgfsr[k++];
y ^= TEMPERING_SHIFT_U (y);
y ^= TEMPERING_SHIFT_S (y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T (y) & TEMPERING_MASK_C;
return y ^= TEMPERING_SHIFT_L (y);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned long RandomVal (int range)
{
return range ? (RandomVal () % range) : 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RandomInit (unsigned long seed)
{
//int k;
//memset (ptgfsr, 0, sizeof (ptgfsr));
//mag01[0] = 0x0;
//mag01[1] = MATRIX_A;
ptgfsr[0] = seed;
for (k = 1; k < N; k++)
ptgfsr[k] = 69069 * ptgfsr[k - 1];
k = 1;
}

5
Random.h Normal file
View File

@ -0,0 +1,5 @@
#define COIN_FLIP (RandomVal (2) == 0)
unsigned long RandomVal (int range);
unsigned long RandomVal (void);
void RandomInit (unsigned long seed);

777
Render.cpp Normal file
View File

@ -0,0 +1,777 @@
/*-----------------------------------------------------------------------------
Render.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This is the core of the gl rendering functions. This contains the main
rendering function RenderUpdate (), which initiates the various
other renders in the other modules.
-----------------------------------------------------------------------------*/
#define RENDER_DISTANCE 1280
#define MAX_TEXT 256
#define YOUFAIL(message) {WinPopup (message);return;}
#define HELP_SIZE sizeof(help)
#define COLOR_CYCLE_TIME 10000 //milliseconds
#define COLOR_CYCLE (COLOR_CYCLE_TIME / 4)
#define FONT_COUNT (sizeof (fonts) / sizeof (struct glFont))
#define FONT_SIZE (LOGO_PIXELS - LOGO_PIXELS / 8)
#define BLOOM_SCALING 0.07f
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include "gltypes.h"
#include "entity.h"
#include "car.h"
#include "camera.h"
#include "ini.h"
#include "light.h"
#include "macro.h"
#include "math.h"
#include "render.h"
#include "sky.h"
#include "texture.h"
#include "world.h"
#include "win.h"
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
32, // Select Our glRgbaDepth
0, 0, 0, 0, 0, 0, // glRgbaBits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // Accumulation Buffers
0, 0, 0, 0, // Accumulation Bits Ignored
16, // Z-Buffer (Depth Buffer) bits
0, // Stencil Buffers
1, // Auxiliary Buffers
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
static char help[] =
"ESC - Exit!\n"
"F1 - Show this help screen\n"
"R - Rebuild city\n"
"L - Toggle 'letterbox' mode\n"
"F - Show Framecounter\n"
"W - Toggle Wireframe\n"
"E - Change full-scene effects\n"
"T - Toggle Textures\n"
"G - Toggle Fog\n"
;
struct glFont
{
char* name;
unsigned base_char;
} fonts[] =
{
"Courier New", 0,
"Arial", 0,
"Times New Roman", 0,
"Arial Black", 0,
"Impact", 0,
"Agency FB", 0,
"Book Antiqua", 0,
};
#if SCREENSAVER
enum
{
EFFECT_NONE,
EFFECT_BLOOM,
EFFECT_BLOOM_RADIAL,
EFFECT_COLOR_CYCLE,
EFFECT_GLASS_CITY,
EFFECT_DEBUG,
EFFECT_DEBUG_OVERBLOOM,
EFFECT_COUNT
};
#else
enum
{
EFFECT_NONE,
EFFECT_BLOOM,
EFFECT_COUNT,
EFFECT_DEBUG,
EFFECT_DEBUG_OVERBLOOM,
EFFECT_BLOOM_RADIAL,
EFFECT_COLOR_CYCLE,
EFFECT_GLASS_CITY,
};
#endif
static HDC hDC;
static HGLRC hRC;
static float render_aspect;
static float fog_distance;
static int render_width;
static int render_height;
static bool letterbox;
static int letterbox_offset;
static int effect;
static int max_texture;
static unsigned next_fps;
static unsigned current_fps;
static unsigned frames;
static bool show_wireframe;
static bool bloom;
static bool flat;
static bool show_fps;
static bool show_fog;
static bool show_help;
/*-----------------------------------------------------------------------------
Draw a clock-ish progress.. widget... thing. It's cute.
-----------------------------------------------------------------------------*/
static void do_progress (float center_x, float center_y, float radius, float opacity, float progress)
{
int i;
int end_angle;
float inner, outer;
float angle;
float s, c;
float gap;
//Outer Ring
gap = radius * 0.05f;
outer = radius;
inner = radius - gap * 2;
glColor4f (1,1,1, opacity);
glBegin (GL_QUAD_STRIP);
for (i = 0; i <= 360; i+= 15) {
//GLrgba col = glRgbaUnique (i);
//glColor3fv (&col.red);
angle = (float)i * DEGREES_TO_RADIANS;
s = sinf (angle);
c = -cosf (angle);
glVertex2f (center_x + s * outer, center_y + c * outer);
glVertex2f (center_x + s * inner, center_y + c * inner);
}
glEnd ();
//Progress indicator
glColor4f (1,1,1, opacity);
end_angle = (int)(360 * progress);
outer = radius - gap * 3;
glBegin (GL_TRIANGLE_FAN);
glVertex2f (center_x, center_y);
for (i = 0; i <= end_angle; i+= 3) {
angle = (float)i * DEGREES_TO_RADIANS;
s = sinf (angle);
c = -cosf (angle);
glVertex2f (center_x + s * outer, center_y + c * outer);
}
glEnd ();
//Tic lines
glLineWidth (2.0f);
outer = radius - gap * 1;
inner = radius - gap * 2;
glColor4f (0,0,0, opacity);
glBegin (GL_LINES);
for (i = 0; i <= 360; i+= 15) {
angle = (float)i * DEGREES_TO_RADIANS;
s = sinf (angle);
c = -cosf (angle);
glVertex2f (center_x + s * outer, center_y + c * outer);
glVertex2f (center_x + s * inner, center_y + c * inner);
}
glEnd ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_effects (int type)
{
float hue1, hue2, hue3, hue4;
GLrgba color;
float fade;
int radius;
int x, y;
int i;
int bloom_radius;
int bloom_step;
fade = WorldFade ();
bloom_radius = 15;
bloom_step = bloom_radius / 3;
if (!TextureReady () && fade == 0.0f)
return;
//Now change projection modes so we can render full-screen effects
glDisable(GL_DEPTH_TEST);
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (0, render_width, render_height, 0, 0.1f, 2048);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity();
glTranslatef(0, 0, -1.0f);
glDisable (GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//Render full-screen effects
glBlendFunc (GL_ONE, GL_ONE);
glEnable (GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_BLOOM));
switch (type) {
case EFFECT_DEBUG:
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_LOGOS));
glDisable (GL_BLEND);
glBegin (GL_QUADS);
glColor3f (1, 1, 1);
glTexCoord2f (0, 0); glVertex2i (0, render_height / 4);
glTexCoord2f (0, 1); glVertex2i (0, 0);
glTexCoord2f (1, 1); glVertex2i (render_width / 4, 0);
glTexCoord2f (1, 0); glVertex2i (render_width / 4, render_height / 4);
glTexCoord2f (0, 0); glVertex2i (0, 512);
glTexCoord2f (0, 1); glVertex2i (0, 0);
glTexCoord2f (1, 1); glVertex2i (512, 0);
glTexCoord2f (1, 0); glVertex2i (512, 512);
glEnd ();
break;
case EFFECT_BLOOM_RADIAL:
//Psychedelic bloom
glEnable (GL_BLEND);
glBegin (GL_QUADS);
color = WorldBloomColor () * BLOOM_SCALING;
glColor3fv (&color.red);
for (i = 0; i <= 100; i+=10) {
glTexCoord2f (0, 0); glVertex2i (-i, i + render_height);
glTexCoord2f (0, 1); glVertex2i (-i, -i);
glTexCoord2f (1, 1); glVertex2i (i + render_width, -i);
glTexCoord2f (1, 0); glVertex2i (i + render_width, i + render_height);
}
glEnd ();
break;
case EFFECT_COLOR_CYCLE:
//Oooh. Pretty colors. Tint the scene according to screenspace.
hue1 = (float)(GetTickCount () % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
hue2 = (float)((GetTickCount () + COLOR_CYCLE) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
hue3 = (float)((GetTickCount () + COLOR_CYCLE * 2) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
hue4 = (float)((GetTickCount () + COLOR_CYCLE * 3) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME;
glBindTexture(GL_TEXTURE_2D, 0);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE);
glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR);
glBegin (GL_QUADS);
color = glRgbaFromHsl (hue1, 1.0f, 0.6f);
glColor3fv (&color.red);
glTexCoord2f (0, 0); glVertex2i (0, render_height);
color = glRgbaFromHsl (hue2, 1.0f, 0.6f);
glColor3fv (&color.red);
glTexCoord2f (0, 1); glVertex2i (0, 0);
color = glRgbaFromHsl (hue3, 1.0f, 0.6f);
glColor3fv (&color.red);
glTexCoord2f (1, 1); glVertex2i (render_width, 0);
color = glRgbaFromHsl (hue4, 1.0f, 0.6f);
glColor3fv (&color.red);
glTexCoord2f (1, 0); glVertex2i (render_width, render_height);
glEnd ();
break;
case EFFECT_BLOOM:
//Simple bloom effect
glBegin (GL_QUADS);
color = WorldBloomColor () * BLOOM_SCALING;
glColor3fv (&color.red);
for (x = -bloom_radius; x <= bloom_radius; x += bloom_step) {
for (y = -bloom_radius; y <= bloom_radius; y += bloom_step) {
if (abs (x) == abs (y) && x)
continue;
glTexCoord2f (0, 0); glVertex2i (x, y + render_height);
glTexCoord2f (0, 1); glVertex2i (x, y);
glTexCoord2f (1, 1); glVertex2i (x + render_width, y);
glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height);
}
}
glEnd ();
break;
case EFFECT_DEBUG_OVERBLOOM:
//This will punish that uppity GPU. Good for testing low frame rate behavior.
glBegin (GL_QUADS);
color = WorldBloomColor () * 0.06f;
glColor3fv (&color.red);
for (x = -50; x <= 50; x+=5) {
for (y = -50; y <= 50; y+=5) {
glTexCoord2f (0, 0); glVertex2i (x, y + render_height);
glTexCoord2f (0, 1); glVertex2i (x, y);
glTexCoord2f (1, 1); glVertex2i (x + render_width, y);
glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height);
}
}
glEnd ();
break;
}
//Do the fade to / from darkness used to hide scene transitions
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glDisable (GL_TEXTURE_2D);
glColor4f (0, 0, 0, fade);
glBegin (GL_QUADS);
glVertex2i (0, 0);
glVertex2i (0, render_height);
glVertex2i (render_width, render_height);
glVertex2i (render_width, 0);
glEnd ();
if (TextureReady () && !EntityReady () && fade != 0.0f) {
radius = render_width / 16;
do_progress ((float)render_width / 2, (float)render_height / 2, (float)radius, fade, EntityProgress ());
RenderPrint (render_width / 2 - LOGO_PIXELS, render_height / 2 + LOGO_PIXELS, 0, glRgba (0.5f), "%1.2f%%", EntityProgress () * 100.0f);
}
glPopMatrix ();
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt, ...)
{
char text[MAX_TEXT];
va_list ap;
text[0] = 0;
if (fmt == NULL)
return;
va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);
glPushAttrib(GL_LIST_BIT);
glListBase(fonts[font % FONT_COUNT].base_char - 32);
glColor3fv (&color.red);
glRasterPos2i (x, y);
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderPrint (int line, const char *fmt, ...)
{
char text[MAX_TEXT];
va_list ap;
text[0] = 0;
if (fmt == NULL)
return;
va_start (ap, fmt);
vsprintf (text, fmt, ap);
va_end (ap);
glDepthMask (false);
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (0, render_width, render_height, 0, 0.1f, 2048);
glDisable(GL_DEPTH_TEST);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity();
glTranslatef(0, 0, -1.0f);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_DEPTH_TEST);
RenderPrint (0, line * FONT_SIZE - 2, 0, glRgba (0.0f), text);
RenderPrint (4, line * FONT_SIZE + 2, 0, glRgba (0.0f), text);
RenderPrint (2, line * FONT_SIZE, 0, glRgba (1.0f), text);
glPopAttrib();
glPopMatrix ();
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void static do_help (void)
{
char* text;
int line;
char parse[HELP_SIZE];
int x;
strcpy (parse, help);
line = 0;
text = strtok (parse, "\n");
x = 10;
while (text) {
RenderPrint (line + 1, text);
text = strtok (NULL, "\n");
line++;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderResize (void)
{
float fovy;
render_width = WinWidth ();
render_height = WinHeight ();
if (letterbox) {
letterbox_offset = render_height / 6;
render_height = render_height - letterbox_offset * 2;
} else
letterbox_offset = 0;
//render_aspect = (float)render_height / (float)render_width;
glViewport (0, letterbox_offset, render_width, render_height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
render_aspect = (float)render_width / (float)render_height;
fovy = 60.0f;
if (render_aspect > 1.0f)
fovy /= render_aspect;
gluPerspective (fovy, render_aspect, 0.1f, RENDER_DISTANCE);
glMatrixMode (GL_MODELVIEW);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderTerm (void)
{
if (!hRC)
return;
wglDeleteContext (hRC);
hRC = NULL;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderInit (void)
{
HWND hWnd;
unsigned PixelFormat;
HFONT font;
HFONT oldfont;
hWnd = WinHwnd ();
if (!(hDC = GetDC (hWnd)))
YOUFAIL ("Can't Create A GL Device Context.") ;
if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd)))
YOUFAIL ("Can't Find A Suitable PixelFormat.") ;
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
YOUFAIL ("Can't Set The PixelFormat.");
if (!(hRC = wglCreateContext (hDC)))
YOUFAIL ("Can't Create A GL Rendering Context.");
if(!wglMakeCurrent(hDC,hRC))
YOUFAIL ("Can't Activate The GL Rendering Context.");
//Load the fonts for printing debug info to the window.
for (int i = 0; i < FONT_COUNT; i++) {
fonts[i].base_char = glGenLists(96);
font = CreateFont (FONT_SIZE, 0, 0, 0,
FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH,
fonts[i].name);
oldfont = (HFONT)SelectObject(hDC, font);
wglUseFontBitmaps(hDC, 32, 96, fonts[i].base_char);
SelectObject(hDC, oldfont);
DeleteObject(font);
}
//load in our settings
letterbox = IniInt ("Letterbox") != 0;
show_wireframe = IniInt ("Wireframe") != 0;
show_fps = IniInt ("ShowFPS") != 0;
show_fog = IniInt ("ShowFog") != 0;
bloom = IniInt ("Bloom") != 0;
effect = IniInt ("Effect");
flat = IniInt ("Flat") != 0;
fog_distance = WORLD_HALF;
//clear the viewport so the user isn't looking at trash while the program starts
glViewport (0, 0, WinWidth (), WinHeight ());
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SwapBuffers (hDC);
RenderResize ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderFPSToggle ()
{
show_fps = !show_fps;
IniIntSet ("ShowFPS", show_fps ? 1 : 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool RenderFog ()
{
return show_fog;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderFogToggle ()
{
show_fog = !show_fog;
IniIntSet ("ShowFog", show_fog ? 1 : 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderLetterboxToggle ()
{
letterbox = !letterbox;
IniIntSet ("Letterbox", letterbox ? 1 : 0);
RenderResize ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderWireframeToggle ()
{
show_wireframe = !show_wireframe;
IniIntSet ("Wireframe", show_wireframe ? 1 : 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool RenderWireframe ()
{
return show_wireframe;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderEffectCycle ()
{
effect = (effect + 1) % EFFECT_COUNT;
IniIntSet ("Effect", effect);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool RenderBloom ()
{
return effect == EFFECT_BLOOM || effect == EFFECT_BLOOM_RADIAL
|| effect == EFFECT_DEBUG_OVERBLOOM || effect == EFFECT_COLOR_CYCLE;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool RenderFlat ()
{
return flat;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderFlatToggle ()
{
flat = !flat;
IniIntSet ("Flat", flat ? 1 : 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderHelpToggle ()
{
show_help = !show_help;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float RenderFogDistance ()
{
return fog_distance;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderUpdate (void)
{
GLvector pos;
GLvector angle;
GLrgba color;
glViewport (0, 0, WinWidth (), WinHeight ());
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
if (letterbox)
glViewport (0, letterbox_offset, render_width, render_height);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glShadeModel(GL_SMOOTH);
glFogi (GL_FOG_MODE, GL_LINEAR);
if (show_fog) {
glEnable (GL_FOG);
glFogf (GL_FOG_START, fog_distance - 100);
glFogf (GL_FOG_END, fog_distance);
color = glRgba (0.0f);
glFogfv (GL_FOG_COLOR, &color.red);
} else
glDisable (GL_FOG);
//glEnable (GL_COLOR_MATERIAL);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode (GL_TEXTURE);
glLoadIdentity();
glMatrixMode (GL_MODELVIEW);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glLoadIdentity();
glLineWidth (2.0f);
pos = CameraPosition ();
angle = CameraAngle ();
glRotatef (angle.x, 1.0f, 0.0f, 0.0f);
glRotatef (angle.y, 0.0f, 1.0f, 0.0f);
glRotatef (angle.z, 0.0f, 0.0f, 1.0f);
glTranslatef (-pos.x, -pos.y, -pos.z);
glEnable (GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//Render all the stuff in the whole entire world.
SkyRender ();
WorldRender ();
if (effect == EFFECT_GLASS_CITY) {
glDisable (GL_CULL_FACE);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE);
glDepthFunc (false);
glDisable(GL_DEPTH_TEST);
glMatrixMode (GL_TEXTURE);
glTranslatef ((pos.x + pos.z) / SEGMENTS_PER_TEXTURE, 0, 0);
glMatrixMode (GL_MODELVIEW);
} else {
glEnable (GL_CULL_FACE);
glDisable (GL_BLEND);
}
EntityRender ();
LightRender ();
CarRender ();
if (show_wireframe) {
glDisable (GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
EntityRender ();
}
//do_effects (EntityReady () ? effect : -1);
do_effects (effect);
//Framerate tracker
if (GetTickCount () > next_fps) {
current_fps = frames;
frames = 0;
next_fps = GetTickCount () + 1000;
}
if (show_fps && !show_help) {
RenderPrint (1, "FPS=%d", current_fps);
RenderPrint (2, "Entities=%d", EntityCount () + LightCount () + CarCount ());
RenderPrint (3, "Lights=%d", LightCount ());
RenderPrint (4, "Polys=%d", EntityPolyCount () + LightCount () + CarCount ());
RenderPrint (5, "Building=%1.2f", EntityProgress () * 100);
}
//Show the help overlay
if (show_help)
do_help ();
glDepthMask (true);
frames++;
SwapBuffers (hDC);
}

24
Render.h Normal file
View File

@ -0,0 +1,24 @@
bool RenderBloom ();
void RenderEffectCycle ();
bool RenderFlat ();
void RenderFlatToggle ();
float RenderFogDistance ();
bool RenderFog ();
void RenderFogToggle ();
void RenderFPSToggle ();
void RenderInit ();
void RenderLetterboxToggle ();
void RenderResize ();
void RenderTerm ();
void RenderUpdate ();
bool RenderWireframe ();
void RenderWireframeToggle ();
void RenderHelpToggle ();
void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt, ...);

146
Sky.cpp Normal file
View File

@ -0,0 +1,146 @@
/*-----------------------------------------------------------------------------
Sky.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
Did this need to be written as a class? It did not. There will never be
more than one sky in play, so the whole class structure here is superflous,
but harmless.
-----------------------------------------------------------------------------*/
#define SKYPOINTS 24
#include <windows.h>
#include <math.h>
#include <gl\gl.h>
#include "camera.h"
#include "macro.h"
#include "math.h"
#include "random.h"
#include "render.h"
#include "sky.h"
#include "texture.h"
#include "glTypes.h"
#include "world.h"
static CSky* sky;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void SkyRender ()
{
if (sky && !RenderFlat ())
sky->Render ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void SkyClear ()
{
if(sky)
delete sky;
sky = NULL;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CSky::Render ()
{
GLvector angle, position;
if (!RenderFog ())
return;
glDepthMask (false);
glPushAttrib (GL_POLYGON_BIT | GL_FOG_BIT);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glDisable (GL_FOG);
glDisable (GL_CULL_FACE);
glPushMatrix ();
glLoadIdentity();
angle = CameraAngle ();
position = CameraPosition ();
glRotatef (angle.x, 1.0f, 0.0f, 0.0f);
glRotatef (angle.y, 0.0f, 1.0f, 0.0f);
glRotatef (angle.z, 0.0f, 0.0f, 1.0f);
glTranslatef (0.0f, -position.y / 100.0f, 0.0f);
glEnable (GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_SKY));
glCallList (m_list);
glEnable (GL_BLEND);
glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_CLOUDS));
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCallList (m_list);
glPopMatrix ();
glPopAttrib ();
glDepthMask (true);
glEnable (GL_COLOR_MATERIAL);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CSky::CSky ()
{
GLvertex circle[SKYPOINTS];
GLvector pos;
float angle;
int i;
float size;
float rad;
float lum;
size = 10.0f;
for (i = 0; i < SKYPOINTS; i++) {
angle = (float)i / (float)(SKYPOINTS - 1);
angle *= 360;
angle *= DEGREES_TO_RADIANS;
circle[i].position.x = sinf (angle) * size;
circle[i].position.y = 0.1f;
circle[i].position.z = cosf (angle) * size;
circle[i].uv.x = ((float)i / (float)(SKYPOINTS - 1)) * 5.0f;
circle[i].uv.y = 0.5f;
rad = ((float)i / (SKYPOINTS - 1)) * 180.0f * DEGREES_TO_RADIANS;
lum = sinf (rad);
lum = (float)pow (lum, 5);
circle[i].color = glRgba (lum);
}
m_list = glGenLists(1);
glNewList (m_list, GL_COMPILE);
glColor3f (1, 1, 1);
glBegin (GL_QUAD_STRIP);
for (i = 0; i < SKYPOINTS; i++) {
glTexCoord2f (circle[i].uv.x, 0.0f);
glVertex3fv (&circle[i].position.x);
pos = circle[i].position;
pos.y = size / 3.5f;
glTexCoord2f (circle[i].uv.x, 1.0f);
glVertex3fv (&pos.x);
}
glEnd ();
glEndList();
glEndList();
sky = this;
}

24
Sky.h Normal file
View File

@ -0,0 +1,24 @@
#define SKY_GRID 21
#define SKY_HALF (SKY_GRID / 2)
struct sky_point
{
GLrgba color;
GLvector position;
};
class CSky
{
private:
int m_list;
int m_stars_list;
sky_point m_grid[SKY_GRID][SKY_GRID];
public:
CSky ();
void Render (void);
};
void SkyRender ();
void SkyClear ();

887
Texture.cpp Normal file
View File

@ -0,0 +1,887 @@
/*-----------------------------------------------------------------------------
Texture.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This procedurally builds all of the textures.
I apologize in advance for the apalling state of this module. It's the victim
of iterative and experimental development. It has cruft, poorly named
functions, obscure code, poorly named variables, a is poorly organized. Even
the formatting sucks in places. Its only saving grace is that it works.
-----------------------------------------------------------------------------*/
#define RANDOM_COLOR_SHIFT ((float)(RandomVal (10)) / 50.0f)
#define RANDOM_COLOR_VAL ((float)(RandomVal (256)) / 256.0f)
#define RANDOM_COLOR_LIGHT ((float)(200 + RandomVal (56)) / 256.0f)
#define SKY_BANDS (sizeof (sky_pos) / sizeof (int))
#define PREFIX_COUNT (sizeof (prefix) / sizeof (char*))
#define SUFFIX_COUNT (sizeof (suffix) / sizeof (char*))
#define NAME_COUNT (sizeof (name) / sizeof (char*))
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include "gltypes.h"
#include "building.h"
#include "camera.h"
#include "car.h"
#include "light.h"
#include "macro.h"
#include "random.h"
#include "render.h"
#include "sky.h"
#include "texture.h"
#include "world.h"
static char* prefix[] =
{
"i",
"Green ",
"Mega",
"Super ",
"Omni",
"e",
"Hyper",
"Global ",
"Vital",
"Next ",
"Pacific ",
"Metro",
"Unity ",
"G-",
"Trans",
"Infinity ",
"Superior ",
"Monolith ",
"Best ",
"Atlantic ",
"First ",
"Union ",
"National ",
};
static char* name[] =
{
"Biotic",
"Info",
"Data",
"Solar",
"Aerospace",
"Motors",
"Nano",
"Online",
"Circuits",
"Energy",
"Med",
"Robotic",
"Exports",
"Security",
"Systems",
"Financial",
"Industrial",
"Media",
"Materials",
"Foods",
"Networks",
"Shipping",
"Tools",
"Medical",
"Publishing",
"Enterprises",
"Audio",
"Health",
"Bank",
"Imports",
"Apparel",
"Petroleum",
"Studios",
};
static char* suffix[] =
{
"Corp",
" Inc.",
"Co",
"World",
".Com",
" USA",
" Ltd.",
"Net",
" Tech",
" Labs",
" Mfg.",
" UK",
" Unlimited",
" One",
};
class CTexture
{
public:
int _my_id;
unsigned _glid;
int _size;
int _half;
int _segment_size;
bool _ready;
bool _masked;
bool _mipmap;
bool _clamp;
public:
CTexture* _next;
CTexture (int id, int size, bool mipmap, bool clamp, bool masked);
void Clear () { _ready = false; }
void Rebuild ();
void DrawWindows ();
};
static CTexture* head;
static bool textures_done;
static GLrgba horizon_color;
static GLrgba cloud_color;
static bool prefix_used[PREFIX_COUNT];
static bool name_used[NAME_COUNT];
static bool suffix_used[SUFFIX_COUNT];
static int build_time;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect_simple (int left, int top, int right, int bottom, GLrgba color)
{
glColor3fv (&color.red);
glBegin (GL_QUADS);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glEnd ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect_simple (int left, int top, int right, int bottom, GLrgba color1, GLrgba color2)
{
glColor3fv (&color1.red);
glBegin (GL_TRIANGLE_FAN);
glVertex2i ((left + right) / 2, (top + bottom) / 2);
glColor3fv (&color2.red);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glVertex2i (left, top);
glEnd ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void drawrect (int left, int top, int right, int bottom, GLrgba color)
{
float average;
float hue;
int potential;
int repeats;
int height;
int i, j;
bool bright;
GLrgba color_noise;
glDisable (GL_CULL_FACE);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glLineWidth (1.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3fv (&color.red);
if (left == right) { //in low resolution, a "rect" might be 1 pixel wide
glBegin (GL_LINES);
glVertex2i (left, top);
glVertex2i (left, bottom);
glEnd ();
} if (top == bottom) { //in low resolution, a "rect" might be 1 pixel wide
glBegin (GL_LINES);
glVertex2i (left, top);
glVertex2i (right, top);
glEnd ();
} else { // draw one of those fancy 2-dimensional rectangles
glBegin (GL_QUADS);
glVertex2i (left, top);
glVertex2i (right, top);
glVertex2i (right, bottom);
glVertex2i (left, bottom);
glEnd ();
average = (color.red + color.blue + color.green) / 3.0f;
bright = average > 0.5f;
potential = (int)(average * 255.0f);
if (bright) {
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin (GL_POINTS);
for (i = left + 1; i < right - 1; i++) {
for (j = top + 1; j < bottom - 1; j++) {
glColor4i (255, 0, RandomVal (potential), 255);
hue = 0.2f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f;
color_noise = glRgbaFromHsl (hue, 0.3f, 0.5f);
color_noise.alpha = (float)RandomVal (potential) / 144.0f;
glColor4f (RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, (float)RandomVal (potential) / 144.0f);
glColor4fv (&color_noise.red);
glVertex2i (i, j);
}
}
glEnd ();
}
repeats = RandomVal (6) + 1;
height = (bottom - top) + (RandomVal (3) - 1) + (RandomVal(3) - 1);
for (i = left; i < right; i++) {
if (RandomVal (3) == 0)
repeats = RandomVal (4) + 1;
if (RandomVal (6) == 0) {
height = bottom - top;
height = RandomVal (height);
height = RandomVal (height);
height = RandomVal (height);
height = ((bottom - top) + height) / 2;
}
for (j = 0; j < 1; j++) {
glBegin (GL_LINES);
glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f);
glVertex2i (i, bottom - height);
glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f);
glVertex2i (i, bottom);
glEnd ();
}
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void window (int x, int y, int size, int id, GLrgba color)
{
int margin;
int half;
int i;
margin = size / 3;
half = size / 2;
//color = (color * 0.9f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
//glColor3fv (&color.red);
switch (id) {
case TEXTURE_BUILDING1: //filled, 1-pixel frame
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
break;
case TEXTURE_BUILDING2: //vertical
drawrect (x + margin, y + 1, x + size - margin, y + size - 1, color);
break;
case TEXTURE_BUILDING3: //side-by-side pair
drawrect (x + 1, y + 1, x + half - 1, y + size - margin, color);
drawrect (x + half + 1, y + 1, x + size - 1, y + size - margin, color);
break;
case TEXTURE_BUILDING4: //windows with blinds
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
i = RandomVal (size - 2);
drawrect (x + 1, y + 1, x + size - 1, y + i + 1, color * 0.3f);
break;
case TEXTURE_BUILDING5: //vert stripes
drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color);
drawrect (x + margin, y + 1, x + margin, y + size - 1, color * 0.7f);
drawrect (x + size - margin - 1, y + 1, x + size - margin - 1, y + size - 1, color * 0.3f);
break;
case TEXTURE_BUILDING6: //wide horz line
drawrect (x + 1, y + 1, x + size - 1, y + size - margin, color);
break;
case TEXTURE_BUILDING7: //4-pane
drawrect (x + 2, y + 1, x + size - 1, y + size - 1, color);
drawrect (x + 2, y + half, x + size - 1, y + half, color * 0.2f);
drawrect (x + half, y + 1, x + half, y + size - 1, color * 0.2f);
break;
case TEXTURE_BUILDING8: // Single narrow window
drawrect (x + half - 1, y + 1, x + half + 1, y + size - margin, color);
break;
case TEXTURE_BUILDING9: //horizontal
drawrect (x + 1, y + margin, x + size - 1, y + size - margin - 1, color);
break;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_bloom (CTexture* t)
{
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, t->_size , t->_size);
glCullFace (GL_BACK);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask (true);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_FOG);
glFogf (GL_FOG_START, RenderFogDistance () / 2);
glFogf (GL_FOG_END, RenderFogDistance ());
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
WorldRender ();
glEnable (GL_TEXTURE_2D);
EntityRender ();
CarRender ();
LightRender ();
glBindTexture(GL_TEXTURE_2D, t->_glid);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, t->_size, t->_size, 0);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CTexture::CTexture (int id, int size, bool mipmap, bool clamp, bool masked)
{
glGenTextures (1, &_glid);
_my_id = id;
_mipmap = mipmap;
_clamp = clamp;
_masked = masked;
_size = size;
_half = size / 2;
_segment_size = size / SEGMENTS_PER_TEXTURE;
_ready = false;
_next = head;
head = this;
}
/*-----------------------------------------------------------------------------
This draws all of the windows on a building texture. lit_density controls
how many lights are on. (1 in n chance that the light is on. Higher values
mean less lit windows. run_length controls how often it will consider
changing the lit / unlit status. 1 produces a complete scatter, higher
numbers make long strings of lights.
-----------------------------------------------------------------------------*/
void CTexture::DrawWindows ()
{
int x, y;
int run;
int run_length;
int lit_density;
GLrgba color;
bool lit;
//color = glRgbaUnique (_my_id);
for (y = 0; y < SEGMENTS_PER_TEXTURE; y++) {
//Every few floors we change the behavior
if (!(y % 8)) {
run = 0;
run_length = RandomVal (9) + 2;
lit_density = 2 + RandomVal(2) + RandomVal(2);
lit = false;
}
for (x = 0; x < SEGMENTS_PER_TEXTURE; x++) {
//if this run is over reroll lit and start a new one
if (run < 1) {
run = RandomVal (run_length);
lit = RandomVal (lit_density) == 0;
//if (lit)
//color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
}
if (lit)
color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT);
else
color = glRgba ((float)(RandomVal () % 40) / 256.0f);
window (x * _segment_size, y * _segment_size, _segment_size, _my_id, color);
run--;
}
}
}
/*-----------------------------------------------------------------------------
Here is where ALL of the procedural textures are created. It's filled with
obscure logic, magic numbers, and messy code. Part of this is because
there is a lot of "art" being done here, and lots of numbers that could be
endlessly tweaked. Also because I'm lazy.
-----------------------------------------------------------------------------*/
void CTexture::Rebuild ()
{
int i, j;
int x, y;
int name_num, prefix_num, suffix_num;
float radius;
GLvector2 pos;
GLrgba color;
bool use_framebuffer;
unsigned char* bits;
unsigned start;
int lapsed;
start = GetTickCount ();
glBindTexture(GL_TEXTURE_2D, _glid);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (_clamp) {
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
//Set up our viewport so that drawing into our texture will be as easy
//as possible. We make the viewport and projection simply match the given
//texture size.
glViewport(0, 0, _size , _size);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, _size, _size, 0, 0.1f, 2048);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity();
glDisable (GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, 0);
glTranslatef(0, 0, -10.0f);
glClearColor (0, 0, 0, _masked ? 0.0f : 1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
use_framebuffer = true;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
switch (_my_id) {
case TEXTURE_GROUND:
unsigned char icolor[4];
char cell;
//memset (buffer, 0, 1024 * 1024 * 4);
bits = new unsigned char[_size * _size * 4];
ZeroMemory (bits, sizeof (bits));
icolor[3] = 255;
for (x = 0; x < _size; x++) {
for (y = 0; y < _size; y++) {
cell = WorldCell (x, y);
memset (icolor, 0, 3);
if (cell & CLAIM_ROAD)
icolor[0] = icolor[1] = icolor[2] = 12;
if (cell == CLAIM_WALK)
icolor[0] = icolor[1] = icolor[2] = 64;
icolor[0] += (unsigned char)RandomVal (4);
icolor[1] += (unsigned char)RandomVal (4);
icolor[2] += (unsigned char)RandomVal (4);
if (1) { //use this to make the road lanes visible
if (cell & MAP_ROAD_EAST)
icolor[0] += 128;
if (cell & MAP_ROAD_WEST)
icolor[1] += 128;
if (cell & MAP_ROAD_NORTH)
icolor[2] += 128;
if (cell & MAP_ROAD_SOUTH) {
icolor[1] += 64;
icolor[2] += 64;
}
}
memcpy (&bits[(x + y * _size) * 4], &icolor[0], 4);
}
}
glBindTexture(GL_TEXTURE_2D, _glid);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
use_framebuffer = false;
delete bits;
break;
case TEXTURE_LATTICE:
glLineWidth (2.0f);
glColor3f (0,0,0);
glBegin (GL_LINES);
glVertex2i (0, 0); glVertex2i (_size, _size);//diagonal
glVertex2i (0, 0); glVertex2i (0, _size);//vertical
glVertex2i (0, 0); glVertex2i (_size, 0);//vertical
glEnd ();
glBegin (GL_LINE_STRIP);
glVertex2i (0, 0);
for (i = 0; i < _size; i += 9) {
if (i % 2)
glVertex2i (0, i);
else
glVertex2i (i, i);
}
for (i = 0; i < _size; i += 9) {
if (i % 2)
glVertex2i (i, 0);
else
glVertex2i (i, i);
}
glEnd ();
break;
case TEXTURE_SOFT_CIRCLE:
//Make a simple circle of light, bright in the center and fading out
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
radius = ((float)_half) - 3;
glBegin (GL_TRIANGLE_FAN);
glColor4f (1, 1, 1, 1);
glVertex2i (_half, _half);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i++) {
pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius;
glVertex2i (_half + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
break;
case TEXTURE_LIGHT:
//
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
radius = ((float)_half) - 3;
for (j = 0; j < 2; j++) {
glBegin (GL_TRIANGLE_FAN);
glColor4f (1, 1, 1, 1);
glVertex2i (_half, _half);
if (!j)
radius = ((float)_half / 2);
else
radius = 8;
glColor4f (1, 1, 0, 0);
for (i = 0; i <= 360; i++) {
pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius;
glVertex2i (_half + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
}
break;
case TEXTURE_HEADLIGHT:
//Make a simple circle of light, bright in the center and fading out
radius = ((float)_half) - 20;
x = _half - 20;
y = _half;
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin (GL_TRIANGLE_FAN);
glColor4f (0.8f, 0.8f, 0.8f, 0.6f);
glVertex2i (_half - 5, y);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i += 36) {
pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
glVertex2i (x + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
x = _half + 20;
glBegin (GL_TRIANGLE_FAN);
glColor4f (0.8f, 0.8f, 0.8f, 0.6f);
glVertex2i (_half + 5, y);
glColor4f (0, 0, 0, 0);
for (i = 0; i <= 360; i += 36) {
pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius;
glVertex2i (x + (int)pos.x, _half + (int)pos.y);
}
glEnd ();
x = _half - 6;
drawrect_simple (x - 3, y - 2, x + 2, y + 2, glRgba (1.0f));
x = _half + 6;
drawrect_simple (x - 2, y - 2, x + 3, y + 2, glRgba (1.0f));
break;
case TEXTURE_LOGOS:
i = 0;
glDepthMask (false);
glDisable (GL_BLEND);
name_num = RandomVal (NAME_COUNT);
prefix_num = RandomVal (PREFIX_COUNT);
suffix_num = RandomVal (SUFFIX_COUNT);
glColor3f (1,1,1);
while (i < _size) {
//randomly use a prefix OR suffix, but not both. Too verbose.
/*
if (COIN_FLIP)
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", prefix[prefix_num], name[name_num]);
else
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", name[name_num], suffix[suffix_num]);
*/
RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "Pixel City");
name_num = (name_num + 1) % NAME_COUNT;
prefix_num = (prefix_num + 1) % PREFIX_COUNT;
suffix_num = (suffix_num + 1) % SUFFIX_COUNT;
i += LOGO_PIXELS;
}
break;
case TEXTURE_CLOUDS:
int width, height;
int offset;
float scale;
for (i = _size - 30; i > 5; i -= 1) {
x = RandomVal (_size);
y = i;
scale = 1.0f - ((float)y / (float)_size);
width = RandomVal (_half / 2) + (int)((float)_half * scale) / 2;
scale = 1.0f - (float)y / (float)_size;
height = (int)((float)(width) * scale);
height = MAX (height, 4);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_CULL_FACE);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, TextureId (TEXTURE_SOFT_CIRCLE));
glDepthMask (false);
glBegin (GL_QUADS);
for (offset = -_size; offset <= _size; offset += _size) {
for (scale = 1.0f; scale > 0.0f; scale -= 0.25f) {
int width_adjust;
int height_adjust;
float inv_scale;
inv_scale = 1.0f - (scale);
if (scale < 0.4f)
color = cloud_color;
else
color = glRgba (0.0f);
color.alpha = 1.0f;
glColor4fv (&color.red);
//width_adjust = (int)((1.0f - scale) * ((float)width / 2.0f));
width_adjust = (int)((float)width / 2.0f + (int)(inv_scale * ((float)width / 2.0f)));
height_adjust = height + (int)(scale * (float)height * 0.99f);
glTexCoord2f (0, 0); glVertex2i (offset + x - width_adjust, y + height - height_adjust);
glTexCoord2f (0, 1); glVertex2i (offset + x - width_adjust, y + height);
glTexCoord2f (1, 1); glVertex2i (offset + x + width_adjust, y + height);
glTexCoord2f (1, 0); glVertex2i (offset + x + width_adjust, y + height - height_adjust);
}
}
glEnd ();
}
break;
case TEXTURE_TRIM:
int margin;
y = 0;
margin = MAX (TRIM_PIXELS / 4, 1);
for (x = 0; x < _size; x += TRIM_PIXELS)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS * 2)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS * 3)
drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
y += TRIM_PIXELS;
for (x = 0; x < _size; x += TRIM_PIXELS)
drawrect_simple (x + margin, y + margin * 2, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f));
break;
case TEXTURE_SKY:
glDisable (GL_BLEND);
glBegin (GL_QUAD_STRIP);
glColor3f (0,0,0);
glVertex2i (0, _half);
glVertex2i (_size, _half);
glColor3fv (&horizon_color.red);
glVertex2i (0, _size - 2);
glVertex2i (_size, _size - 2);
glEnd ();
//Draw a bunch of little faux-buildings on the horizon.
for (i = 0; i < _size; i += 5)
drawrect (i, _size - RandomVal (8) - RandomVal (8) - RandomVal (8), i + RandomVal (9), _size, glRgba (0.0f));
break;
default: //building textures
DrawWindows ();
break;
}
glPopMatrix ();
//Now blit the finished image into our texture
if (use_framebuffer) {
glBindTexture(GL_TEXTURE_2D, _glid);
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _size, _size, 0);
}
if (_mipmap) {
bits = (unsigned char*)malloc (_size * _size * 4);
glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, _size, _size, GL_RGBA, GL_UNSIGNED_BYTE, bits);
free (bits);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
} else
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
//cleanup and restore the viewport
RenderResize ();
_ready = true;
lapsed = GetTickCount () - start;
build_time += lapsed;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned TextureId (int id)
{
for (CTexture* t = head; t; t = t->_next) {
if (t->_my_id == id)
return t->_glid;
}
return 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
unsigned TextureRandomBuilding (int index)
{
index = abs (index) % BUILDING_COUNT;
return TextureId (TEXTURE_BUILDING1 + index);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureReset (void)
{
float hue, sat;
textures_done = false;
build_time = 0;
for (CTexture* t = head; t; t = t->_next)
t->Clear ();
hue = 0.5f + (float)RandomVal (20) / 100.0f;
sat = 0.1f + (float)RandomVal (80) / 100.0f;
horizon_color = glRgbaFromHsl (hue, sat, 0.15f);
cloud_color = glRgbaFromHsl (hue, 0.15f, 0.1f);
ZeroMemory (prefix_used, sizeof (prefix_used));
ZeroMemory (name_used, sizeof (name_used));
ZeroMemory (suffix_used, sizeof (suffix_used));
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool TextureReady ()
{
return textures_done;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureUpdate (void)
{
if (textures_done) {
if (!RenderBloom ())
return;
CTexture* t;
for (t = head; t; t = t->_next) {
if (t->_my_id != TEXTURE_BLOOM)
continue;
do_bloom (t);
return;
}
}
for (CTexture* t = head; t; t = t->_next) {
if (!t->_ready) {
t->Rebuild();
return;
}
}
textures_done = true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureTerm (void)
{
CTexture* t;
while (head) {
t = head->_next;
free (head);
head = t;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void TextureInit (void)
{
new CTexture (TEXTURE_SKY, 512, true, false, false);
new CTexture (TEXTURE_CLOUDS, 256, true, false, true);
new CTexture (TEXTURE_LATTICE, 128, true, true, true);
new CTexture (TEXTURE_LIGHT, 128, false, false, true);
new CTexture (TEXTURE_SOFT_CIRCLE, 128, false, false, true);
new CTexture (TEXTURE_HEADLIGHT, 128, false, false, true);
new CTexture (TEXTURE_TRIM, TRIM_RESOLUTION, true, false, false);
if (SHOW_DEBUG_GROUND)
new CTexture (TEXTURE_GROUND, 1024, false, false, false);
new CTexture (TEXTURE_LOGOS, LOGO_RESOLUTION, true, false, true);
for (int i = TEXTURE_BUILDING1; i <= TEXTURE_BUILDING9; i++)
new CTexture (i, 512, true, false, false);
new CTexture (TEXTURE_BLOOM, 512, true, false, false);
int names = PREFIX_COUNT * NAME_COUNT + SUFFIX_COUNT * NAME_COUNT;
}

49
Texture.h Normal file
View File

@ -0,0 +1,49 @@
#define SEGMENTS_PER_TEXTURE 64
#define ONE_SEGMENT (1.0f / SEGMENTS_PER_TEXTURE)
#define LANES_PER_TEXTURE 8
#define LANE_SIZE (1.0f / LANES_PER_TEXTURE)
#define LANE_PIXELS (_size / LANES_PER_TEXTURE)
#define TRIM_RESOLUTION 256
#define TRIM_ROWS 4
#define TRIM_SIZE (1.0f / TRIM_ROWS)
#define TRIM_PIXELS (TRIM_RESOLUTION / TRIM_ROWS)
#define LOGO_RESOLUTION 512
#define LOGO_ROWS 16
#define LOGO_SIZE (1.0f / LOGO_ROWS)
#define LOGO_PIXELS (LOGO_RESOLUTION / LOGO_ROWS)
enum
{
TEXTURE_GROUND,
TEXTURE_LIGHT,
TEXTURE_SOFT_CIRCLE,
TEXTURE_SKY,
TEXTURE_CLOUDS,
TEXTURE_LOGOS,
TEXTURE_TRIM,
TEXTURE_BLOOM,
TEXTURE_HEADLIGHT,
TEXTURE_LATTICE,
TEXTURE_BUILDING1,
TEXTURE_BUILDING2,
TEXTURE_BUILDING3,
TEXTURE_BUILDING4,
TEXTURE_BUILDING5,
TEXTURE_BUILDING6,
TEXTURE_BUILDING7,
TEXTURE_BUILDING8,
TEXTURE_BUILDING9,
TEXTURE_COUNT,
};
#define BUILDING_COUNT ((TEXTURE_BUILDING9 - TEXTURE_BUILDING1) + 1)
unsigned TextureFromName (char* name);
unsigned TextureId (int id);
void TextureInit (void);
void TextureTerm (void);
unsigned TextureRandomBuilding (int index);
bool TextureReady ();
void TextureReset (void);
void TextureUpdate (void);

132
Visible.cpp Normal file
View File

@ -0,0 +1,132 @@
/*-----------------------------------------------------------------------------
Visible.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This module runs the visibility grid, a 2-dimensional array that aids in
culling objects during rendering.
There are many ways this could be refined or sped up, although tests indicate
it's not a huge drain on performance.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <math.h>
#include "glTypes.h"
#include "camera.h"
#include "macro.h"
#include "math.h"
#include "visible.h"
#include "world.h"
static bool vis_grid[GRID_SIZE][GRID_SIZE];
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool Visible (GLvector pos)
{
return vis_grid[WORLD_TO_GRID(pos.x)][WORLD_TO_GRID(pos.z)];
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool Visible (int x, int z)
{
return vis_grid[x][z];
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void VisibleUpdate (void)
{
GLvector angle;
GLvector position;
int x, y, grid_x, grid_z;
int left, right, front, back;
float angle_to;
float angle_diff;
float target_x, target_z;
LIMIT_INTERVAL (50);
//Clear the visibility table
ZeroMemory (vis_grid, sizeof (vis_grid));
//Calculate which cell the camera is in
angle = CameraAngle ();
position = CameraPosition ();
grid_x = WORLD_TO_GRID(position.x);
grid_z = WORLD_TO_GRID(position.z);
//Cells directly adjactent to the camera might technically fall out of the fov,
//but still have a few objects poking into screenspace when looking up or down.
//Rather than obsess over sorting those objects properly, it's more efficient to
//just mark them visible.
left = right = front = back = 3;
//Looking north, can't see south.
if (angle.y < 45.0f || angle.y > 315.0f)
front = 0;
//Looking south, can't see north
if (angle.y > 135.0f && angle.y < 225.0f)
back = 0;
//Looking east, can't see west
if (angle.y > 45.0f && angle.y < 135.0f)
left = 0;
//Looking west, can't see east
if (angle.y > 225.0f && angle.y < 315.0f)
right = 0;
//Now mark the block around us the might be visible
for (x = grid_x - left; x <= grid_x + right; x++) {
if (x < 0 || x >= WORLD_SIZE) //just in case the camera leaves the world map
continue;
for (y = grid_z - back; y <= grid_z + front; y++) {
if (y < 0 || y >= WORLD_SIZE) //just in case the camera leaves the world map
continue;
vis_grid[x][y] = true;
}
}
//Doesn't matter where we are facing, objects in current cell are always visible
vis_grid[grid_x][grid_z] = true;
//Here, we look at the angle from the current camera position to the cell
//on the grid, and how much that angle deviates from the current view angle.
for (x = 0; x < GRID_SIZE; x++) {
for (y = 0; y < GRID_SIZE; y++) {
//if we marked it visible earlier, skip all this math
if (vis_grid[x][y])
continue;
//if the camera is to the left of this cell, use the left edge
if (grid_x < x)
target_x = (float)x * GRID_RESOLUTION;
else
target_x = (float)(x + 1) * GRID_RESOLUTION;
if (grid_z < y)
target_z = (float)y * GRID_RESOLUTION;
else
target_z = (float)(y + 1) * GRID_RESOLUTION;
angle_to = 180 - MathAngle (target_x, target_z, position.x, position.z);
//Store how many degrees the cell is to the
angle_diff = (float)fabs (MathAngleDifference (angle.y, angle_to));
vis_grid[x][y] = angle_diff < 45;
}
}
}

11
Visible.h Normal file
View File

@ -0,0 +1,11 @@
#define GRID_RESOLUTION 32
#define GRID_CELL (GRID_RESOLUTION / 2)
#define GRID_SIZE (WORLD_SIZE / GRID_RESOLUTION)
#define WORLD_TO_GRID(x) (int)(x / GRID_RESOLUTION)
#define GRID_TO_WORLD(x) ((float)x * GRID_RESOLUTION)
void VisibleUpdate (void);
bool Visible (GLvector pos);
bool Visible (int x, int z);

608
Win.cpp Normal file
View File

@ -0,0 +1,608 @@
/*-----------------------------------------------------------------------------
Win.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
Create the main window and make it go.
-----------------------------------------------------------------------------*/
#define MOUSE_MOVEMENT 0.5f
#include <windows.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <scrnsave.h>
#include "camera.h"
#include "car.h"
#include "entity.h"
#include "glTypes.h"
#include "ini.h"
#include "macro.h"
#include "random.h"
#include "render.h"
#include "texture.h"
#include "win.h"
#include "world.h"
#include "visible.h"
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "GLaux.lib")
#if SCREENSAVER
#pragma comment (lib, "scrnsave.lib")
#endif
static HWND hwnd;
static HINSTANCE module;
static int width;
static int height;
static int half_width;
static int half_height;
static bool lmb;
static bool rmb;
static bool mouse_forced;
static POINT select_pos;
static POINT mouse_pos;
static bool quit;
static HINSTANCE instance;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CenterCursor ()
{
int center_x;
int center_y;
RECT rect;
SetCursor (NULL);
mouse_forced = true;
GetWindowRect (hwnd, &rect);
center_x = rect.left + (rect.right - rect.left) / 2;
center_y = rect.top + (rect.bottom - rect.top) / 2;
SetCursorPos (center_x, center_y);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void MoveCursor (int x, int y)
{
int center_x;
int center_y;
RECT rect;
SetCursor (NULL);
mouse_forced = true;
GetWindowRect (hwnd, &rect);
center_x = rect.left + x;
center_y = rect.top + y;
SetCursorPos (center_x, center_y);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
RECT r;
float delta_x, delta_y;
POINT p;
int param;
int key;
switch (message) {
case WM_SIZE:
param = wParam; // resizing flag
width = LOWORD(lParam); // width of client area
height = HIWORD(lParam); // height of client area
if (param == SIZE_RESTORED)
IniIntSet ("WindowMaximized", 0);
if (param == SIZE_MAXIMIZED) {
IniIntSet ("WindowMaximized", 1);
} else {
IniIntSet ("WindowWidth", width);
IniIntSet ("WindowHeight", height);
}
return 0;
case WM_MOVE:
GetClientRect (hwnd, &r);
height = r.bottom - r.top;
width = r.right - r.left;
IniIntSet ("WindowX", r.left);
IniIntSet ("WindowY", r.top);
IniIntSet ("WindowWidth", width);
IniIntSet ("WindowHeight", height);
half_width = width / 2;
half_height = height / 2;
break;
case WM_KEYDOWN:
key = (int) wParam;
if (key == 'R')
WorldReset ();
if (key == 'C')
CameraAutoToggle ();
if (key == 'W')
RenderWireframeToggle ();
if (key == 'E')
RenderEffectCycle ();
if (key == 'L')
RenderLetterboxToggle ();
if (key == 'F')
RenderFPSToggle ();
if (key == 'G')
RenderFogToggle ();
if (key == 'T')
RenderFlatToggle ();
if (key == VK_F1)
RenderHelpToggle ();
if (key == 'B')
CameraNextBehavior ();
if (key == VK_ESCAPE)
quit = true;
if (key == VK_F5)
CameraReset ();
return 0;
case WM_LBUTTONDOWN:
lmb = true;
SetCapture (hwnd);
break;
case WM_RBUTTONDOWN:
rmb = true;
SetCapture (hwnd);
break;
case WM_LBUTTONUP:
lmb = false;
if (!rmb) {
ReleaseCapture ();
MoveCursor (select_pos.x, select_pos.y);
}
break;
case WM_RBUTTONUP:
rmb = false;
if (!lmb) {
ReleaseCapture ();
MoveCursor (select_pos.x, select_pos.y);
}
break;
case WM_MOUSEMOVE:
p.x = LOWORD(lParam); // horizontal position of cursor
p.y = HIWORD(lParam); // vertical position of cursor
if (p.x < 0 || p.x > width)
break;
if (p.y < 0 || p.y > height)
break;
if (!mouse_forced && !lmb && !rmb) {
select_pos = p;
}
if (mouse_forced) {
mouse_forced = false;
} else if (rmb || lmb) {
CenterCursor ();
delta_x = (float)(mouse_pos.x - p.x) * MOUSE_MOVEMENT;
delta_y = (float)(mouse_pos.y - p.y) * MOUSE_MOVEMENT;
if (rmb && lmb) {
GLvector pos;
CameraPan (delta_x);
pos = CameraPosition ();
pos.y += delta_y;
CameraPositionSet (pos);
} else if (rmb) {
CameraPan (delta_x);
CameraForward (delta_y);
} else if (lmb) {
GLvector angle;
angle = CameraAngle ();
angle.y -= delta_x;
angle.x += delta_y;
CameraAngleSet (angle);
}
}
mouse_pos = p;
break;
case WM_CLOSE:
quit = true;
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
HINSTANCE WinInstance ()
{
return instance;
}
/*-----------------------------------------------------------------------------
n o t e
-----------------------------------------------------------------------------*/
void WinPopup (char* message, ...)
{
va_list marker;
char buf[1024];
va_start (marker, message);
vsprintf (buf, message, marker);
va_end (marker);
MessageBox (NULL, buf, APP_TITLE, MB_ICONSTOP | MB_OK |
MB_TASKMODAL);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int WinWidth (void)
{
return width;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WinMousePosition (int* x, int* y)
{
*x = select_pos.x;
*y = select_pos.y;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int WinHeight (void)
{
return height;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WinTerm (void)
{
#if !SCREENAVER
DestroyWindow (hwnd);
#endif
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
HWND WinHwnd (void)
{
return hwnd;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool WinInit (void)
{
WNDCLASSEX wcex;
int x, y;
int style;
bool max;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = instance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = APP_TITLE;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex)) {
WinPopup ("Cannot create window class");
return false;
}
x = IniInt ("WindowX");
y = IniInt ("WindowY");
style = WS_TILEDWINDOW;
style |= WS_MAXIMIZE;
width = IniInt ("WindowWidth");
height = IniInt ("WindowHeight");
width = CLAMP (width, 800, 2048);
height = CLAMP (height, 600, 2048);
half_width = width / 2;
half_height = height / 2;
max = IniInt ("WindowMaximized") == 1;
if (!(hwnd = CreateWindowEx (0, APP_TITLE, APP_TITLE, style,
CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, instance, NULL))) {
WinPopup ("Cannot create window");
return false;
}
if (max)
ShowWindow (hwnd, SW_MAXIMIZE);
else
ShowWindow (hwnd, SW_SHOW);
UpdateWindow (hwnd);
return true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppQuit ()
{
quit = true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppInit (void)
{
RandomInit (1);
CameraInit ();
RenderInit ();
TextureInit ();
WorldInit ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppUpdate ()
{
CameraUpdate ();
WorldUpdate ();
TextureUpdate ();
VisibleUpdate ();
CarUpdate ();
EntityUpdate ();
RenderUpdate ();
}
/*-----------------------------------------------------------------------------
W i n M a i n
-----------------------------------------------------------------------------*/
void AppTerm (void)
{
TextureTerm ();
WorldTerm ();
RenderTerm ();
CameraTerm ();
WinTerm ();
}
/*-----------------------------------------------------------------------------
W i n M a i n
-----------------------------------------------------------------------------*/
#if !SCREENSAVER
int PASCAL WinMain (HINSTANCE instance_in, HINSTANCE previous_instance,
LPSTR command_line, int show_style)
{
MSG msg;
instance = instance_in;
WinInit ();
AppInit ();
while (!quit) {
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message == WM_QUIT)
quit = true;
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} else {
AppUpdate ();
}
}
AppTerm ();
return 0;
}
#else
static bool terminated;
LONG WINAPI ScreenSaverProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
RECT r;
float delta_x, delta_y;
POINT p;
int param;
int key;
if (terminated)
return DefScreenSaverProc (hWnd, msg, wParam, lParam);
switch (msg) {
case WM_CREATE:
hwnd = hWnd;
AppInit ();
return 0;
case WM_CLOSE:
case WM_DESTROY:
AppTerm ();
terminated = true;
return 0;
case WM_PAINT:
AppUpdate ();
return 0;
case WM_SIZE:
param = wParam; // resizing flag
width = LOWORD(lParam); // width of client area
height = HIWORD(lParam); // height of client area
if (param == SIZE_MAXIMIZED) {
IniIntSet ("WindowMaximized", 1);
} else {
IniIntSet ("WindowWidth", width);
IniIntSet ("WindowHeight", height);
}
return 0;
case WM_MOVE:
GetClientRect (hwnd, &r);
height = r.bottom - r.top;
width = r.right - r.left;
IniIntSet ("WindowX", r.left);
IniIntSet ("WindowY", r.top);
IniIntSet ("WindowWidth", width);
IniIntSet ("WindowHeight", height);
half_width = width / 2;
half_height = height / 2;
break;
case WM_KEYDOWN:
key = (int) wParam;
if (key == 'R')
WorldReset ();
else if (key == 'C')
CameraAutoToggle ();
else if (key == 'W')
RenderWireframeToggle ();
else if (key == 'E')
RenderEffectCycle ();
else if (key == 'L')
RenderLetterboxToggle ();
else if (key == 'F')
RenderFPSToggle ();
else if (key == 'G')
RenderFogToggle ();
else if (key == 'T')
RenderFlatToggle ();
else if (key == VK_F1)
RenderHelpToggle ();
else if (key == VK_ESCAPE)
break;
else if (key == VK_F5)
CameraReset ();
else
break;
return 0;
case WM_LBUTTONDOWN:
lmb = true;
SetCapture (hwnd);
break;
case WM_RBUTTONDOWN:
rmb = true;
SetCapture (hwnd);
break;
case WM_LBUTTONUP:
lmb = false;
if (!rmb) {
ReleaseCapture ();
MoveCursor (select_pos.x, select_pos.y);
}
break;
case WM_RBUTTONUP:
rmb = false;
if (!lmb) {
ReleaseCapture ();
MoveCursor (select_pos.x, select_pos.y);
}
break;
case WM_MOUSEMOVE:
p.x = LOWORD(lParam); // horizontal position of cursor
p.y = HIWORD(lParam); // vertical position of cursor
if (p.x < 0 || p.x > width)
break;
if (p.y < 0 || p.y > height)
break;
if (!mouse_forced && !lmb && !rmb) {
select_pos = p;
}
if (mouse_forced) {
mouse_forced = false;
} else if (rmb || lmb) {
CenterCursor ();
delta_x = (float)(mouse_pos.x - p.x) * MOUSE_MOVEMENT;
delta_y = (float)(mouse_pos.y - p.y) * MOUSE_MOVEMENT;
if (rmb && lmb) {
GLvector pos;
CameraPan (delta_x);
pos = CameraPosition ();
pos.y += delta_y;
CameraPositionSet (pos);
} else if (rmb) {
CameraPan (delta_x);
CameraForward (delta_y);
} else if (lmb) {
GLvector angle;
angle = CameraAngle ();
angle.y -= delta_x;
angle.x += delta_y;
CameraAngleSet (angle);
}
}
mouse_pos = p;
break;
}
return DefScreenSaverProc (hWnd, msg, wParam, lParam);
}
BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { return FALSE; }
BOOL WINAPI RegisterDialogClasses(HANDLE hInst) { return TRUE; }
#endif

12
Win.h Normal file
View File

@ -0,0 +1,12 @@
#define APP_TITLE "PixelCity"
#define APP "pixelcity"
#define SCREENSAVER 0
HWND WinHwnd (void);
void WinPopup (char* message, ...);
void WinTerm (void);
bool WinInit (void);
int WinWidth (void);
int WinHeight (void);
void WinMousePosition (int* x, int* y);

745
World.cpp Normal file
View File

@ -0,0 +1,745 @@
/*-----------------------------------------------------------------------------
World.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
This holds a bunch of variables used by the other modules. It has the
claim system, which tracks all of the "property" is being used: As roads,
buildings, etc.
-----------------------------------------------------------------------------*/
#define HUE_COUNT (sizeof(hue_list)/sizeof(float))
#define LIGHT_COLOR_COUNT (sizeof(light_colors)/sizeof(HSL))
#define CARS 600
#define WORLD_EDGE 200
#if SCREENSAVER
#define RESET_INTERVAL 120 //seconds
#define FADE_TIME 500 //milliseconds
#else
#define RESET_INTERVAL 999 //seconds
#define FADE_TIME 1500 //milliseconds
#endif
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include <math.h>
#include <time.h>
#include "glTypes.h"
#include "building.h"
#include "car.h"
#include "deco.h"
#include "camera.h"
#include "light.h"
#include "macro.h"
#include "math.h"
#include "mesh.h"
#include "random.h"
#include "render.h"
#include "sky.h"
#include "texture.h"
#include "visible.h"
#include "world.h"
struct plot
{
int x;
int z;
int width;
int depth;
};
enum {
FADE_IDLE,
FADE_OUT,
FADE_WAIT,
FADE_IN,
};
struct HSL
{
float hue;
float sat;
float lum;
};
class CStreet
{
public:
int _x;
int _y;
int _width;
int _depth;
CMesh* _mesh;
CStreet (int x, int y, int width, int depth);
~CStreet();
void Render ();
};
static HSL light_colors[] =
{
0.04f, 0.9f, 0.93f, //Amber / pink
0.055f, 0.95f, 0.93f, //Slightly brighter amber
0.08f, 0.7f, 0.93f, //Very pale amber
0.07f, 0.9f, 0.93f, //Very pale orange
0.1f, 0.9f, 0.85f, //Peach
0.13f, 0.9f, 0.93f, //Pale Yellow
0.15f, 0.9f, 0.93f, //Yellow
0.17f, 1.0f, 0.85f, //Saturated Yellow
0.55f, 0.9f, 0.93f, //Cyan
0.55f, 0.9f, 0.93f, //Cyan - pale, almost white
0.6f, 0.9f, 0.93f, //Pale blue
0.65f, 0.9f, 0.93f, //Pale Blue II, The Palening
0.65f, 0.4f, 0.99f, //Pure white. Bo-ring.
0.65f, 0.0f, 0.8f, //Dimmer white.
0.65f, 0.0f, 0.6f, //Dimmest white.
};
static float hue_list[] = { 0.04f, 0.07f, 0.1f, 0.5f, 0.6f }; //Yellows and blues - good for lights
static GLrgba bloom_color;
static long last_update;
static char world[WORLD_SIZE][WORLD_SIZE];
static CSky* sky;
static int fade_state;
static unsigned fade_start;
static float fade_current;
static int modern_count;
static int tower_count;
static int blocky_count;
static bool reset_needed;
static int skyscrapers;
static GLbbox hot_zone;
static unsigned start_time;
static int logo_index;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static GLrgba get_light_color (float sat, float lum)
{
int index;
index = RandomVal (LIGHT_COLOR_COUNT);
return glRgbaFromHsl (light_colors[index].hue, sat, lum);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void claim (int x, int y, int width, int depth, int val)
{
int xx, yy;
for (xx = x; xx < (x + width); xx++) {
for (yy = y; yy < (y + depth); yy++) {
world[CLAMP (xx,0,WORLD_SIZE - 1)][CLAMP (yy,0,WORLD_SIZE - 1)] |= val;
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static bool claimed (int x, int y, int width, int depth)
{
int xx, yy;
for (xx = x; xx < x + width; xx++) {
for (yy = y; yy < y + depth; yy++) {
if (world[CLAMP (xx,0,WORLD_SIZE - 1)][CLAMP (yy,0,WORLD_SIZE - 1)])
return true;
}
}
return false;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void build_road (int x1, int y1, int width, int depth)
{
int lanes;
int divider;
int sidewalk;
//the given rectangle defines a street and its sidewalk. See which way it goes.
if (width > depth)
lanes = depth;
else
lanes = width;
//if we dont have room for both lanes and sidewalk, abort
if (lanes < 4)
return;
//if we have an odd number of lanes, give the extra to a divider.
if (lanes % 2) {
lanes--;
divider = 1;
} else
divider = 0;
//no more than 10 traffic lanes, give the rest to sidewalks
sidewalk = MAX (2, (lanes - 10));
lanes -= sidewalk;
sidewalk /= 2;
//take the remaining space and give half to each direction
lanes /= 2;
//Mark the entire rectangle as used
claim (x1, y1, width, depth, CLAIM_WALK);
//now place the directional roads
if (width > depth) {
claim (x1, y1 + sidewalk, width, lanes, CLAIM_ROAD | MAP_ROAD_WEST);
claim (x1, y1 + sidewalk + lanes + divider, width, lanes, CLAIM_ROAD | MAP_ROAD_EAST);
} else {
claim (x1 + sidewalk, y1, lanes, depth, CLAIM_ROAD | MAP_ROAD_SOUTH);
claim (x1 + sidewalk + lanes + divider, y1, lanes, depth, CLAIM_ROAD | MAP_ROAD_NORTH);
}
//new CStreet (x1, y1, width, depth);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static plot find_plot (int x, int z)
{
plot p;
int x1, x2, z1, z2;
//We've been given the location of an open bit of land, but we have no
//idea how big it is. Find the boundary.
x1 = x2 = x;
while (!claimed (x1 - 1, z, 1, 1) && x1 > 0)
x1--;
while (!claimed (x2 + 1, z, 1, 1) && x2 < WORLD_SIZE)
x2++;
z1 = z2 = z;
while (!claimed (x, z1 - 1, 1, 1) && z1 > 0)
z1--;
while (!claimed (x, z2 + 1, 1, 1) && z2 < WORLD_SIZE)
z2++;
p.width = (x2 - x1);
p.depth = (z2 - z1);
p.x = x1;
p.z = z1;
return p;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static plot make_plot (int x, int z, int width, int depth)
{
plot p = {x, z, width, depth};
return p;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void do_building (plot p)
{
int height;
int seed;
int area;
int type;
GLrgba color;
bool square;
//now we know how big the rectangle plot is.
area = p.width * p.depth;
color = WorldLightColor (RandomVal ());
seed = RandomVal ();
//Make sure the plot is big enough for a building
if (p.width < 10 || p.depth < 10)
return;
//If the area is too big for one building, sub-divide it.
if (area > 600) {
if (p.width > p.depth) {
p.width /= 2;
if (COIN_FLIP)
do_building (make_plot (p.x, p.z, p.width, p.depth));
else
do_building (make_plot (p.x + p.width, p.z, p.width, p.depth));
return;
} else {
p.depth /= 2;
if (COIN_FLIP)
do_building (make_plot (p.x, p.z, p.width, p.depth));
else
do_building (make_plot (p.x, p.z + p.depth, p.width, p.depth));
return;
}
}
if (area < 100)
return;
//The plot is "square" if width & depth are close
square = abs (p.width - p.depth) < 10;
//mark the land as used so other buildings don't appear here, even if we don't use it all.
claim (p.x, p.z, p.width, p.depth, CLAIM_BUILDING);
//The roundy mod buildings look best on square plots.
if (square && p.width > 20) {
height = 45 + RandomVal (10);
modern_count++;
skyscrapers++;
new CBuilding (BUILDING_MODERN, p.x, p.z, height, p.width, p.depth, seed, color);
return;
}
//This spot isn't ideal for any particular building, but try to keep a good mix
if (tower_count < modern_count && tower_count < blocky_count) {
type = BUILDING_TOWER;
tower_count++;
} else if (blocky_count < modern_count) {
type = BUILDING_BLOCKY;
blocky_count++;
} else {
type = BUILDING_MODERN;
modern_count++;
}
height = 45 + RandomVal (10);
new CBuilding (type, p.x, p.z, height, p.width, p.depth, seed, color);
skyscrapers++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static int build_light_strip (int x1, int z1, int direction)
{
CDeco* d;
GLrgba color;
int x2, z2;
int length;
int width, depth;
int dir_x, dir_z;
float size_adjust;
//We adjust the size of the lights with this.
size_adjust = 2.5f;
color = glRgbaFromHsl (0.09f, 0.99f, 0.85f);
switch (direction) {
case NORTH:
dir_z = 1; dir_x = 0;break;
case SOUTH:
dir_z = 1; dir_x = 0;break;
case EAST:
dir_z = 0; dir_x = 1;break;
case WEST:
dir_z = 0; dir_x = 1;break;
}
//So we know we're on the corner of an intersection
//look in the given until we reach the end of the sidewalk
x2 = x1;
z2 = z1;
length = 0;
while (x2 > 0 && x2 < WORLD_SIZE && z2 > 0 && z2 < WORLD_SIZE) {
if ((world[x2][z2] & CLAIM_ROAD))
break;
length++;
x2 += dir_x;
z2 += dir_z;
}
if (length < 10)
return length;
width = MAX (abs(x2 - x1), 1);
depth = MAX (abs(z2 - z1), 1);
d = new CDeco;
if (direction == EAST)
d->CreateLightStrip ((float)x1, (float)z1 - size_adjust, (float)width, (float)depth + size_adjust, 2, color);
else if (direction == WEST)
d->CreateLightStrip ((float)x1, (float)z1, (float)width, (float)depth + size_adjust, 2, color);
else if (direction == NORTH)
d->CreateLightStrip ((float)x1, (float)z1, (float)width + size_adjust, (float)depth, 2, color);
else
d->CreateLightStrip ((float)x1 - size_adjust, (float)z1, (float)width + size_adjust, (float)depth, 2, color);
return length;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static void do_reset (void)
{
int x, y;
int width, depth, height;
int attempts;
bool broadway_done;
bool road_left, road_right;
GLrgba light_color;
GLrgba building_color;
float west_street, north_street, east_street, south_street;
//RandomInit (6);
reset_needed = false;
broadway_done = false;
skyscrapers = 0;
logo_index = 0;
tower_count = blocky_count = modern_count = 0;
hot_zone = glBboxClear ();
EntityClear ();
LightClear ();
CarClear ();
TextureReset ();
//Pick a tint for the bloom
bloom_color = get_light_color(0.5f + (float)RandomVal (10) / 20.0f, 0.75f);
light_color = glRgbaFromHsl (0.11f, 1.0f, 0.65f);
ZeroMemory (world, WORLD_SIZE * WORLD_SIZE);
for (y = WORLD_EDGE; y < WORLD_SIZE - WORLD_EDGE; y += RandomVal (30) + 20) {
if (!broadway_done && y > WORLD_HALF - 20) {
build_road (0, y, WORLD_SIZE, 19);
y += 20;
broadway_done = true;
} else {
depth = 6 + RandomVal (6);
if (y < WORLD_HALF / 2)
north_street = (float)(y + depth / 2);
if (y < (WORLD_SIZE - WORLD_HALF / 2))
south_street = (float)(y + depth / 2);
build_road (0, y, WORLD_SIZE, depth);
}
}
broadway_done = false;
for (x = WORLD_EDGE; x < WORLD_SIZE - WORLD_EDGE; x += RandomVal (30) + 20) {
if (!broadway_done && x > WORLD_HALF - 20) {
build_road (x, 0, 19, WORLD_SIZE);
x += 20;
broadway_done = true;
} else {
width = 6 + RandomVal (6);
if (x <= WORLD_HALF / 2)
west_street = (float)(x + width / 2);
if (x <= WORLD_HALF + WORLD_HALF / 2)
east_street = (float)(x + width / 2);
build_road (x, 0, width, WORLD_SIZE);
}
}
//We kept track of the positions of streets that will outline the high-detail hot zone
//in the middle of the world. Save this in a bounding box so that later we can
//have the camera fly around without clipping through buildings.
hot_zone = glBboxContainPoint (hot_zone, glVector (west_street, 0.0f, north_street));
hot_zone = glBboxContainPoint (hot_zone, glVector (east_street, 0.0f, south_street));
//Scan for places to put runs of streetlights on the east & west side of the road
for (x = 1; x < WORLD_SIZE - 1; x++) {
for (y = 0; y < WORLD_SIZE; y++) {
//if this isn't a bit of sidewalk, then keep looking
if (!(world[x][y] & CLAIM_WALK))
continue;
//If it's used as a road, skip it.
if ((world[x][y] & CLAIM_ROAD))
continue;
road_left = (world[x + 1][y] & CLAIM_ROAD) != 0;
road_right = (world[x - 1][y] & CLAIM_ROAD) != 0;
//if the cells to our east and west are not road, then we're not on a corner.
if (!road_left && !road_right)
continue;
//if the cell to our east AND west is road, then we're on a median. skip it
if (road_left && road_right)
continue;
y += build_light_strip (x, y, road_right ? SOUTH : NORTH);
}
}
//Scan for places to put runs of streetlights on the north & south side of the road
for (y = 1; y < WORLD_SIZE - 1; y++) {
for (x = 1; x < WORLD_SIZE - 1; x++) {
//if this isn't a bit of sidewalk, then keep looking
if (!(world[x][y] & CLAIM_WALK))
continue;
//If it's used as a road, skip it.
if ((world[x][y] & CLAIM_ROAD))
continue;
road_left = (world[x][y + 1] & CLAIM_ROAD) != 0;
road_right = (world[x][y - 1] & CLAIM_ROAD) != 0;
//if the cell to our east AND west is road, then we're on a median. skip it
if (road_left && road_right)
continue;
//if the cells to our north and south are not road, then we're not on a corner.
if (!road_left && !road_right)
continue;
x += build_light_strip (x, y, road_right ? EAST : WEST);
}
}
//Scan over the center area of the map and place the big buildings
attempts = 0;
while (skyscrapers < 50 && attempts < 350) {
x = (WORLD_HALF / 2) + (RandomVal () % WORLD_HALF);
y = (WORLD_HALF / 2) + (RandomVal () % WORLD_HALF);
if (!claimed (x, y, 1,1)) {
do_building (find_plot (x, y));
skyscrapers++;
}
attempts++;
}
//now blanket the rest of the world with lesser buildings
for (x = 0; x < WORLD_SIZE; x ++) {
for (y = 0; y < WORLD_SIZE; y ++) {
if (world[CLAMP (x,0,WORLD_SIZE)][CLAMP (y,0,WORLD_SIZE)])
continue;
width = 12 + RandomVal (20);
depth = 12 + RandomVal (20);
height = MIN (width, depth);
if (x < 30 || y < 30 || x > WORLD_SIZE - 30 || y > WORLD_SIZE - 30)
height = RandomVal (15) + 20;
else if (x < WORLD_HALF / 2)
height /= 2;
while (width > 8 && depth > 8) {
if (!claimed (x, y, width, depth)) {
claim (x, y, width, depth,CLAIM_BUILDING);
building_color = WorldLightColor (RandomVal ());
//if we're out of the hot zone, use simple buildings
if (x < hot_zone.min.x || x > hot_zone.max.x || y < hot_zone.min.z || y > hot_zone.max.z) {
height = 5 + RandomVal (height) + RandomVal (height);
new CBuilding (BUILDING_SIMPLE, x + 1, y + 1, height, width - 2, depth - 2, RandomVal (), building_color);
} else { //use fancy buildings.
height = 15 + RandomVal (15);
width -=2;
depth -=2;
if (COIN_FLIP)
new CBuilding (BUILDING_TOWER, x + 1, y + 1, height, width, depth, RandomVal (), building_color);
else
new CBuilding (BUILDING_BLOCKY, x + 1, y + 1, height, width, depth, RandomVal (), building_color);
}
break;
}
width--;
depth--;
}
//leave big gaps near the edge of the map, no need to pack detail there.
if (y < WORLD_EDGE || y > WORLD_SIZE - WORLD_EDGE)
y += 32;
}
//leave big gaps near the edge of the map
if (x < WORLD_EDGE || x > WORLD_SIZE - WORLD_EDGE)
x += 28;
}
}
/*-----------------------------------------------------------------------------
This will return a random color which is suitible for light sources, taken
from a narrow group of hues. (Yellows, oranges, blues.)
-----------------------------------------------------------------------------*/
GLrgba WorldLightColor (unsigned index)
{
index %= LIGHT_COLOR_COUNT;
return glRgbaFromHsl (light_colors[index].hue, light_colors[index].sat, light_colors[index].lum);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
char WorldCell (int x, int y)
{
return world[CLAMP (x, 0,WORLD_SIZE - 1)][CLAMP (y, 0, WORLD_SIZE - 1)];
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba WorldBloomColor ()
{
return bloom_color;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int WorldLogoIndex ()
{
return logo_index++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLbbox WorldHotZone ()
{
return hot_zone;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WorldTerm (void)
{
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WorldReset (void)
{
//If we're already fading out, then this is the developer hammering on the
//"rebuild" button. Let's hurry things up for the nice man...
if (fade_state == FADE_OUT)
do_reset ();
//If reset is called but the world isn't ready, then don't bother fading out.
//The program probably just started.
fade_state = FADE_OUT;
fade_start = GetTickCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WorldRender ()
{
//Cheap - render the crappy one-texture streets
if (!SHOW_DEBUG_GROUND)
return;
glDepthMask (false);
glDisable (GL_CULL_FACE);
glDisable (GL_BLEND);
glEnable (GL_TEXTURE_2D);
glColor3f (1,1,1);
glBindTexture (GL_TEXTURE_2D, TextureId (TEXTURE_GROUND));
glBegin (GL_QUADS);
glTexCoord2f (0, 0); glVertex3f ( 0., 0, 0);
glTexCoord2f (0, 1); glVertex3f ( 0, 0, 1024);
glTexCoord2f (1, 1); glVertex3f ( 1024, 0, 1024);
glTexCoord2f (1, 0); glVertex3f ( 1024, 0, 0);
glEnd ();
glDepthMask (true);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float WorldFade (void)
{
return fade_current;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WorldUpdate (void)
{
unsigned fade_delta;
unsigned now, elapsed;
now = GetTickCount ();
if (reset_needed) {
do_reset (); //Now we've faded out the scene, rebuild it
}
if (fade_state != FADE_IDLE) {
if (fade_state == FADE_WAIT && TextureReady () && EntityReady ()) {
fade_state = FADE_IN;
fade_start = now;
fade_current = 1.0f;
}
fade_delta = now - fade_start;
//See if we're done fading in or out
if (fade_delta > FADE_TIME && fade_state != FADE_WAIT) {
if (fade_state == FADE_OUT) {
reset_needed = true;
fade_state = FADE_WAIT;
fade_current = 1.0f;
} else {
fade_state = FADE_IDLE;
fade_current = 0.0f;
start_time = time (NULL);
}
} else {
fade_current = (float)fade_delta / FADE_TIME;
if (fade_state == FADE_IN)
fade_current = 1.0f - fade_current;
if (fade_state == FADE_WAIT)
fade_current = 1.0f;
}
if (!TextureReady ())
fade_current = 1.0f;
}
if (fade_state == FADE_IDLE && !TextureReady ()) {
fade_state = FADE_IN;
fade_start = now;
}
elapsed = time (NULL) - start_time;
if (fade_state == FADE_IDLE && elapsed > RESET_INTERVAL)
WorldReset ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void WorldInit (void)
{
last_update = GetTickCount ();
for (int i = 0; i < CARS; i++)
new CCar ();
sky = new CSky ();
WorldReset ();
fade_state = FADE_OUT;
fade_start = 0;
}

35
World.h Normal file
View File

@ -0,0 +1,35 @@
#define SHOW_DEBUG_GROUND 0
#define WORLD_SIZE 1024
#define WORLD_HALF (WORLD_SIZE / 2)
#define CLAIM_ROAD 1
#define CLAIM_WALK 2
#define CLAIM_BUILDING 4
#define MAP_ROAD_NORTH 8
#define MAP_ROAD_SOUTH 16
#define MAP_ROAD_EAST 32
#define MAP_ROAD_WEST 64
#define RANDOM_COLOR (glRgbaFromHsl ((float)RandomVal (255)/255,1.0f, 0.75f))
enum
{
NORTH,
EAST,
SOUTH,
WEST
};
GLrgba WorldBloomColor ();
char WorldCell (int x, int y);
GLrgba WorldLightColor (unsigned index);
int WorldLogoIndex ();
GLbbox WorldHotZone ();
void WorldInit (void);
float WorldFade (void);
void WorldRender ();
void WorldReset (void);
void WorldTerm (void);
void WorldUpdate (void);

74
foo.h Normal file
View File

@ -0,0 +1,74 @@
i
Green
Mega
Super
Omni
e
Hyper
Global
Vital
Next
Pacific
Metro
Unity
G-
Trans
Infinity
Superior
Monolith
Best
Atlantic
First
Union
National
Biotic
Info
Data
Solar
Aerospace
Motors
Nano
Online
Circuits
Energy
Med
Robotic
Exports
Security
Systems
Financial
Industrial
Media
Materials
Foods
Networks
Shipping
Tools
Medical
Publishing
Enterpise
Audio
Health
Bank
Imports
Apparel
Petroleum
Studios
Corp
Inc.
Co
World
.Com
USA
Ltd.
Net
Tech
Labs
Mfg.
UK
Unlimited
One

70
glBbox.cpp Normal file
View File

@ -0,0 +1,70 @@
/*-----------------------------------------------------------------------------
glBbox.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
This module has a few functions useful for manipulating the bounding-box
structs.
-----------------------------------------------------------------------------*/
#define MAX_VALUE 999999999999999.9f
#include <math.h>
#include "macro.h"
#include "glTypes.h"
/*-----------------------------------------------------------------------------
Does the given point fall within the given Bbox?
-----------------------------------------------------------------------------*/
bool glBboxTestPoint (GLbbox box, GLvector point)
{
if (point.x > box.max.x || point.x < box.min.x)
return false;
if (point.y > box.max.y || point.y < box.min.y)
return false;
if (point.z > box.max.z || point.z < box.min.z)
return false;
return true;
}
/*-----------------------------------------------------------------------------
Expand Bbox (if needed) to contain given point
-----------------------------------------------------------------------------*/
GLbbox glBboxContainPoint (GLbbox box, GLvector point)
{
box.min.x = MIN (box.min.x, point.x);
box.min.y = MIN (box.min.y, point.y);
box.min.z = MIN (box.min.z, point.z);
box.max.x = MAX (box.max.x, point.x);
box.max.y = MAX (box.max.y, point.y);
box.max.z = MAX (box.max.z, point.z);
return box;
}
/*-----------------------------------------------------------------------------
This will invalidate the bbox.
-----------------------------------------------------------------------------*/
GLbbox glBboxClear (void)
{
GLbbox result;
result.max = glVector (-MAX_VALUE, -MAX_VALUE, -MAX_VALUE);
result.min = glVector ( MAX_VALUE, MAX_VALUE, MAX_VALUE);
return result;
}

324
glMatrix.cpp Normal file
View File

@ -0,0 +1,324 @@
/*-----------------------------------------------------------------------------
glMatrix.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
Functions useful for manipulating the Matrix struct
-----------------------------------------------------------------------------*/
#define M(e,x,y) (e.elements[x][y])
/*** Order type constants, constructors, extractors ***/
/* There are 24 possible conventions, designated by: */
/* o EulAxI = axis used initially */
/* o EulPar = parity of axis permutation */
/* o EulRep = repetition of initial axis as last */
/* o EulFrm = frame from which axes are taken */
/* Axes I,J,K will be a permutation of X,Y,Z. */
/* Axis H will be either I or K, depending on EulRep. */
/* Frame S takes axes from initial static frame. */
/* If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then */
/* {a,b,c,ord} means Rz(c)Ry(b)Rx(a), where Rz(c)v */
/* rotates v around Z by c radians. */
#define EulFrmS 0
#define EulFrmR 1
#define EulFrm(ord) ((unsigned)(ord)&1)
#define EulRepNo 0
#define EulRepYes 1
#define EulRep(ord) (((unsigned)(ord)>>1)&1)
#define EulParEven 0
#define EulParOdd 1
#define EulPar(ord) (((unsigned)(ord)>>2)&1)
#define EulSafe "\000\001\002\000"
#define EulNext "\001\002\000\001"
#define EulAxI(ord) ((int)(EulSafe[(((unsigned)(ord)>>3)&3)]))
#define EulAxJ(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)==EulParOdd)]))
#define EulAxK(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)!=EulParOdd)]))
#define EulAxH(ord) ((EulRep(ord)==EulRepNo)?EulAxK(ord):EulAxI(ord))
/* EulGetOrd unpacks all useful information about order simultaneously. */
#define EulGetOrd(ord,i,j,k,h,n,s,f) {unsigned o=ord;f=o&1;o>>=1;s=o&1;o>>=1;\
n=o&1;o>>=1;i=EulSafe[o&3];j=EulNext[i+n];k=EulNext[i+1-n];h=s?k:i;}
/* EulOrd creates an order value between 0 and 23 from 4-tuple choices. */
#define EulOrd(i,p,r,f) (((((((i)<<1)+(p))<<1)+(r))<<1)+(f))
/* Static axes */
#define EulOrdXYZs EulOrd(X,EulParEven,EulRepNo,EulFrmS)
#define EulOrdXYXs EulOrd(X,EulParEven,EulRepYes,EulFrmS)
#define EulOrdXZYs EulOrd(X,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdXZXs EulOrd(X,EulParOdd,EulRepYes,EulFrmS)
#define EulOrdYZXs EulOrd(Y,EulParEven,EulRepNo,EulFrmS)
#define EulOrdYZYs EulOrd(Y,EulParEven,EulRepYes,EulFrmS)
#define EulOrdYXZs EulOrd(Y,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdYXYs EulOrd(Y,EulParOdd,EulRepYes,EulFrmS)
#define EulOrdZXYs EulOrd(Z,EulParEven,EulRepNo,EulFrmS)
#define EulOrdZXZs EulOrd(Z,EulParEven,EulRepYes,EulFrmS)
#define EulOrdZYXs EulOrd(Z,EulParOdd,EulRepNo,EulFrmS)
#define EulOrdZYZs EulOrd(Z,EulParOdd,EulRepYes,EulFrmS)
/* Rotating axes */
#define EulOrdZYXr EulOrd(X,EulParEven,EulRepNo,EulFrmR)
#define EulOrdXYXr EulOrd(X,EulParEven,EulRepYes,EulFrmR)
#define EulOrdYZXr EulOrd(X,EulParOdd,EulRepNo,EulFrmR)
#define EulOrdXZXr EulOrd(X,EulParOdd,EulRepYes,EulFrmR)
#define EulOrdXZYr EulOrd(Y,EulParEven,EulRepNo,EulFrmR)
#define EulOrdYZYr EulOrd(Y,EulParEven,EulRepYes,EulFrmR)
#define EulOrdZXYr EulOrd(Y,EulParOdd,EulRepNo,EulFrmR)
#define EulOrdYXYr EulOrd(Y,EulParOdd,EulRepYes,EulFrmR)
#define EulOrdYXZr EulOrd(Z,EulParEven,EulRepNo,EulFrmR)
#define EulOrdZXZr EulOrd(Z,EulParEven,EulRepYes,EulFrmR)
#define EulOrdXYZr EulOrd(Z,EulParOdd,EulRepNo,EulFrmR)
#define EulOrdZYZr EulOrd(Z,EulParOdd,EulRepYes,EulFrmR)
//EulerAngles Eul_(float ai, float aj, float ah, int order);
//Quat Eul_ToQuat(EulerAngles ea);
//void Eul_ToHMatrix(EulerAngles ea, HMatrix M);
//EulerAngles Eul_FromHMatrix(HMatrix M, int order);
//EulerAngles Eul_FromQuat(Quat q, int order);
#include <math.h>
#include <float.h>
#include "macro.h"
#include "glTypes.h"
static float identity[4][4] =
{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f},
};
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void* glMatrixCreate (void)
{
GLmatrix* m;
int x;
int y;
m = new GLmatrix;
for (x = 0; x < 4; x++) {
for (y = 0; y < 4; y++) {
m -> elements[x][y] = identity[x][y];
}
}
return (void*)m;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLmatrix glMatrixIdentity (void)
{
GLmatrix m;
int x;
int y;
for (x = 0; x < 4; x++) {
for (y = 0; y < 4; y++) {
M(m, x, y) = identity[x][y];
}
}
return m;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void glMatrixElementsSet (GLmatrix* m, float* in)
{
m -> elements[0][0] = in[0];
m -> elements[0][1] = in[1];
m -> elements[0][2] = in[2];
m -> elements[0][3] = in[3];
m -> elements[1][0] = in[4];
m -> elements[1][1] = in[5];
m -> elements[1][2] = in[6];
m -> elements[1][3] = in[7];
m -> elements[2][0] = in[8];
m -> elements[2][1] = in[9];
m -> elements[2][2] = in[10];
m -> elements[2][3] = in[11];
m -> elements[3][0] = in[12];
m -> elements[3][1] = in[13];
m -> elements[3][2] = in[14];
m -> elements[3][3] = in[15];
}
/*---------------------------------------------------------------------------
A matrix multiplication (dot product) of two 4x4 matrices.
---------------------------------------------------------------------------*/
GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b)
{
GLmatrix result;
M(result, 0,0) = M(a, 0,0) * M(b, 0, 0) + M(a, 1,0) * M(b, 0, 1) + M(a, 2,0) * M(b, 0, 2);
M(result, 1,0) = M(a, 0,0) * M(b, 1, 0) + M(a, 1,0) * M(b, 1, 1) + M(a, 2,0) * M(b, 1, 2);
M(result, 2,0) = M(a, 0,0) * M(b, 2, 0) + M(a, 1,0) * M(b, 2, 1) + M(a, 2,0) * M(b, 2, 2);
M(result, 3,0) = M(a, 0,0) * M(b, 3, 0) + M(a, 1,0) * M(b, 3, 1) + M(a, 2,0) * M(b, 3, 2) + M(a, 3,0);
M(result, 0,1) = M(a, 0,1) * M(b, 0, 0) + M(a, 1,1) * M(b, 0, 1) + M(a, 2,1) * M(b, 0, 2);
M(result, 1,1) = M(a, 0,1) * M(b, 1, 0) + M(a, 1,1) * M(b, 1, 1) + M(a, 2,1) * M(b, 1, 2);
M(result, 2,1) = M(a, 0,1) * M(b, 2, 0) + M(a, 1,1) * M(b, 2, 1) + M(a, 2,1) * M(b, 2, 2);
M(result, 3,1) = M(a, 0,1) * M(b, 3, 0) + M(a, 1,1) * M(b, 3, 1) + M(a, 2,1) * M(b, 3, 2) + M(a, 3,1);
M(result, 0,2) = M(a, 0,2) * M(b, 0, 0) + M(a, 1,2) * M(b, 0, 1) + M(a, 2,2) * M(b, 0, 2);
M(result, 1,2) = M(a, 0,2) * M(b, 1, 0) + M(a, 1,2) * M(b, 1, 1) + M(a, 2,2) * M(b, 1, 2);
M(result, 2,2) = M(a, 0,2) * M(b, 2, 0) + M(a, 1,2) * M(b, 2, 1) + M(a, 2,2) * M(b, 2, 2);
M(result, 3,2) = M(a, 0,2) * M(b, 3, 0) + M(a, 1,2) * M(b, 3, 1) + M(a, 2,2) * M(b, 3, 2) + M(a, 3,2);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector glMatrixTransformPoint (GLmatrix m, GLvector in)
{
GLvector out;
out.x = M(m,0,0) * in.x + M(m,1,0) * in.y + M(m,2,0) * in.z + M(m,3,0);
out.y = M(m,0,1) * in.x + M(m,1,1) * in.y + M(m,2,1) * in.z + M(m,3,1);
out.z = M(m,0,2) * in.x + M(m,1,2) * in.y + M(m,2,2) * in.z + M(m,3,2);
return out;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLmatrix glMatrixTranslate (GLmatrix m, GLvector in)
{
GLvector old;
old.x = M(m,3,0);
old.y = M(m,3,1);
old.z = M(m,3,2);
M(m, 3, 0) = 0.0f;
M(m, 3, 1) = 0.0f;
M(m, 3, 2) = 0.0f;
in = glMatrixTransformPoint (m, in);
M(m, 3, 0) = old.x;
M(m, 3, 1) = old.y;
M(m, 3, 2) = old.z;
M(m,3,0) += in.x;
M(m,3,1) += in.y;
M(m,3,2) += in.z;
return m;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, float z)
{
GLmatrix r;
float length;
float s, c, t;
GLvector in;
theta *= DEGREES_TO_RADIANS;
r = glMatrixIdentity ();
length = (float)sqrt (x * x + y * y + z * z);
if (length < 0.00001f)
return m;
x /= length;
y /= length;
z /= length;
s = (float)sin (theta);
c = (float)cos (theta);
t = 1.0f - c;
in.x = in.y = in.z = 1.0f;
M(r, 0,0) = t*x*x + c;
M(r, 1,0) = t*x*y - s*z;
M(r, 2,0) = t*x*z + s*y;
M(r, 3,0) = 0;
M(r, 0,1) = t*x*y + s*z;
M(r, 1,1) = t*y*y + c;
M(r, 2,1) = t*y*z - s*x;
M(r, 3,1) = 0;
M(r, 0,2) = t*x*z - s*y;
M(r, 1,2) = t*y*z + s*x;
M(r, 2,2) = t*z*z + c;
M(r, 3,2) = 0;
m = glMatrixMultiply (m, r);
return m;
}
/* Convert matrix to Euler angles (in radians). */
GLvector glMatrixToEuler (GLmatrix mat, int order)
{
GLvector ea;
int i,j,k,h,n,s,f;
EulGetOrd (order,i,j,k,h,n,s,f);
if (s==EulRepYes) {
float sy = (float)sqrt(mat.elements[i][j]*mat.elements[i][j] + mat.elements[i][k]*mat.elements[i][k]);
if (sy > 16 * FLT_EPSILON) {
ea.x = (float)atan2(mat.elements[i][j], mat.elements[i][k]);
ea.y = (float)atan2(sy, mat.elements[i][i]);
ea.z = (float)atan2(mat.elements[j][i], -mat.elements[k][i]);
} else {
ea.x = (float)atan2(-mat.elements[j][k], mat.elements[j][j]);
ea.y = (float)atan2(sy, mat.elements[i][i]);
ea.z = 0;
}
} else {
float cy = (float)sqrt(mat.elements[i][i]*mat.elements[i][i] + mat.elements[j][i]*mat.elements[j][i]);
if (cy > 16*FLT_EPSILON) {
ea.x = (float)atan2(mat.elements[k][j], mat.elements[k][k]);
ea.y = (float)atan2(-mat.elements[k][i], cy);
ea.z = (float)atan2(mat.elements[j][i], mat.elements[i][i]);
} else {
ea.x = (float)atan2(-mat.elements[j][k], mat.elements[j][j]);
ea.y = (float)atan2(-mat.elements[k][i], cy);
ea.z = 0;
}
}
if (n==EulParOdd) {
ea.x = -ea.x;
ea.y = - ea.y;
ea.z = -ea.z;
}
if (f==EulFrmR) {
float t = ea.x;
ea.x = ea.z;
ea.z = t;
}
//ea.w = order;
return (ea);
}

78
glQuat.cpp Normal file
View File

@ -0,0 +1,78 @@
/*-----------------------------------------------------------------------------
glQuat.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
Functions for dealing with Quaternions
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <float.h>
#include <math.h>
#include <gl\gl.h>
#include "math.h"
#include "glTypes.h"
enum QuatPart {X, Y, Z, W};
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLquat glQuat (float x, float y, float z, float w)
{
GLquat result;
result.x = x;
result.y = y;
result.z = z;
result.w = w;
return result;
}
/* Convert quaternion to Euler angles (in radians). */
/*
EulerAngles Eul_FromQuat(Quat q, int order)
{
HMatrix M;
double Nq = q.x*q.x+q.y*q.y+q.z*q.z+q.w*q.w;
double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
double xs = q.x*s, ys = q.y*s, zs = q.z*s;
double wx = q.w*xs, wy = q.w*ys, wz = q.w*zs;
double xx = q.x*xs, xy = q.x*ys, xz = q.x*zs;
double yy = q.y*ys, yz = q.y*zs, zz = q.z*zs;
M[X][X] = 1.0 - (yy + zz); M[X][Y] = xy - wz; M[X][Z] = xz + wy;
M[Y][X] = xy + wz; M[Y][Y] = 1.0 - (xx + zz); M[Y][Z] = yz - wx;
M[Z][X] = xz - wy; M[Z][Y] = yz + wx; M[Z][Z] = 1.0 - (xx + yy);
M[W][X]=M[W][Y]=M[W][Z]=M[X][W]=M[Y][W]=M[Z][W]=0.0; M[W][W]=1.0;
return (Eul_FromHMatrix(M, order));
}
*/
GLvector glQuatToEuler (GLquat q, int order)
{
GLmatrix M;
float Nq = q.x*q.x+q.y*q.y+q.z*q.z+q.w*q.w;
float s = (Nq > 0.0f) ? (2.0f / Nq) : 0.0f;
float xs = q.x*s, ys = q.y*s, zs = q.z*s;
float wx = q.w*xs, wy = q.w*ys, wz = q.w*zs;
float xx = q.x*xs, xy = q.x*ys, xz = q.x*zs;
float yy = q.y*ys, yz = q.y*zs, zz = q.z*zs;
M.elements[X][X] = 1.0f - (yy + zz); M.elements[X][Y] = xy - wz; M.elements[X][Z] = xz + wy;
M.elements[Y][X] = xy + wz; M.elements[Y][Y] = 1.0f - (xx + zz); M.elements[Y][Z] = yz - wx;
M.elements[Z][X] = xz - wy; M.elements[Z][Y] = yz + wx; M.elements[Z][Z] = 1.0f - (xx + yy);
M.elements[W][X] = M.elements[W][Y] =
M.elements[W][Z] = M.elements[X][W] =
M.elements[Y][W] = M.elements[Z][W] = 0.0f;
M.elements[W][W] = 1.0f;
return (glMatrixToEuler(M, order));
}

401
glRgba.cpp Normal file
View File

@ -0,0 +1,401 @@
/*-----------------------------------------------------------------------------
glRgba.cpp
2009 Shamus Young
-------------------------------------------------------------------------------
Functions for dealing with RGBA color values.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#include <gl\gl.h>
#include <math.h>
#include "math.h"
#include "glTypes.h"
#include "macro.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaFromHsl (float h, float sl, float l)
{
float v;
float r,g,b;
r = l; // default to gray
g = l;
b = l;
v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl);
if (v > 0) {
float m;
float sv;
int sextant;
float fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m ) / v;
h *= 6.0f;
sextant = (int)h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant) {
case 0:
r = v; g = mid1; b = m;
break;
case 1:
r = mid2; g = v; b = m;
break;
case 2:
r = m; g = v; b = mid1;
break;
case 3:
r = m; g = mid2; b = v;
break;
case 4:
r = mid1; g = m; b = v;
break;
case 5:
r = v; g = m; b = mid2;
break;
}
}
return glRgba (r, g, b);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta)
{
GLrgba result;
result.red = MathInterpolate (c1.red, c2.red, delta);
result.green = MathInterpolate (c1.green, c2.green, delta);
result.blue = MathInterpolate (c1.blue, c2.blue, delta);
result.alpha = MathInterpolate (c1.alpha, c2.alpha, delta);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaAdd (GLrgba c1, GLrgba c2)
{
GLrgba result;
result.red = c1.red + c2.red;
result.green = c1.green + c2.green;
result.blue = c1.blue + c2.blue;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2)
{
GLrgba result;
result.red = c1.red - c2.red;
result.green = c1.green - c2.green;
result.blue = c1.blue - c2.blue;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2)
{
GLrgba result;
result.red = c1.red * c2.red;
result.green = c1.green * c2.green;
result.blue = c1.blue * c2.blue;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgbaScale (GLrgba c, float scale)
{
c.red *= scale;
c.green *= scale;
c.blue *= scale;
return c;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (char* string)
{
long color;
char buffer[10];
char* pound;
GLrgba result;
strncmp (buffer, string, 10);
if (pound = strchr (buffer, '#'))
pound[0] = ' ';
if (sscanf (string, "%x", &color) != 1)
return glRgba (0.0f);
result.red = (float)GetBValue (color) / 255.0f;
result.green = (float)GetGValue (color) / 255.0f;
result.blue = (float)GetRValue (color) / 255.0f;
result.alpha = 1.0f;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (int red, int green, int blue)
{
GLrgba result;
result.red = (float)red / 255.0f;
result.green = (float)green / 255.0f;
result.blue = (float)blue / 255.0f;
result.alpha = 1.0f;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (float red, float green, float blue)
{
GLrgba result;
result.red = red;
result.green = green;
result.blue = blue;
result.alpha = 1.0f;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (float red, float green, float blue, float alpha)
{
GLrgba result;
result.red = red;
result.green = green;
result.blue = blue;
result.alpha = alpha;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (long c)
{
GLrgba result;
result.red = (float)GetRValue (c) / 255.0f;
result.green = (float)GetGValue (c) / 255.0f;
result.blue = (float)GetBValue (c) / 255.0f;
result.alpha = 1.0f;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLrgba glRgba (float luminance)
{
GLrgba result;
result.red = luminance;
result.green = luminance;
result.blue = luminance;
result.alpha = 1.0f;
return result;
}
/*-----------------------------------------------------------------------------
Takes the given index and returns a "random" color unique for that index.
512 Unique values: #0 and #512 will be the same, as will #1 and #513, etc
Useful for visual debugging in some situations.
-----------------------------------------------------------------------------*/
GLrgba glRgbaUnique (int i)
{
GLrgba c;
c.alpha = 1.0f;
c.red = 0.4f + ((i & 1) ? 0.2f : 0.0f) + ((i & 8) ? 0.3f : 0.0f) - ((i & 64) ? 0.3f : 0.0f);
c.green = 0.4f + ((i & 2) ? 0.2f : 0.0f) + ((i & 32) ? 0.3f : 0.0f) - ((i & 128) ? 0.3f : 0.0f);
c.blue = 0.4f + ((i & 4) ? 0.2f : 0.0f) + ((i & 16) ? 0.3f : 0.0f) - ((i & 256) ? 0.3f : 0.0f);
return c;
}
/*-----------------------------------------------------------------------------
+ operator
-----------------------------------------------------------------------------*/
GLrgba GLrgba::operator+ (const GLrgba& c)
{
return glRgba (red + c.red, green + c.green, blue + c.blue, alpha);
}
GLrgba GLrgba::operator+ (const float& c)
{
return glRgba (red + c, green + c, blue + c, alpha);
}
void GLrgba::operator+= (const GLrgba& c)
{
red += c.red;
green += c.green;
blue += c.blue;
}
void GLrgba::operator+= (const float& c)
{
red += c;
green += c;
blue += c;
}
/*-----------------------------------------------------------------------------
- operator
-----------------------------------------------------------------------------*/
GLrgba GLrgba::operator- (const GLrgba& c)
{
return glRgba (red - c.red, green - c.green, blue - c.blue);
}
GLrgba GLrgba::operator- (const float& c)
{
return glRgba (red - c, green - c, blue - c, alpha);
}
void GLrgba::operator-= (const GLrgba& c)
{
red -= c.red;
green -= c.green;
blue -= c.blue;
}
void GLrgba::operator-= (const float& c)
{
red -= c;
green -= c;
blue -= c;
}
/*-----------------------------------------------------------------------------
* operator
-----------------------------------------------------------------------------*/
GLrgba GLrgba::operator* (const GLrgba& c)
{
return glRgba (red * c.red, green * c.green, blue * c.blue);
}
GLrgba GLrgba::operator* (const float& c)
{
return glRgba (red * c, green * c, blue * c, alpha);
}
void GLrgba::operator*= (const GLrgba& c)
{
red *= c.red;
green *= c.green;
blue *= c.blue;
}
void GLrgba::operator*= (const float& c)
{
red *= c;
green *= c;
blue *= c;
}
/*-----------------------------------------------------------------------------
/ operator
-----------------------------------------------------------------------------*/
GLrgba GLrgba::operator/ (const GLrgba& c)
{
return glRgba (red / c.red, green / c.green, blue / c.blue);
}
GLrgba GLrgba::operator/ (const float& c)
{
return glRgba (red / c, green / c, blue / c, alpha);
}
void GLrgba::operator/= (const GLrgba& c)
{
red /= c.red;
green /= c.green;
blue /= c.blue;
}
void GLrgba::operator/= (const float& c)
{
red /= c;
green /= c;
blue /= c;
}
bool GLrgba::operator== (const GLrgba& c)
{
return (red == c.red && green == c.green && blue == c.blue);
}

209
glTypes.h Normal file
View File

@ -0,0 +1,209 @@
#ifndef glTYPES
#define glTYPES
#define GL_CLAMP_TO_EDGE 0x812F
#define OPERATORS(type) \
type operator+ (const type& c); \
type operator+ (const float& c);\
void operator+= (const type& c);\
void operator+= (const float& c);\
type operator- (const type& c);\
type operator- (const float& c);\
void operator-= (const type& c);\
void operator-= (const float& c);\
type operator* (const type& c);\
type operator* (const float& c);\
void operator*= (const type& c);\
void operator*= (const float& c);\
type operator/ (const type& c);\
type operator/ (const float& c);\
void operator/= (const type& c);\
void operator/= (const float& c);\
bool operator== (const type& c);
#define JOINT_MAX_CHILDREN 8
struct GLquat
{
float x;
float y;
float z;
float w;
};
struct GLvector
{
float x;
float y;
float z;
OPERATORS(GLvector);
};
typedef GLvector GLvector3;
struct GLvector2
{
float x;
float y;
OPERATORS(GLvector2);
};
struct GLrgba
{
float red;
float green;
float blue;
float alpha;
OPERATORS(GLrgba);
};
struct GLmatrix
{
float elements[4][4];
};
struct GLbbox
{
GLvector3 min;
GLvector3 max;
};
struct GLvertex
{
GLvector3 position;
GLvector2 uv;
GLrgba color;
int bone;
};
struct GLrect
{
float left;
float top;
float right;
float bottom;
};
struct GLtriangle
{
int v1;
int v2;
int v3;
int normal1;
int normal2;
int normal3;
};
/*
class GLmodel
{
public:
unsigned vertex_count;
unsigned triangle_count;
unsigned normal_count;
GLvertex* vertex;
GLvector* normal;
GLtriangle* triangle;
void TriangleRender (unsigned n);
GLtriangle* TriangleAdd (unsigned v1, int unsigned, int unsigned);
GLtriangle* TriangleAdd (GLtriangle c);
void NormalAdd (GLvector n);
void VertexAdd (GLvertex v);
GLmodel ();
~GLmodel ();
void Render ();
GLbbox BBox ();
private:
GLbbox m_bbox;
};
struct GLkeyframe
{
float time;
GLvector offset;
GLvector rotation;
};
struct GLsegment
{
int index;
GLvector rotation;
GLvector offset;
GLkeyframe keyframes[255];
int frame_count;
};
class GLanimate
{
public:
GLanimate ();
void KeyframeAdd (int joint, float time, GLquat q);
void TimeSet (float time);
void PositionSet (float pos);
GLvector Rotation (int);
GLvector Offset (int);
private:
GLsegment* m_segments;
int m_segment_count;
float m_length;
};
*/
GLbbox glBboxClear (void);
GLbbox glBboxContainPoint (GLbbox box, GLvector point);
bool glBboxTestPoint (GLbbox box, GLvector point);
GLrgba glRgba (char* string);
GLrgba glRgba (float red, float green, float blue);
GLrgba glRgba (float luminance);
GLrgba glRgba (float red, float green, float blue, float alpha);
GLrgba glRgba (long c);
GLrgba glRgba (int red, int green, int blue);
GLrgba glRgbaAdd (GLrgba c1, GLrgba c2);
GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2);
GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta);
GLrgba glRgbaScale (GLrgba c, float scale);
GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2);
GLrgba glRgbaUnique (int i);
GLrgba glRgbaFromHsl (float h, float s, float l);
GLmatrix glMatrixIdentity (void);
void glMatrixElementsSet (GLmatrix* m, float* in);
GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b);
GLvector glMatrixTransformPoint (GLmatrix m, GLvector in);
GLmatrix glMatrixTranslate (GLmatrix m, GLvector in);
GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, float z);
GLvector glMatrixToEuler (GLmatrix mat, int order);
GLquat glQuat (float x, float y, float z, float w);
GLvector glQuatToEuler (GLquat q, int order);
GLvector glVector (float x, float y, float z);
GLvector glVectorCrossProduct (GLvector v1, GLvector v2);
float glVectorDotProduct (GLvector v1, GLvector v2);
void glVectorGl (GLvector v);
GLvector glVectorInterpolate (GLvector v1, GLvector v2, float scalar);
float glVectorLength (GLvector v);
GLvector glVectorNormalize (GLvector v);
GLvector glVectorReflect (GLvector3 ray, GLvector3 normal);
GLvector2 glVector (float x, float y);
GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2);
GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2);
GLvector2 glVectorNormalize (GLvector2 v);
GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar);
GLvector2 glVectorSinCos (float angle);
float glVectorLength (GLvector2 v);
#endif
#ifndef NULL
#define NULL 0
#endif

223
glVector2.cpp Normal file
View File

@ -0,0 +1,223 @@
/*-----------------------------------------------------------------------------
Vector2.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
Functions for dealing with 2d (usually texture mapping) values.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <float.h>
#include <math.h>
#include <gl\gl.h>
#include "glTypes.h"
#include "math.h"
#include "macro.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVectorNormalize (GLvector2 v)
{
float length;
length = glVectorLength (v);
if (length < 0.000001f)
return v;
return v * (1.0f / length);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float glVectorLength (GLvector2 v)
{
return (float)sqrt (v.x * v.x + v.y * v.y);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVectorSinCos (float a)
{
GLvector2 val;
a *= DEGREES_TO_RADIANS;
val.x = sinf (a);
val.y = cosf (a);
return val;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVector (float x, float y)
{
GLvector2 val;
val.x = x;
val.y = y;
return val;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2)
{
GLvector2 result;
result.x = val1.x + val2.x;
result.y = val1.y + val2.y;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar)
{
GLvector2 result;
result.x = MathInterpolate (v1.x, v2.x, scalar);
result.y = MathInterpolate (v1.y, v2.y, scalar);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2)
{
GLvector2 result;
result.x = val1.x - val2.x;
result.y = val1.y - val2.y;
return result;
}
/*-----------------------------------------------------------------------------
+
-----------------------------------------------------------------------------*/
GLvector2 GLvector2::operator+ (const GLvector2& c)
{
return glVector (x + c.x, y + c.y);
}
GLvector2 GLvector2::operator+ (const float& c)
{
return glVector (x + c, y + c);
}
void GLvector2::operator+= (const GLvector2& c)
{
x += c.x;
y += c.y;
}
void GLvector2::operator+= (const float& c)
{
x += c;
y += c;
}
GLvector2 GLvector2::operator- (const GLvector2& c)
{
return glVector (x - c.x, y - c.y);
}
GLvector2 GLvector2::operator- (const float& c)
{
return glVector (x - c, y - c);
}
void GLvector2::operator-= (const GLvector2& c)
{
x -= c.x;
y -= c.y;
}
void GLvector2::operator-= (const float& c)
{
x -= c;
y -= c;
}
GLvector2 GLvector2::operator* (const GLvector2& c)
{
return glVector (x * c.x, y * c.y);
}
GLvector2 GLvector2::operator* (const float& c)
{
return glVector (x * c, y * c);
}
void GLvector2::operator*= (const GLvector2& c)
{
x *= c.x;
y *= c.y;
}
void GLvector2::operator*= (const float& c)
{
x *= c;
y *= c;
}
GLvector2 GLvector2::operator/ (const GLvector2& c)
{
return glVector (x / c.x, y / c.y);
}
GLvector2 GLvector2::operator/ (const float& c)
{
return glVector (x / c, y / c);
}
void GLvector2::operator/= (const GLvector2& c)
{
x /= c.x;
y /= c.y;
}
void GLvector2::operator/= (const float& c)
{
x /= c;
y /= c;
}
bool GLvector2::operator== (const GLvector2& c)
{
if (x == c.x && y == c.y)
return true;
return false;
}

257
glVector3.cpp Normal file
View File

@ -0,0 +1,257 @@
/*-----------------------------------------------------------------------------
glVector3.cpp
2006 Shamus Young
-------------------------------------------------------------------------------
Functions for dealing with 3d vectors.
-----------------------------------------------------------------------------*/
#include <windows.h>
#include <float.h>
#include <math.h>
#include <gl\gl.h>
#include "macro.h"
#include "math.h"
#include "glTypes.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector glVectorReflect (GLvector3 ray, GLvector3 normal)
{
float dot;
dot = glVectorDotProduct (ray, normal);
//return glVectorSubtract (ray, glVectorScale (normal, 2.0f * dot));
return ray - (normal * (2.0f * dot));
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVector (float x, float y, float z)
{
GLvector3 result;
result.x = x;
result.y = y;
result.z = z;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVectorInterpolate (GLvector3 v1, GLvector3 v2, float scalar)
{
GLvector3 result;
result.x = MathInterpolate (v1.x, v2.x, scalar);
result.y = MathInterpolate (v1.y, v2.y, scalar);
result.z = MathInterpolate (v1.z, v2.z, scalar);
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float glVectorLength (GLvector3 v)
{
return (float)sqrt (v.x * v.x + v.y * v.y + v.z * v.z);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float glVectorDotProduct (GLvector3 v1, GLvector3 v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVectorCrossProduct (GLvector3 v1, GLvector3 v2)
{
GLvector3 result;
result.x = v1.y * v2.z - v2.y * v1.z;
result.y = v1.z * v2.x - v2.z * v1.x;
result.z = v1.x * v2.y - v2.x * v1.y;
return result;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVectorInvert (GLvector3 v)
{
v.x *= -v.x;
v.y *= -v.y;
v.z *= -v.z;
return v;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVectorScale (GLvector3 v, float scale)
{
v.x *= scale;
v.y *= scale;
v.z *= scale;
return v;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
GLvector3 glVectorNormalize (GLvector3 v)
{
float length;
length = glVectorLength (v);
if (length < 0.000001f)
return v;
return glVectorScale (v, 1.0f / length);
}
/*-----------------------------------------------------------------------------
+
-----------------------------------------------------------------------------*/
GLvector GLvector::operator+ (const GLvector& c)
{
return glVector (x + c.x, y + c.y, z + c.z);
}
GLvector GLvector::operator+ (const float& c)
{
return glVector (x + c, y + c, z + c);
}
void GLvector::operator+= (const GLvector& c)
{
x += c.x;
y += c.y;
z += c.z;
}
void GLvector::operator+= (const float& c)
{
x += c;
y += c;
z += c;
}
GLvector GLvector::operator- (const GLvector& c)
{
return glVector (x - c.x, y - c.y, z - c.z);
}
GLvector GLvector::operator- (const float& c)
{
return glVector (x - c, y - c, z - c);
}
void GLvector::operator-= (const GLvector& c)
{
x -= c.x;
y -= c.y;
z -= c.z;
}
void GLvector::operator-= (const float& c)
{
x -= c;
y -= c;
z -= c;
}
GLvector GLvector::operator* (const GLvector& c)
{
return glVector (x * c.x, y * c.y, z * c.z);
}
GLvector GLvector::operator* (const float& c)
{
return glVector (x * c, y * c, z * c);
}
void GLvector::operator*= (const GLvector& c)
{
x *= c.x;
y *= c.y;
z *= c.z;
}
void GLvector::operator*= (const float& c)
{
x *= c;
y *= c;
z *= c;
}
GLvector GLvector::operator/ (const GLvector& c)
{
return glVector (x / c.x, y / c.y, z / c.z);
}
GLvector GLvector::operator/ (const float& c)
{
return glVector (x / c, y / c, z / c);
}
void GLvector::operator/= (const GLvector& c)
{
x /= c.x;
y /= c.y;
z /= c.z;
}
void GLvector::operator/= (const float& c)
{
x /= c;
y /= c;
z /= c;
}
bool GLvector::operator== (const GLvector& c)
{
if (x == c.x && y == c.y && z == c.z)
return true;
return false;
}