Showing preview only (246K chars total). Download the full file or copy to clipboard to get everything.
Repository: skeeto/pixelcity
Branch: master
Commit: 8e0a90a34ce2
Files: 41
Total size: 235.0 KB
Directory structure:
gitextract_5n_ku7qe/
├── Building.cpp
├── Building.h
├── Camera.cpp
├── Camera.h
├── Car.cpp
├── Car.h
├── Deco.cpp
├── Deco.h
├── Entity.cpp
├── Entity.h
├── Ini.cpp
├── Ini.h
├── Light.cpp
├── Light.h
├── Macro.h
├── Math.cpp
├── Math.h
├── Mesh.cpp
├── Mesh.h
├── PixelCity.dsp
├── Random.cpp
├── Random.h
├── Render.cpp
├── Render.h
├── Sky.cpp
├── Sky.h
├── Texture.cpp
├── Texture.h
├── Visible.cpp
├── Visible.h
├── Win.cpp
├── Win.h
├── World.cpp
├── World.h
├── glBbox.cpp
├── glMatrix.cpp
├── glQuat.cpp
├── glRgba.cpp
├── glTypes.h
├── glVector2.cpp
└── glVector3.cpp
================================================
FILE CONTENTS
================================================
================================================
FILE: Building.cpp
================================================
/*-----------------------------------------------------------------------------
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"
#include "win.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);
_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;
cube c;
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]);
c.index_list.push_back(base_index + i);
}
_mesh->CubeAdd (c);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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;
cube c;
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]);
c.index_list.push_back(base_index + i);
}
_mesh_flat->CubeAdd (c);
}
/*-----------------------------------------------------------------------------
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;
fan f;
int i;
GLvector center;
for (i = 0; i < 5; i++)
f.index_list.push_back(_mesh_flat->VertexCount () + i);
f.index_list.push_back(f.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 (f);
}
/*-----------------------------------------------------------------------------
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;
quad_strip qs;
int column;
int mid;
int odd;
GLvertex v;
bool blank;
bool last_blank;
qs.index_list.reserve(100);
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;
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);
qs.index_list.push_back(_mesh->VertexCount () - 1);
v.position.y = (float)(start_y + height);
v.uv.y = (float)(start_y + height) / SEGMENTS_PER_TEXTURE;;
_mesh->VertexAdd (v);
qs.index_list.push_back(_mesh->VertexCount () - 1);
}
//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 (qs);
return v.uv.x;
}
/*-----------------------------------------------------------------------------
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;
//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;
quad_strip qs;
float u, v1, v2;
float cap_height;
float ledge;
for(int i=0; i<10; i++)
qs.index_list.push_back(i);
//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 (qs);
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;
quad_strip qs;
fan f;
int points;
int skip_interval;
int skip_counter;
int skip_delta;
int i;
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);
}
qs.index_list.reserve(points);
//Add the outer walls
for (i = 0; i < points; i++)
qs.index_list.push_back(i);
_mesh->QuadStripAdd (qs);
_mesh_flat->QuadStripAdd (qs);
//add the fan to cap the top of the buildings
f.index_list.push_back(points);
for (i = 0; i < points / 2; i++)
f.index_list.push_back(points - (1 + i * 2));
p.position.x = _center.x;
p.position.z = _center.z;
_mesh_flat->VertexAdd (p);
_mesh_flat->FanAdd (f);
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;
int narrowing_interval;
int tiers;
float ledge;
float uv_start;
bool blank_corners;
bool roof_spike;
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 (4) + 1;
//How the windows are grouped
grouping = RandomVal (3) + 2;
//if the corners of the building have no windows
blank_corners = RandomVal (4) > 0;
//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 (4);
//How often (in tiers) does the building get narrorwer?
narrowing_interval = 1 + RandomVal (10);
//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;
tiers = 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;
tiers++;
if ((tiers % narrowing_interval) == 0) {
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 ();
}
================================================
FILE: Building.h
================================================
#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 ();
};
================================================
FILE: Camera.cpp
================================================
/*-----------------------------------------------------------------------------
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 GLvector movement;
static bool cam_auto;
static float tracker;
static unsigned last_update;
static int camera_behavior;
static unsigned last_move;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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, 50); //limit to 1/20th 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 / 300.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)
{
angle.y -= delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraPitch (float delta)
{
angle.x -= delta;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraPan (float delta)
{
float move_x, move_y;
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;
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 CameraVertical (float val)
{
movement.y += val;
last_move = GetTickCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraLateral (float val)
{
movement.x += val;
last_move = GetTickCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraMedial (float val)
{
movement.z += val;
last_move = GetTickCount ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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)
{
CameraPan (movement.x);
CameraForward (movement.z);
position.y += movement.y / 10.0f;
if (GetTickCount () - last_move > 1000)
movement *= 0.9f;
else
movement *= 0.99f;
if (SCREENSAVER)
cam_auto = true;
if (cam_auto)
do_auto_cam ();
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);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CameraTerm (void)
{
//just store our most recent position in the ini
IniVectorSet ("CameraAngle", angle);
IniVectorSet ("CameraPosition", position);
}
================================================
FILE: Camera.h
================================================
#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 CameraPan (float delta_x);
void CameraPitch (float delta_y);
void CameraYaw (float delta_x);
void CameraVertical (float val);
void CameraLateral (float val);
void CameraMedial (float val);
================================================
FILE: Car.cpp
================================================
/*-----------------------------------------------------------------------------
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"
#include "win.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;
float top;
if (!m_ready)
return;
if (!Visible (m_drive_position))
return;
if (m_front) {
glColor3f (1, 1, 0.8f);
top = CAR_SIZE;
} else {
glColor3f (0.5, 0.2f, 0);
top = 0.0f;
}
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, top, pos.z - angles[angle].y);
glTexCoord2f (0, 1);
glVertex3f (pos.x + angles[angle].x, top, pos.z + angles[angle].y);
glEnd ();
}
================================================
FILE: Car.h
================================================
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 ();
================================================
FILE: Deco.cpp
================================================
/*-----------------------------------------------------------------------------
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 ()
{
delete _mesh;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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;
fan f;
for(int i=0; i<6; i++)
f.index_list.push_back(i);
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 (f);
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;
quad_strip qs;
float u1, u2, v1, v2;
float top;
float height, length;
GLvector2 center2d;
GLvector to;
GLvector out;
int logo_index;
qs.index_list.push_back(0);
qs.index_list.push_back(1);
qs.index_list.push_back(3);
qs.index_list.push_back(2);
_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 (qs);
_texture = TextureId (TEXTURE_LOGOS);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CDeco::CreateLightStrip (float x, float z, float width, float depth, float height, GLrgba color)
{
GLvertex p;
quad_strip qs1;
float u, v;
qs1.index_list.push_back(0);
qs1.index_list.push_back(1);
qs1.index_list.push_back(3);
qs1.index_list.push_back(2);
_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));
}
_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);
_mesh->QuadStripAdd (qs1);
_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;
quad_strip qs;
_color = color;
_center = glVector (0.0f, 0.0f, 0.0f);
qs.index_list.reserve(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);
qs.index_list.push_back(index++);
//Top point
p.position.y += height;p.uv = glVector (u, v1);
_mesh->VertexAdd (p);
qs.index_list.push_back(index++);
}
_mesh->QuadStripAdd (qs);
_texture = TextureId (TEXTURE_TRIM);
_mesh->Compile ();
}
================================================
FILE: Deco.h
================================================
#ifndef ENTITY
#include "entity.h"
#endif
class CDeco : CEntity
{
GLrgba _color;
class CMesh* _mesh;
int _type;
unsigned _texture;
bool _use_alpha;
public:
CDeco ();
~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 ();
};
================================================
FILE: Entity.cpp
================================================
/*-----------------------------------------------------------------------------
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"
#include "win.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 compile_end;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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_end = GetTickCount ();
}
compile_count++;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
bool EntityReady ()
{
return compiled;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
float EntityProgress ()
{
return (float)compile_count / (GRID_SIZE * GRID_SIZE);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityUpdate ()
{
unsigned stop_time;
if (!TextureReady ()) {
sorted = false;
return;
}
if (!sorted) {
qsort (entity_list, entity_count, sizeof (struct entity), do_compare);
sorted = true;
}
//We want to do several cells at once. Enough to get things done, but
//not so many that the program is unresponsive.
if (LOADING_SCREEN) { //If we're using a loading screen, we want to build as fast as possible
stop_time = GetTickCount () + 100;
while (!compiled && GetTickCount () < stop_time)
do_compile ();
} else //Take it slow
do_compile ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void EntityRender ()
{
int polymode[2];
bool wireframe;
int x, y;
int elapsed;
//Draw all textured objects
glGetIntegerv (GL_POLYGON_MODE, &polymode[0]);
wireframe = polymode[0] != GL_FILL;
if (RenderFlat ())
glDisable (GL_TEXTURE_2D);
//If we're not using a loading screen, make the wireframe fade out via fog
if (!LOADING_SCREEN && wireframe) {
elapsed = 6000 - WorldSceneElapsed ();
if (elapsed >= 0 && elapsed <= 6000)
RenderFogFX ((float)elapsed / 6000.0f);
else
return;
}
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)
{
}
================================================
FILE: Entity.h
================================================
#ifndef TYPES
#include "glTypes.h"
#endif
#ifndef ENTITY
#define ENTITY
class CEntity
{
private:
protected:
GLvector _center;
public:
CEntity (void);
virtual ~CEntity () {};
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; }
GLvector Center () { return _center; }
};
void EntityClear ();
int EntityCount (void);
float EntityProgress ();
bool EntityReady ();
void EntityRender (void);
void EntityUpdate (void);
int EntityPolyCount (void);
#endif
================================================
FILE: Ini.cpp
================================================
/*-----------------------------------------------------------------------------
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;
}
================================================
FILE: Ini.h
================================================
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);
================================================
FILE: Light.cpp
================================================
/*-----------------------------------------------------------------------------
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 "entity.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 (!EntityReady ())
return;
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;
_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;
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);
}
================================================
FILE: Light.h
================================================
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 ();
================================================
FILE: Macro.h
================================================
#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;}
================================================
FILE: Math.cpp
================================================
/*-----------------------------------------------------------------------------
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.0f);
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;
}
================================================
FILE: Math.h
================================================
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);
================================================
FILE: Mesh.cpp
================================================
/*-----------------------------------------------------------------------------
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 <vector>
#include "glTypes.h"
#include "Mesh.h"
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CMesh::CMesh ()
{
_list = glGenLists(1);
_compiled = false;
_polycount = 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
CMesh::~CMesh ()
{
glDeleteLists (_list, 1);
_vertex.clear ();
_fan.clear ();
_quad_strip.clear ();
_cube.clear ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::VertexAdd (const GLvertex& v)
{
_vertex.push_back(v);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::CubeAdd (const cube& c)
{
_cube.push_back(c);
_polycount += 5;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::QuadStripAdd (const quad_strip& qs)
{
_quad_strip.push_back(qs);
_polycount += (qs.index_list.size() - 2) / 2;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::FanAdd (const fan& f)
{
_fan.push_back(f);
_polycount += f.index_list.size() - 2;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::Render ()
{
std::vector<quad_strip>::iterator qsi;
std::vector<cube>::iterator ci;
std::vector<fan>::iterator fi;
std::vector<int>::iterator n;
if (_compiled) {
glCallList (_list);
return;
}
for (qsi = _quad_strip.begin(); qsi < _quad_strip.end(); ++qsi) {
glBegin (GL_QUAD_STRIP);
for (n = qsi->index_list.begin(); n < qsi->index_list.end(); ++n) {
glTexCoord2fv (&_vertex[*n].uv.x);
glVertex3fv (&_vertex[*n].position.x);
}
glEnd ();
}
for (ci = _cube.begin(); ci < _cube.end(); ++ci) {
glBegin (GL_QUAD_STRIP);
for (n = ci->index_list.begin(); n < ci->index_list.end(); ++n) {
glTexCoord2fv (&_vertex[*n].uv.x);
glVertex3fv (&_vertex[*n].position.x);
}
glEnd ();
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[ci->index_list[7]].uv.x);
glVertex3fv (&_vertex[ci->index_list[7]].position.x);
glVertex3fv (&_vertex[ci->index_list[5]].position.x);
glVertex3fv (&_vertex[ci->index_list[3]].position.x);
glVertex3fv (&_vertex[ci->index_list[1]].position.x);
glEnd ();
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[ci->index_list[6]].uv.x);
glVertex3fv (&_vertex[ci->index_list[0]].position.x);
glVertex3fv (&_vertex[ci->index_list[2]].position.x);
glVertex3fv (&_vertex[ci->index_list[4]].position.x);
glVertex3fv (&_vertex[ci->index_list[6]].position.x);
glEnd ();
}
for (fi = _fan.begin(); fi < _fan.end(); ++fi) {
glBegin (GL_TRIANGLE_FAN);
for (n = fi->index_list.begin(); n < fi->index_list.end(); ++n) {
glTexCoord2fv (&_vertex[*n].uv.x);
glVertex3fv (&_vertex[*n].position.x);
}
glEnd ();
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CMesh::Compile ()
{
glNewList (_list, GL_COMPILE);
Render ();
glEndList();
_compiled = true;
}
================================================
FILE: Mesh.h
================================================
#include <vector>
struct cube
{
std::vector<int> index_list; // probably always .size() == 10...
};
struct quad_strip
{
std::vector<int> index_list;
};
struct fan
{
std::vector<int> index_list;
};
class CMesh
{
public:
CMesh ();
~CMesh ();
unsigned _list;
int _polycount;
std::vector<GLvertex> _vertex;
std::vector<cube> _cube;
std::vector<quad_strip> _quad_strip;
std::vector<fan> _fan;
bool _compiled;
void VertexAdd (const GLvertex& v);
int VertexCount () { return _vertex.size(); }
int PolyCount () { return _polycount; }
void CubeAdd (const cube& c);
void QuadStripAdd (const quad_strip& qs);
void FanAdd (const fan& f);
void Render ();
void Compile ();
};
================================================
FILE: PixelCity.dsp
================================================
# 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 Ignore_Export_Lib 0
# 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 /profile /debug /machine:I386
!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
================================================
FILE: Random.cpp
================================================
/*-----------------------------------------------------------------------------
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;
}
================================================
FILE: Random.h
================================================
#define COIN_FLIP (RandomVal (2) == 0)
unsigned long RandomVal (int range);
unsigned long RandomVal (void);
void RandomInit (unsigned long seed);
================================================
FILE: Render.cpp
================================================
/*-----------------------------------------------------------------------------
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 <time.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_COUNT,
EFFECT_DEBUG,
EFFECT_DEBUG_OVERBLOOM,
};
#else
enum
{
EFFECT_NONE,
EFFECT_BLOOM,
EFFECT_COUNT,
EFFECT_DEBUG_OVERBLOOM,
EFFECT_DEBUG,
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 unsigned next_fps;
static unsigned current_fps;
static unsigned frames;
static bool show_wireframe;
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) {
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 ())
return;
//Now change projection modes so we can render full-screen effects
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);
glDisable (GL_FOG);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//Render full-screen effects
glBlendFunc (GL_ONE, GL_ONE);
glEnable (GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDepthMask (false);
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 * 2;
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.01f;
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
if (LOADING_SCREEN) {
if (fade > 0.0f) {
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);
RenderPrint (1, "%s v%d.%d.%03d", APP_TITLE, VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
}
}
glPopMatrix ();
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
int RenderMaxTextureSize ()
{
int mts;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mts);
mts = MIN (mts, render_width);
return MIN (mts, render_height);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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);
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (0, render_width, render_height, 0, 0.1f, 2048);
glDisable(GL_DEPTH_TEST);
glDepthMask (false);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity();
glTranslatef(0, 0, -1.0f);
glDisable (GL_BLEND);
glDisable (GL_FOG);
glDisable (GL_TEXTURE_2D);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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 + 2, text);
text = strtok (NULL, "\n");
line++;
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void do_fps ()
{
LIMIT_INTERVAL (1000);
current_fps = frames;
frames = 0;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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);
}
//If the program is running for the first time, set the defaults.
if (!IniInt ("SetDefaults")) {
IniIntSet ("SetDefaults", 1);
IniIntSet ("Effect", EFFECT_BLOOM);
IniIntSet ("ShowFog", 1);
}
//load in our settings
letterbox = IniInt ("Letterbox") != 0;
show_wireframe = IniInt ("Wireframe") != 0;
show_fps = IniInt ("ShowFPS") != 0;
show_fog = IniInt ("ShowFog") != 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;
}
/*-----------------------------------------------------------------------------
This is used to set a gradient fog that goes from camera to some portion of
the normal fog distance. This is used for making wireframe outlines and
flat surfaces fade out after rebuild. Looks cool.
-----------------------------------------------------------------------------*/
void RenderFogFX (float scalar)
{
if (scalar >= 1.0f) {
glDisable (GL_FOG);
return;
}
glFogf (GL_FOG_START, 0.0f);
glFogf (GL_FOG_END, fog_distance * 2.0f * scalar);
glEnable (GL_FOG);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void RenderUpdate (void)
{
GLvector pos;
GLvector angle;
GLrgba color;
int elapsed;
frames++;
do_fps ();
glViewport (0, 0, WinWidth (), WinHeight ());
glDepthMask (true);
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (letterbox)
glViewport (0, letterbox_offset, render_width, render_height);
if (LOADING_SCREEN && TextureReady () && !EntityReady ()) {
do_effects (EFFECT_NONE);
SwapBuffers (hDC);
return;
}
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glShadeModel(GL_SMOOTH);
glFogi (GL_FOG_MODE, GL_LINEAR);
glDepthFunc(GL_LEQUAL);
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 (1.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.
glDisable (GL_FOG);
SkyRender ();
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);
}
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 ();
if (!LOADING_SCREEN) {
elapsed = 3000 - WorldSceneElapsed ();
if (elapsed >= 0 && elapsed <= 3000) {
RenderFogFX ((float)elapsed / 3000.0f);
glDisable (GL_TEXTURE_2D);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE);
EntityRender ();
}
}
if (EntityReady ())
LightRender ();
CarRender ();
if (show_wireframe) {
glDisable (GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
EntityRender ();
}
do_effects (effect);
//Framerate tracker
if (show_fps)
RenderPrint (1, "FPS=%d : Entities=%d : polys=%d", current_fps, EntityCount () + LightCount () + CarCount (), EntityPolyCount () + LightCount () + CarCount ());
//Show the help overlay
if (show_help)
do_help ();
SwapBuffers (hDC);
}
================================================
FILE: Render.h
================================================
bool RenderBloom ();
void RenderEffectCycle ();
bool RenderFlat ();
void RenderFlatToggle ();
float RenderFogDistance ();
bool RenderFog ();
void RenderFogToggle ();
void RenderFogFX (float scalar);
void RenderFPSToggle ();
void RenderInit ();
void RenderLetterboxToggle ();
int RenderMaxTextureSize ();
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, ...);
void RenderPrint (int line, const char *fmt, ...);
================================================
FILE: Sky.cpp
================================================
/*-----------------------------------------------------------------------------
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 (!TextureReady ())
return;
glDepthMask (false);
glPushAttrib (GL_POLYGON_BIT | GL_FOG_BIT);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glDisable (GL_CULL_FACE);
glDisable (GL_FOG);
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);
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();
sky = this;
}
================================================
FILE: Sky.h
================================================
#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 ();
================================================
FILE: Texture.cpp
================================================
/*-----------------------------------------------------------------------------
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, and is badly 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"
#include "win.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",
" LLC"
};
class CTexture
{
public:
int _my_id;
unsigned _glid;
int _desired_size;
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 ();
void DrawSky ();
void DrawHeadlight ();
};
static CTexture* head;
static bool textures_done;
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;
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);
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;
_desired_size = size;
_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--;
}
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CTexture::DrawSky ()
{
GLrgba color;
float grey;
float scale, inv_scale;
int i, x, y;
int width, height;
int offset;
int width_adjust;
int height_adjust;
color = WorldBloomColor ();
grey = (color.red + color.green + color.blue) / 3.0f;
//desaturate, slightly dim
color = (color + glRgba (grey) * 2.0f) / 15.0f;
glDisable (GL_BLEND);
glBegin (GL_QUAD_STRIP);
glColor3f (0,0,0);
glVertex2i (0, _half);
glVertex2i (_size, _half);
glColor3fv (&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));
//Draw the clouds
for (i = _size - 30; i > 5; i -= 2) {
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) {
inv_scale = 1.0f - (scale);
if (scale < 0.4f)
color = WorldBloomColor () * 0.1f;
else
color = glRgba (0.0f);
color.alpha = 0.2f;
glColor4fv (&color.red);
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 ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void CTexture::DrawHeadlight ()
{
float radius;
int i, x, y;
GLvector2 pos;
//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));
}
/*-----------------------------------------------------------------------------
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;
int max_size;
float radius;
GLvector2 pos;
bool use_framebuffer;
unsigned char* bits;
unsigned start;
int lapsed;
start = GetTickCount ();
//Since we make textures by drawing into the viewport, we can't make them bigger
//than the current view.
_size = _desired_size;
max_size = RenderMaxTextureSize ();
while (_size > max_size)
_size /= 2;
glBindTexture(GL_TEXTURE_2D, _glid);
//Set up the texture
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);
glDisable (GL_FOG);
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_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, 1, 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:
DrawHeadlight ();
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]);
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_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:
DrawSky ();
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)
{
textures_done = false;
build_time = 0;
for (CTexture* t = head; t; t = t->_next)
t->Clear ();
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_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);
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;
}
================================================
FILE: Texture.h
================================================
#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_LIGHT,
TEXTURE_SOFT_CIRCLE,
TEXTURE_SKY,
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);
================================================
FILE: Visible.cpp
================================================
/*-----------------------------------------------------------------------------
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"
#include "win.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;
//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 >= GRID_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 >= GRID_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;
}
}
}
================================================
FILE: Visible.h
================================================
#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);
================================================
FILE: Win.cpp
================================================
/*-----------------------------------------------------------------------------
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, "winmm.lib")
#pragma comment (lib, "glu32.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;
LONG WINAPI ScreenSaverProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static 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);
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static 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);
}
/*-----------------------------------------------------------------------------
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;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppQuit ()
{
quit = true;
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppUpdate ()
{
CameraUpdate ();
EntityUpdate ();
WorldUpdate ();
TextureUpdate ();
VisibleUpdate ();
CarUpdate ();
RenderUpdate ();
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
void AppInit (void)
{
RandomInit (time (NULL));
CameraInit ();
RenderInit ();
TextureInit ();
WorldInit ();
}
/*-----------------------------------------------------------------------------
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
BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { return FALSE; }
BOOL WINAPI RegisterDialogClasses(HANDLE hInst) { return TRUE; }
#endif
LONG WINAPI ScreenSaverProc(HWND hwnd_in,UINT message,WPARAM wparam,LPARAM lparam)
{
RECT r;
int key;
float delta_x, delta_y;
POINT p;
// Handles screen saver messages
switch(message)
{
case WM_SIZE:
width = LOWORD(lparam); // width of client area
height = HIWORD(lparam); // height of client area
if (wparam == SIZE_MAXIMIZED) {
IniIntSet ("WindowMaximized", 1);
} else {
IniIntSet ("WindowWidth", width);
IniIntSet ("WindowHeight", height);
IniIntSet ("WindowMaximized", 0);
}
RenderResize ();
break;
case WM_KEYDOWN:
key = (int) wparam;
if (key == 'R')
WorldReset ();
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 (!SCREENSAVER) {
//Dev mode keys
if (key == 'C')
CameraAutoToggle ();
if (key == 'B')
CameraNextBehavior ();
if (key == VK_F5)
CameraReset ();
if (key == VK_UP)
CameraMedial (1.0f);
if (key == VK_DOWN)
CameraMedial (-1.0f);
if (key == VK_LEFT)
CameraLateral (1.0f);
if (key == VK_RIGHT)
CameraLateral (-1.0f);
if (key == VK_PRIOR)
CameraVertical (1.0f);
if (key == VK_NEXT)
CameraVertical (-1.0f);
if (key == VK_F5)
CameraReset ();
return 0;
} else
break;
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;
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_CREATE:
hwnd = hwnd_in;
if (SCREENSAVER)
AppInit ();
SetTimer (hwnd, 1, 7, NULL);
return 0;
case WM_TIMER:
AppUpdate ();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
#if SCREENSAVER
return DefScreenSaverProc(hwnd_in,message,wparam,lparam);
#else
return DefWindowProc (hwnd_in,message,wparam,lparam);
#endif
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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)ScreenSaverProc;
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;
}
================================================
FILE: Win.h
================================================
//Versioning info
#define APP_TITLE "PixelCity"
#define APP "pixelcity"
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_REVISION 10
//Best to disable screensaver mode when working on the program.
#define SCREENSAVER 0
//Do we hide scene building behing a loading screen or show it?
#define LOADING_SCREEN 1
//Controls the density of cars.
#define CARS 500
//The "dead zone" along the edge of the world, with super-low detail.
#define WORLD_EDGE 200
//How often to rebuild the city
#define RESET_INTERVAL (SCREENSAVER ? 120000 : 999999)//milliseconds
//How long the screen fade takes when transitioning to a new city
#define FADE_TIME (SCREENSAVER ? 1500 : 1) //milliseconds
//Debug ground texture that shows traffic lanes
#define SHOW_DEBUG_GROUND 0
//Controls the ammount of space available for buildings.
//Other code is wrtten assuming this will be a power of two.
#define WORLD_SIZE 1024
#define WORLD_HALF (WORLD_SIZE / 2)
//Bitflags used to track how world space is being used.
#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
//Random SATURATED color
#define RANDOM_COLOR (glRgbaFromHsl ((float)RandomVal (255)/255,1.0f, 0.75f))
//Used in orienting roads and cars
enum
{
NORTH,
EAST,
SOUTH,
WEST
};
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);
================================================
FILE: World.cpp
================================================
/*-----------------------------------------------------------------------------
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))
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include <math.h>
#include <time.h>
#include <vector>
#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 "win.h"
#include "world.h"
using namespace std;
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 int logo_index;
static unsigned start_time;
static int scene_begin;
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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);
}
}
/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
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 > 800) {
if (COIN_FLIP) {
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;
}
/*
//Rectangular plots are a good place for Blocky style buildsing to sprawl blockily.
if (p.width > p.depth * 2 || p.depth > p.width * 2 && area > 800) {
height = 20 + RandomVal (10);
blocky_count++;
skyscrapers++;
new CBuilding (BUILDING_BLOCKY, p.x, p.z, height, p.width, p.depth, seed, color);
return;
}
*/
//tower_count = -1;
//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;
//Re-init Random to make the same city each time. Helpful when running tests.
RandomInit (6);
reset_needed = false;
broadway_done = false;
skyscrapers = 0;
logo_index = 0;
scene_begin = 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 (25) + 25) {
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 (25) + 25) {
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;
}
/*-----------------------------------------------------------------------------
------------------------------------------------
gitextract_5n_ku7qe/ ├── Building.cpp ├── Building.h ├── Camera.cpp ├── Camera.h ├── Car.cpp ├── Car.h ├── Deco.cpp ├── Deco.h ├── Entity.cpp ├── Entity.h ├── Ini.cpp ├── Ini.h ├── Light.cpp ├── Light.h ├── Macro.h ├── Math.cpp ├── Math.h ├── Mesh.cpp ├── Mesh.h ├── PixelCity.dsp ├── Random.cpp ├── Random.h ├── Render.cpp ├── Render.h ├── Sky.cpp ├── Sky.h ├── Texture.cpp ├── Texture.h ├── Visible.cpp ├── Visible.h ├── Win.cpp ├── Win.h ├── World.cpp ├── World.h ├── glBbox.cpp ├── glMatrix.cpp ├── glQuat.cpp ├── glRgba.cpp ├── glTypes.h ├── glVector2.cpp └── glVector3.cpp
SYMBOL INDEX (231 symbols across 27 files)
FILE: Building.h
function class (line 13) | class CBuilding : public CEntity
FILE: Camera.cpp
function GLvector (line 65) | static GLvector flycam_position (unsigned t)
function do_auto_cam (line 105) | static void do_auto_cam ()
function CameraAutoToggle (line 181) | void CameraAutoToggle ()
function CameraNextBehavior (line 192) | void CameraNextBehavior ()
function CameraYaw (line 204) | void CameraYaw (float delta)
function CameraPitch (line 215) | void CameraPitch (float delta)
function CameraPan (line 226) | void CameraPan (float delta)
function CameraForward (line 242) | void CameraForward (float delta)
function CameraVertical (line 258) | void CameraVertical (float val)
function CameraLateral (line 270) | void CameraLateral (float val)
function CameraMedial (line 282) | void CameraMedial (float val)
function GLvector (line 294) | GLvector CameraPosition (void)
function CameraReset (line 307) | void CameraReset ()
function CameraPositionSet (line 323) | void CameraPositionSet (GLvector new_pos)
function GLvector (line 334) | GLvector CameraAngle (void)
function CameraAngleSet (line 347) | void CameraAngleSet (GLvector new_angle)
function CameraInit (line 359) | void CameraInit (void)
function CameraUpdate (line 371) | void CameraUpdate (void)
function CameraTerm (line 396) | void CameraTerm (void)
FILE: Car.cpp
function CarCount (line 60) | int CarCount ()
function CarClear (line 71) | void CarClear ()
function CarRender (line 87) | void CarRender ()
function CarUpdate (line 115) | void CarUpdate ()
FILE: Car.h
function class (line 1) | class CCar
FILE: Deco.h
function class (line 5) | class CDeco : CEntity
FILE: Entity.cpp
type entity (line 31) | struct entity
type cell (line 37) | struct cell
function do_compare (line 61) | static int do_compare (const void *arg1, const void *arg2 )
function add (line 83) | void add (CEntity* b)
function do_compile (line 97) | static void do_compile ()
function EntityReady (line 188) | bool EntityReady ()
function EntityProgress (line 199) | float EntityProgress ()
function EntityUpdate (line 211) | void EntityUpdate ()
function EntityRender (line 239) | void EntityRender ()
function EntityClear (line 300) | void EntityClear ()
function EntityCount (line 338) | int EntityCount ()
function EntityInit (line 349) | void EntityInit (void)
function EntityPolyCount (line 358) | int EntityPolyCount (void)
FILE: Entity.h
function class (line 9) | class CEntity
FILE: Ini.cpp
function IniInt (line 33) | int IniInt (char* entry)
function IniIntSet (line 47) | void IniIntSet (char* entry, int val)
function IniFloat (line 61) | float IniFloat (char* entry)
function IniFloatSet (line 76) | void IniFloatSet (char* entry, float val)
function IniStringSet (line 103) | void IniStringSet (char* entry, char* val)
function IniVectorSet (line 115) | void IniVectorSet (char* entry, GLvector v)
function GLvector (line 127) | GLvector IniVector (char* entry)
FILE: Light.cpp
function LightClear (line 45) | void LightClear ()
function LightCount (line 63) | int LightCount ()
function LightRender (line 75) | void LightRender ()
FILE: Light.h
function class (line 1) | class CLight
FILE: Math.cpp
function MathAngle (line 22) | float MathAngle (float angle)
function MathAngle (line 37) | float MathAngle (float x1, float y1, float x2, float y2)
function MathDistance2 (line 71) | float MathDistance2 (float x1, float y1, float x2, float y2)
function MathDistance (line 88) | float MathDistance (float x1, float y1, float x2, float y2)
function MathAngleDifference (line 104) | float MathAngleDifference (float a1, float a2)
function MathInterpolate (line 123) | float MathInterpolate (float n1, float n2, float delta)
function MathSmoothStep (line 134) | float MathSmoothStep (float val, float a, float b)
function MathAverage (line 149) | float MathAverage (float n1, float n2)
function MathScalarCurve (line 162) | float MathScalarCurve (float val)
FILE: Mesh.h
type cube (line 4) | struct cube
type quad_strip (line 9) | struct quad_strip
type fan (line 14) | struct fan
function class (line 19) | class CMesh
FILE: Random.cpp
function RandomVal (line 37) | unsigned long RandomVal (void)
function RandomVal (line 68) | unsigned long RandomVal (int range)
function RandomInit (line 79) | void RandomInit (unsigned long seed)
FILE: Render.cpp
type glFont (line 82) | struct glFont
function do_progress (line 147) | static void do_progress (float center_x, float center_y, float radius, f...
function do_effects (line 205) | static void do_effects (int type)
function RenderMaxTextureSize (line 363) | int RenderMaxTextureSize ()
function RenderPrint (line 378) | void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt,...
function RenderPrint (line 402) | void RenderPrint (int line, const char *fmt, ...)
function do_help (line 443) | void static do_help (void)
function do_fps (line 468) | void do_fps ()
function RenderResize (line 482) | void RenderResize (void)
function RenderTerm (line 511) | void RenderTerm (void)
function RenderInit (line 525) | void RenderInit (void)
function RenderFPSToggle (line 583) | void RenderFPSToggle ()
function RenderFog (line 595) | bool RenderFog ()
function RenderFogToggle (line 606) | void RenderFogToggle ()
function RenderLetterboxToggle (line 618) | void RenderLetterboxToggle ()
function RenderWireframeToggle (line 632) | void RenderWireframeToggle ()
function RenderWireframe (line 644) | bool RenderWireframe ()
function RenderEffectCycle (line 656) | void RenderEffectCycle ()
function RenderBloom (line 668) | bool RenderBloom ()
function RenderFlat (line 680) | bool RenderFlat ()
function RenderFlatToggle (line 691) | void RenderFlatToggle ()
function RenderHelpToggle (line 703) | void RenderHelpToggle ()
function RenderFogDistance (line 714) | float RenderFogDistance ()
function RenderFogFX (line 729) | void RenderFogFX (float scalar)
function RenderUpdate (line 746) | void RenderUpdate (void)
FILE: Sky.cpp
function SkyRender (line 37) | void SkyRender ()
function SkyClear (line 49) | void SkyClear ()
FILE: Sky.h
type sky_point (line 4) | struct sky_point
function class (line 10) | class CSky
FILE: Texture.cpp
class CTexture (line 129) | class CTexture
method Clear (line 145) | void Clear () { _ready = false; }
function drawrect_simple (line 163) | void drawrect_simple (int left, int top, int right, int bottom, GLrgba c...
function drawrect_simple (line 181) | void drawrect_simple (int left, int top, int right, int bottom, GLrgba c...
function drawrect (line 202) | void drawrect (int left, int top, int right, int bottom, GLrgba color)
function window (line 288) | static void window (int x, int y, int size, int id, GLrgba color)
function do_bloom (line 341) | static void do_bloom (CTexture* t)
function TextureId (line 757) | unsigned TextureId (int id)
function TextureRandomBuilding (line 772) | unsigned TextureRandomBuilding (int index)
function TextureReset (line 784) | void TextureReset (void)
function TextureReady (line 801) | bool TextureReady ()
function TextureUpdate (line 812) | void TextureUpdate (void)
function TextureTerm (line 841) | void TextureTerm (void)
function TextureInit (line 858) | void TextureInit (void)
FILE: Visible.cpp
function Visible (line 35) | bool Visible (GLvector pos)
function Visible (line 47) | bool Visible (int x, int z)
function VisibleUpdate (line 60) | void VisibleUpdate (void)
FILE: Win.cpp
function CenterCursor (line 65) | static void CenterCursor ()
function MoveCursor (line 85) | static void MoveCursor (int x, int y)
function WinPopup (line 105) | void WinPopup (char* message, ...)
function WinWidth (line 123) | int WinWidth (void)
function WinMousePosition (line 134) | void WinMousePosition (int* x, int* y)
function WinHeight (line 147) | int WinHeight (void)
function WinTerm (line 158) | void WinTerm (void)
function HWND (line 169) | HWND WinHwnd (void)
function AppQuit (line 181) | void AppQuit ()
function AppUpdate (line 192) | void AppUpdate ()
function AppInit (line 209) | void AppInit (void)
function AppTerm (line 225) | void AppTerm (void)
function WinMain (line 241) | int PASCAL WinMain (HINSTANCE instance_in, HINSTANCE previous_instance,
function BOOL (line 269) | BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT msg, WPARAM wPar...
function BOOL (line 270) | BOOL WINAPI RegisterDialogClasses(HANDLE hInst) { return TRUE; }
function LONG (line 274) | LONG WINAPI ScreenSaverProc(HWND hwnd_in,UINT message,WPARAM wparam,LPAR...
function WinInit (line 436) | bool WinInit (void)
FILE: World.cpp
type plot (line 45) | struct plot
type HSL (line 61) | struct HSL
class CStreet (line 68) | class CStreet
function GLrgba (line 124) | static GLrgba get_light_color (float sat, float lum)
function claim (line 138) | static void claim (int x, int y, int width, int depth, int val)
function claimed (line 155) | static bool claimed (int x, int y, int width, int depth)
function build_road (line 174) | static void build_road (int x1, int y1, int width, int depth)
function plot (line 218) | static plot find_plot (int x, int z)
function plot (line 248) | static plot make_plot (int x, int z, int width, int depth)
function do_building (line 260) | void do_building (plot p)
function build_light_strip (line 343) | static int build_light_strip (int x1, int z1, int direction)
function do_reset (line 400) | static void do_reset (void)
function GLrgba (line 572) | GLrgba WorldLightColor (unsigned index)
function WorldCell (line 584) | char WorldCell (int x, int y)
function GLrgba (line 595) | GLrgba WorldBloomColor ()
function WorldLogoIndex (line 606) | int WorldLogoIndex ()
function GLbbox (line 617) | GLbbox WorldHotZone ()
function WorldTerm (line 628) | void WorldTerm (void)
function WorldReset (line 638) | void WorldReset (void)
function WorldRender (line 656) | void WorldRender ()
function WorldFade (line 684) | float WorldFade (void)
function WorldSceneBegin (line 695) | int WorldSceneBegin ()
function WorldSceneElapsed (line 708) | int WorldSceneElapsed ()
function WorldUpdate (line 726) | void WorldUpdate (void)
function WorldInit (line 778) | void WorldInit (void)
FILE: glBbox.cpp
function glBboxTestPoint (line 25) | bool glBboxTestPoint (GLbbox box, GLvector point)
function GLbbox (line 42) | GLbbox glBboxContainPoint (GLbbox box, GLvector point)
function GLbbox (line 59) | GLbbox glBboxClear (void)
FILE: glMatrix.cpp
function GLmatrix (line 117) | GLmatrix glMatrixIdentity (void)
function glMatrixElementsSet (line 137) | void glMatrixElementsSet (GLmatrix* m, float* in)
function GLmatrix (line 166) | GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b)
function GLvector (line 193) | GLvector glMatrixTransformPoint (GLmatrix m, GLvector in)
function GLmatrix (line 209) | GLmatrix glMatrixTranslate (GLmatrix m, GLvector in)
function GLmatrix (line 235) | GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, floa...
function GLvector (line 277) | GLvector glMatrixToEuler (GLmatrix mat, int order)
FILE: glQuat.cpp
type QuatPart (line 21) | enum QuatPart {X, Y, Z, W}
function GLquat (line 27) | GLquat glQuat (float x, float y, float z, float w)
function GLvector (line 60) | GLvector glQuatToEuler (GLquat q, int order)
FILE: glRgba.cpp
function GLrgba (line 26) | GLrgba glRgbaFromHsl (float h, float sl, float l)
function GLrgba (line 80) | GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta)
function GLrgba (line 97) | GLrgba glRgbaAdd (GLrgba c1, GLrgba c2)
function GLrgba (line 113) | GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2)
function GLrgba (line 130) | GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2)
function GLrgba (line 146) | GLrgba glRgbaScale (GLrgba c, float scale)
function GLrgba (line 160) | GLrgba glRgba (char* string)
function GLrgba (line 185) | GLrgba glRgba (int red, int green, int blue)
function GLrgba (line 202) | GLrgba glRgba (float red, float green, float blue)
function GLrgba (line 219) | GLrgba glRgba (float red, float green, float blue, float alpha)
function GLrgba (line 237) | GLrgba glRgba (long c)
function GLrgba (line 254) | GLrgba glRgba (float luminance)
function GLrgba (line 273) | GLrgba glRgbaUnique (int i)
function GLrgba (line 290) | GLrgba GLrgba::operator+ (const GLrgba& c)
function GLrgba (line 295) | GLrgba GLrgba::operator+ (const float& c)
function GLrgba (line 318) | GLrgba GLrgba::operator- (const GLrgba& c)
function GLrgba (line 323) | GLrgba GLrgba::operator- (const float& c)
function GLrgba (line 346) | GLrgba GLrgba::operator* (const GLrgba& c)
function GLrgba (line 351) | GLrgba GLrgba::operator* (const float& c)
function GLrgba (line 374) | GLrgba GLrgba::operator/ (const GLrgba& c)
function GLrgba (line 379) | GLrgba GLrgba::operator/ (const float& c)
FILE: glTypes.h
type GLquat (line 28) | struct GLquat
type GLvector (line 36) | struct GLvector
type GLvector (line 44) | typedef GLvector GLvector3;
type GLvector2 (line 46) | struct GLvector2
type GLrgba (line 53) | struct GLrgba
type GLmatrix (line 62) | struct GLmatrix
type GLbbox (line 67) | struct GLbbox
type GLvertex (line 73) | struct GLvertex
type GLrect (line 81) | struct GLrect
type GLtriangle (line 89) | struct GLtriangle
FILE: glVector2.cpp
function GLvector2 (line 26) | GLvector2 glVectorNormalize (GLvector2 v)
function glVectorLength (line 42) | float glVectorLength (GLvector2 v)
function GLvector2 (line 53) | GLvector2 glVectorSinCos (float a)
function GLvector2 (line 69) | GLvector2 glVector (float x, float y)
function GLvector2 (line 84) | GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2)
function GLvector2 (line 100) | GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar)
function GLvector2 (line 115) | GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2)
function GLvector2 (line 130) | GLvector2 GLvector2::operator+ (const GLvector2& c)
function GLvector2 (line 135) | GLvector2 GLvector2::operator+ (const float& c)
function GLvector2 (line 152) | GLvector2 GLvector2::operator- (const GLvector2& c)
function GLvector2 (line 157) | GLvector2 GLvector2::operator- (const float& c)
function GLvector2 (line 174) | GLvector2 GLvector2::operator* (const GLvector2& c)
function GLvector2 (line 179) | GLvector2 GLvector2::operator* (const float& c)
function GLvector2 (line 196) | GLvector2 GLvector2::operator/ (const GLvector2& c)
function GLvector2 (line 201) | GLvector2 GLvector2::operator/ (const float& c)
FILE: glVector3.cpp
function GLvector (line 26) | GLvector glVectorReflect (GLvector3 ray, GLvector3 normal)
function GLvector3 (line 41) | GLvector3 glVector (float x, float y, float z)
function GLvector3 (line 57) | GLvector3 glVectorInterpolate (GLvector3 v1, GLvector3 v2, float scalar)
function glVectorLength (line 73) | float glVectorLength (GLvector3 v)
function glVectorDotProduct (line 84) | float glVectorDotProduct (GLvector3 v1, GLvector3 v2)
function GLvector3 (line 95) | GLvector3 glVectorCrossProduct (GLvector3 v1, GLvector3 v2)
function GLvector3 (line 111) | GLvector3 glVectorInvert (GLvector3 v)
function GLvector3 (line 125) | GLvector3 glVectorScale (GLvector3 v, float scale)
function GLvector3 (line 139) | GLvector3 glVectorNormalize (GLvector3 v)
function GLvector (line 155) | GLvector GLvector::operator+ (const GLvector& c)
function GLvector (line 160) | GLvector GLvector::operator+ (const float& c)
function GLvector (line 179) | GLvector GLvector::operator- (const GLvector& c)
function GLvector (line 184) | GLvector GLvector::operator- (const float& c)
function GLvector (line 203) | GLvector GLvector::operator* (const GLvector& c)
function GLvector (line 208) | GLvector GLvector::operator* (const float& c)
function GLvector (line 227) | GLvector GLvector::operator/ (const GLvector& c)
function GLvector (line 232) | GLvector GLvector::operator/ (const float& c)
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (261K chars).
[
{
"path": "Building.cpp",
"chars": 28537,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Building.cpp\r\n\r\n 2009 Shamus Young"
},
{
"path": "Building.h",
"chars": 1893,
"preview": "#ifndef ENTITY\r\n#include \"entity.h\"\r\n#endif\r\n\r\nenum\r\n{\r\n BUILDING_SIMPLE,\r\n BUILDING_BLOCKY,\r\n BUILDING_MODERN,\r\n BU"
},
{
"path": "Camera.cpp",
"chars": 10874,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Camera.cpp\r\n\r\n 2009 Shamus Young\r\n"
},
{
"path": "Camera.h",
"chars": 754,
"preview": "#ifndef TYPES\r\n#include \"glTypes.h\"\r\n#endif\r\n\r\nGLvector CameraAngle (void);\r\nvoid CameraAngleSet (GLvector new_ang"
},
{
"path": "Car.cpp",
"chars": 8591,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Car.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n-"
},
{
"path": "Car.h",
"chars": 691,
"preview": "class CCar\r\n{\r\n GLvector m_position;\r\n GLvector m_drive_position;\r\n bool m_ready;\r\n bool "
},
{
"path": "Deco.cpp",
"chars": 8260,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Deco.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n"
},
{
"path": "Deco.h",
"chars": 810,
"preview": "#ifndef ENTITY\r\n#include \"entity.h\"\r\n#endif\r\n\r\nclass CDeco : CEntity\r\n{\r\n GLrgba _color;\r\n class CMesh* _mesh;"
},
{
"path": "Entity.cpp",
"chars": 10804,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Entity.cpp\r\n\r\n Copyright (c) 2005 "
},
{
"path": "Entity.h",
"chars": 844,
"preview": "#ifndef TYPES\r\n#include \"glTypes.h\"\r\n#endif\r\n\r\n#ifndef ENTITY\r\n\r\n#define ENTITY\r\n\r\nclass CEntity\r\n{\r\nprivate:\r\nprotected"
},
{
"path": "Ini.cpp",
"chars": 3403,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Ini.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n\r"
},
{
"path": "Ini.h",
"chars": 335,
"preview": "int IniInt (char* entry);\r\nvoid IniIntSet (char* entry, int val);\r\nfloat IniFloat (char* entry);\r\nvoid "
},
{
"path": "Light.cpp",
"chars": 4591,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Light.cpp\r\n\r\n 2006 Shamus Young\r\n\r"
},
{
"path": "Light.h",
"chars": 517,
"preview": "class CLight\r\n{\r\n GLvector _position;\r\n GLrgba _color;\r\n int _size;\r\n float _v"
},
{
"path": "Macro.h",
"chars": 974,
"preview": "#define LIMIT_INTERVAL(interval) { static unsigned next_update; if (next_update > GetTickCount ()) return; next_update "
},
{
"path": "Math.cpp",
"chars": 4560,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Math.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n"
},
{
"path": "Math.h",
"chars": 538,
"preview": "float MathAngle (float angle);\r\nfloat MathAngle (float x1, float y1, float x2, float y2);\r\nfloat MathAngleDifference (fl"
},
{
"path": "Mesh.cpp",
"chars": 4644,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Mesh.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n"
},
{
"path": "Mesh.h",
"chars": 929,
"preview": "\r\n#include <vector>\r\n\r\nstruct cube\r\n{\r\n std::vector<int> index_list; // probably always .size() == 10...\r\n};\r\n\r\nstruc"
},
{
"path": "PixelCity.dsp",
"chars": 6504,
"preview": "# Microsoft Developer Studio Project File - Name=\"PixelCity\" - Package Owner=<4>\r\n# Microsoft Developer Studio Generated"
},
{
"path": "Random.cpp",
"chars": 3020,
"preview": "/*-----------------------------------------------------------------------------\r\n\t\t\t\t\t\t\t\t\t r a n d o m\r\n--"
},
{
"path": "Random.h",
"chars": 165,
"preview": "#define COIN_FLIP (RandomVal (2) == 0)\r\n\r\nunsigned long RandomVal (int range);\r\nunsigned long RandomVal (void);\r\nvoi"
},
{
"path": "Render.cpp",
"chars": 24202,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Render.cpp\r\n\r\n 2009 Shamus Young\r\n"
},
{
"path": "Render.h",
"chars": 634,
"preview": "bool RenderBloom ();\r\nvoid RenderEffectCycle ();\r\nbool RenderFlat ();\r\nvoid RenderFlatToggle ();\r\nfloat RenderFogDis"
},
{
"path": "Sky.cpp",
"chars": 3510,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Sky.cpp\r\n\r\n 2009 Shamus Young\r\n\r\n-"
},
{
"path": "Sky.h",
"chars": 437,
"preview": "#define SKY_GRID 21\r\n#define SKY_HALF (SKY_GRID / 2)\r\n\r\nstruct sky_point\r\n{\r\n GLrgba color;\r\n GLvecto"
},
{
"path": "Texture.cpp",
"chars": 26850,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Texture.cpp\r\n\r\n 2009 Shamus Young\r"
},
{
"path": "Texture.h",
"chars": 1340,
"preview": "#define SEGMENTS_PER_TEXTURE 64\r\n#define ONE_SEGMENT (1.0f / SEGMENTS_PER_TEXTURE)\r\n#define LANES_PER_TEXTURE"
},
{
"path": "Visible.cpp",
"chars": 4125,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Visible.cpp\r\n\r\n 2009 Shamus Young\r"
},
{
"path": "Visible.h",
"chars": 341,
"preview": "#define GRID_RESOLUTION 32\r\n#define GRID_CELL (GRID_RESOLUTION / 2)\r\n#define GRID_SIZE (WORLD_SIZE / G"
},
{
"path": "Win.cpp",
"chars": 11723,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Win.cpp\r\n\r\n 2006 Shamus Young\r\n\r\n-"
},
{
"path": "Win.h",
"chars": 1758,
"preview": "//Versioning info\r\n#define APP_TITLE \"PixelCity\"\r\n#define APP \"pixelcity\"\r\n#define VERSION_MAJ"
},
{
"path": "World.cpp",
"chars": 23228,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n World.cpp\r\n\r\n 2009 Shamus Young\r\n\r"
},
{
"path": "World.h",
"chars": 416,
"preview": "\r\nGLrgba WorldBloomColor ();\r\nchar WorldCell (int x, int y);\r\nGLrgba WorldLightColor (unsigned index);\r\nint "
},
{
"path": "glBbox.cpp",
"chars": 1953,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n glBbox.cpp\r\n\r\n 2006 Shamus Young\r\n"
},
{
"path": "glMatrix.cpp",
"chars": 10544,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n glMatrix.cpp\r\n\r\n 2006 Shamus Young"
},
{
"path": "glQuat.cpp",
"chars": 2536,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n glQuat.cpp\r\n\r\n 2006 Shamus Young\r\n"
},
{
"path": "glRgba.cpp",
"chars": 9459,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n glRgba.cpp\r\n\r\n 2009 Shamus Young\r\n"
},
{
"path": "glTypes.h",
"chars": 5114,
"preview": "#ifndef glTYPES\r\n#define glTYPES\r\n\r\n#define GL_CLAMP_TO_EDGE 0x812F\r\n\r\n#define OPERATORS(type) \\\r\n type operator"
},
{
"path": "glVector2.cpp",
"chars": 4601,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n Vector2.cpp\r\n\r\n 2006 Shamus Young\r"
},
{
"path": "glVector3.cpp",
"chars": 5581,
"preview": "/*-----------------------------------------------------------------------------\r\n\r\n glVector3.cpp\r\n\r\n 2006 Shamus Youn"
}
]
About this extraction
This page contains the full source code of the skeeto/pixelcity GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (235.0 KB), approximately 63.0k tokens, and a symbol index with 231 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.