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 #include #include #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 #include #include #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 #include #include #include #include #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 #include #include #include #include #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 #include #include #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 #include #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 #include #include #include #include #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 #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 #include #include #include #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::iterator qsi; std::vector::iterator ci; std::vector::iterator fi; std::vector::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 struct cube { std::vector index_list; // probably always .size() == 10... }; struct quad_strip { std::vector index_list; }; struct fan { std::vector index_list; }; class CMesh { public: CMesh (); ~CMesh (); unsigned _list; int _polycount; std::vector _vertex; std::vector _cube; std::vector _quad_strip; std::vector _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 . 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 #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 #include #include #include #include #include #include #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 #include #include #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 #include #include #include #include #include #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 #include #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 #include #include #include #include #include #include #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 #include #include #include #include #include #include #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; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void WorldTerm (void) { } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void WorldReset (void) { //If we're already fading out, then this is the developer hammering on the //"rebuild" button. Let's hurry things up for the nice man... if (fade_state == FADE_OUT) do_reset (); //If reset is called but the world isn't ready, then don't bother fading out. //The program probably just started. fade_state = FADE_OUT; fade_start = GetTickCount (); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void WorldRender () { if (!SHOW_DEBUG_GROUND) return; //Render a single texture over the city that shows traffic lanes glDepthMask (false); glDisable (GL_CULL_FACE); glDisable (GL_BLEND); glEnable (GL_TEXTURE_2D); glColor3f (1,1,1); glBindTexture (GL_TEXTURE_2D, 0); glBegin (GL_QUADS); glTexCoord2f (0, 0); glVertex3f ( 0., 0, 0); glTexCoord2f (0, 1); glVertex3f ( 0, 0, 1024); glTexCoord2f (1, 1); glVertex3f ( 1024, 0, 1024); glTexCoord2f (1, 0); glVertex3f ( 1024, 0, 0); glEnd (); glDepthMask (true); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ float WorldFade (void) { return fade_current; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ int WorldSceneBegin () { return scene_begin; } /*----------------------------------------------------------------------------- How long since this current iteration of the city went on display, -----------------------------------------------------------------------------*/ int WorldSceneElapsed () { int elapsed; if (!EntityReady () || !WorldSceneBegin ()) elapsed = 1; else elapsed = GetTickCount () - (WorldSceneBegin ()); elapsed = MAX (elapsed, 1); return elapsed; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void WorldUpdate (void) { unsigned fade_delta; int now; now = GetTickCount (); if (reset_needed) { do_reset (); //Now we've faded out the scene, rebuild it } if (fade_state != FADE_IDLE) { if (fade_state == FADE_WAIT && TextureReady () && EntityReady ()) { fade_state = FADE_IN; fade_start = now; fade_current = 1.0f; } fade_delta = now - fade_start; //See if we're done fading in or out if (fade_delta > FADE_TIME && fade_state != FADE_WAIT) { if (fade_state == FADE_OUT) { reset_needed = true; fade_state = FADE_WAIT; fade_current = 1.0f; } else { fade_state = FADE_IDLE; fade_current = 0.0f; start_time = time (NULL); scene_begin = GetTickCount (); } } else { fade_current = (float)fade_delta / FADE_TIME; if (fade_state == FADE_IN) fade_current = 1.0f - fade_current; if (fade_state == FADE_WAIT) fade_current = 1.0f; } if (!TextureReady ()) fade_current = 1.0f; } if (fade_state == FADE_IDLE && !TextureReady ()) { fade_state = FADE_IN; fade_start = now; } if (fade_state == FADE_IDLE && WorldSceneElapsed () > RESET_INTERVAL) WorldReset (); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void WorldInit (void) { last_update = GetTickCount (); for (int i = 0; i < CARS; i++) new CCar (); sky = new CSky (); WorldReset (); fade_state = FADE_OUT; fade_start = 0; } ================================================ FILE: World.h ================================================ GLrgba WorldBloomColor (); char WorldCell (int x, int y); GLrgba WorldLightColor (unsigned index); int WorldLogoIndex (); GLbbox WorldHotZone (); void WorldInit (void); float WorldFade (void); void WorldRender (); void WorldReset (void); int WorldSceneBegin (); int WorldSceneElapsed (); void WorldTerm (void); void WorldUpdate (void); ================================================ FILE: glBbox.cpp ================================================ /*----------------------------------------------------------------------------- glBbox.cpp 2006 Shamus Young ------------------------------------------------------------------------------- This module has a few functions useful for manipulating the bounding-box structs. -----------------------------------------------------------------------------*/ #define MAX_VALUE 999999999999999.9f #include #include "macro.h" #include "glTypes.h" /*----------------------------------------------------------------------------- Does the given point fall within the given Bbox? -----------------------------------------------------------------------------*/ bool glBboxTestPoint (GLbbox box, GLvector point) { if (point.x > box.max.x || point.x < box.min.x) return false; if (point.y > box.max.y || point.y < box.min.y) return false; if (point.z > box.max.z || point.z < box.min.z) return false; return true; } /*----------------------------------------------------------------------------- Expand Bbox (if needed) to contain given point -----------------------------------------------------------------------------*/ GLbbox glBboxContainPoint (GLbbox box, GLvector point) { box.min.x = MIN (box.min.x, point.x); box.min.y = MIN (box.min.y, point.y); box.min.z = MIN (box.min.z, point.z); box.max.x = MAX (box.max.x, point.x); box.max.y = MAX (box.max.y, point.y); box.max.z = MAX (box.max.z, point.z); return box; } /*----------------------------------------------------------------------------- This will invalidate the bbox. -----------------------------------------------------------------------------*/ GLbbox glBboxClear (void) { GLbbox result; result.max = glVector (-MAX_VALUE, -MAX_VALUE, -MAX_VALUE); result.min = glVector ( MAX_VALUE, MAX_VALUE, MAX_VALUE); return result; } ================================================ FILE: glMatrix.cpp ================================================ /*----------------------------------------------------------------------------- glMatrix.cpp 2006 Shamus Young ------------------------------------------------------------------------------- Functions useful for manipulating the Matrix struct -----------------------------------------------------------------------------*/ #define M(e,x,y) (e.elements[x][y]) /*** Order type constants, constructors, extractors ***/ /* There are 24 possible conventions, designated by: */ /* o EulAxI = axis used initially */ /* o EulPar = parity of axis permutation */ /* o EulRep = repetition of initial axis as last */ /* o EulFrm = frame from which axes are taken */ /* Axes I,J,K will be a permutation of X,Y,Z. */ /* Axis H will be either I or K, depending on EulRep. */ /* Frame S takes axes from initial static frame. */ /* If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then */ /* {a,b,c,ord} means Rz(c)Ry(b)Rx(a), where Rz(c)v */ /* rotates v around Z by c radians. */ #define EulFrmS 0 #define EulFrmR 1 #define EulFrm(ord) ((unsigned)(ord)&1) #define EulRepNo 0 #define EulRepYes 1 #define EulRep(ord) (((unsigned)(ord)>>1)&1) #define EulParEven 0 #define EulParOdd 1 #define EulPar(ord) (((unsigned)(ord)>>2)&1) #define EulSafe "\000\001\002\000" #define EulNext "\001\002\000\001" #define EulAxI(ord) ((int)(EulSafe[(((unsigned)(ord)>>3)&3)])) #define EulAxJ(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)==EulParOdd)])) #define EulAxK(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)!=EulParOdd)])) #define EulAxH(ord) ((EulRep(ord)==EulRepNo)?EulAxK(ord):EulAxI(ord)) /* EulGetOrd unpacks all useful information about order simultaneously. */ #define EulGetOrd(ord,i,j,k,h,n,s,f) {unsigned o=ord;f=o&1;o>>=1;s=o&1;o>>=1;\ n=o&1;o>>=1;i=EulSafe[o&3];j=EulNext[i+n];k=EulNext[i+1-n];h=s?k:i;} /* EulOrd creates an order value between 0 and 23 from 4-tuple choices. */ #define EulOrd(i,p,r,f) (((((((i)<<1)+(p))<<1)+(r))<<1)+(f)) /* Static axes */ #define EulOrdXYZs EulOrd(X,EulParEven,EulRepNo,EulFrmS) #define EulOrdXYXs EulOrd(X,EulParEven,EulRepYes,EulFrmS) #define EulOrdXZYs EulOrd(X,EulParOdd,EulRepNo,EulFrmS) #define EulOrdXZXs EulOrd(X,EulParOdd,EulRepYes,EulFrmS) #define EulOrdYZXs EulOrd(Y,EulParEven,EulRepNo,EulFrmS) #define EulOrdYZYs EulOrd(Y,EulParEven,EulRepYes,EulFrmS) #define EulOrdYXZs EulOrd(Y,EulParOdd,EulRepNo,EulFrmS) #define EulOrdYXYs EulOrd(Y,EulParOdd,EulRepYes,EulFrmS) #define EulOrdZXYs EulOrd(Z,EulParEven,EulRepNo,EulFrmS) #define EulOrdZXZs EulOrd(Z,EulParEven,EulRepYes,EulFrmS) #define EulOrdZYXs EulOrd(Z,EulParOdd,EulRepNo,EulFrmS) #define EulOrdZYZs EulOrd(Z,EulParOdd,EulRepYes,EulFrmS) /* Rotating axes */ #define EulOrdZYXr EulOrd(X,EulParEven,EulRepNo,EulFrmR) #define EulOrdXYXr EulOrd(X,EulParEven,EulRepYes,EulFrmR) #define EulOrdYZXr EulOrd(X,EulParOdd,EulRepNo,EulFrmR) #define EulOrdXZXr EulOrd(X,EulParOdd,EulRepYes,EulFrmR) #define EulOrdXZYr EulOrd(Y,EulParEven,EulRepNo,EulFrmR) #define EulOrdYZYr EulOrd(Y,EulParEven,EulRepYes,EulFrmR) #define EulOrdZXYr EulOrd(Y,EulParOdd,EulRepNo,EulFrmR) #define EulOrdYXYr EulOrd(Y,EulParOdd,EulRepYes,EulFrmR) #define EulOrdYXZr EulOrd(Z,EulParEven,EulRepNo,EulFrmR) #define EulOrdZXZr EulOrd(Z,EulParEven,EulRepYes,EulFrmR) #define EulOrdXYZr EulOrd(Z,EulParOdd,EulRepNo,EulFrmR) #define EulOrdZYZr EulOrd(Z,EulParOdd,EulRepYes,EulFrmR) #include #include #include "macro.h" #include "glTypes.h" static float identity[4][4] = { {1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}, }; /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void* glMatrixCreate (void) { GLmatrix* m; int x; int y; m = new GLmatrix; for (x = 0; x < 4; x++) { for (y = 0; y < 4; y++) { m -> elements[x][y] = identity[x][y]; } } return (void*)m; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLmatrix glMatrixIdentity (void) { GLmatrix m; int x; int y; for (x = 0; x < 4; x++) { for (y = 0; y < 4; y++) { M(m, x, y) = identity[x][y]; } } return m; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ void glMatrixElementsSet (GLmatrix* m, float* in) { m -> elements[0][0] = in[0]; m -> elements[0][1] = in[1]; m -> elements[0][2] = in[2]; m -> elements[0][3] = in[3]; m -> elements[1][0] = in[4]; m -> elements[1][1] = in[5]; m -> elements[1][2] = in[6]; m -> elements[1][3] = in[7]; m -> elements[2][0] = in[8]; m -> elements[2][1] = in[9]; m -> elements[2][2] = in[10]; m -> elements[2][3] = in[11]; m -> elements[3][0] = in[12]; m -> elements[3][1] = in[13]; m -> elements[3][2] = in[14]; m -> elements[3][3] = in[15]; } /*--------------------------------------------------------------------------- A matrix multiplication (dot product) of two 4x4 matrices. ---------------------------------------------------------------------------*/ GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b) { GLmatrix result; M(result, 0,0) = M(a, 0,0) * M(b, 0, 0) + M(a, 1,0) * M(b, 0, 1) + M(a, 2,0) * M(b, 0, 2); M(result, 1,0) = M(a, 0,0) * M(b, 1, 0) + M(a, 1,0) * M(b, 1, 1) + M(a, 2,0) * M(b, 1, 2); M(result, 2,0) = M(a, 0,0) * M(b, 2, 0) + M(a, 1,0) * M(b, 2, 1) + M(a, 2,0) * M(b, 2, 2); M(result, 3,0) = M(a, 0,0) * M(b, 3, 0) + M(a, 1,0) * M(b, 3, 1) + M(a, 2,0) * M(b, 3, 2) + M(a, 3,0); M(result, 0,1) = M(a, 0,1) * M(b, 0, 0) + M(a, 1,1) * M(b, 0, 1) + M(a, 2,1) * M(b, 0, 2); M(result, 1,1) = M(a, 0,1) * M(b, 1, 0) + M(a, 1,1) * M(b, 1, 1) + M(a, 2,1) * M(b, 1, 2); M(result, 2,1) = M(a, 0,1) * M(b, 2, 0) + M(a, 1,1) * M(b, 2, 1) + M(a, 2,1) * M(b, 2, 2); M(result, 3,1) = M(a, 0,1) * M(b, 3, 0) + M(a, 1,1) * M(b, 3, 1) + M(a, 2,1) * M(b, 3, 2) + M(a, 3,1); M(result, 0,2) = M(a, 0,2) * M(b, 0, 0) + M(a, 1,2) * M(b, 0, 1) + M(a, 2,2) * M(b, 0, 2); M(result, 1,2) = M(a, 0,2) * M(b, 1, 0) + M(a, 1,2) * M(b, 1, 1) + M(a, 2,2) * M(b, 1, 2); M(result, 2,2) = M(a, 0,2) * M(b, 2, 0) + M(a, 1,2) * M(b, 2, 1) + M(a, 2,2) * M(b, 2, 2); M(result, 3,2) = M(a, 0,2) * M(b, 3, 0) + M(a, 1,2) * M(b, 3, 1) + M(a, 2,2) * M(b, 3, 2) + M(a, 3,2); return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector glMatrixTransformPoint (GLmatrix m, GLvector in) { GLvector out; out.x = M(m,0,0) * in.x + M(m,1,0) * in.y + M(m,2,0) * in.z + M(m,3,0); out.y = M(m,0,1) * in.x + M(m,1,1) * in.y + M(m,2,1) * in.z + M(m,3,1); out.z = M(m,0,2) * in.x + M(m,1,2) * in.y + M(m,2,2) * in.z + M(m,3,2); return out; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLmatrix glMatrixTranslate (GLmatrix m, GLvector in) { GLvector old; old.x = M(m,3,0); old.y = M(m,3,1); old.z = M(m,3,2); M(m, 3, 0) = 0.0f; M(m, 3, 1) = 0.0f; M(m, 3, 2) = 0.0f; in = glMatrixTransformPoint (m, in); M(m, 3, 0) = old.x; M(m, 3, 1) = old.y; M(m, 3, 2) = old.z; M(m,3,0) += in.x; M(m,3,1) += in.y; M(m,3,2) += in.z; return m; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, float z) { GLmatrix r; float length; float s, c, t; GLvector in; theta *= DEGREES_TO_RADIANS; r = glMatrixIdentity (); length = (float)sqrt (x * x + y * y + z * z); if (length < 0.00001f) return m; x /= length; y /= length; z /= length; s = (float)sin (theta); c = (float)cos (theta); t = 1.0f - c; in.x = in.y = in.z = 1.0f; M(r, 0,0) = t*x*x + c; M(r, 1,0) = t*x*y - s*z; M(r, 2,0) = t*x*z + s*y; M(r, 3,0) = 0; M(r, 0,1) = t*x*y + s*z; M(r, 1,1) = t*y*y + c; M(r, 2,1) = t*y*z - s*x; M(r, 3,1) = 0; M(r, 0,2) = t*x*z - s*y; M(r, 1,2) = t*y*z + s*x; M(r, 2,2) = t*z*z + c; M(r, 3,2) = 0; m = glMatrixMultiply (m, r); return m; } /* Convert matrix to Euler angles (in radians). */ GLvector glMatrixToEuler (GLmatrix mat, int order) { GLvector ea; int i,j,k,h,n,s,f; EulGetOrd (order,i,j,k,h,n,s,f); if (s==EulRepYes) { float sy = (float)sqrt(mat.elements[i][j]*mat.elements[i][j] + mat.elements[i][k]*mat.elements[i][k]); if (sy > 16 * FLT_EPSILON) { ea.x = (float)atan2(mat.elements[i][j], mat.elements[i][k]); ea.y = (float)atan2(sy, mat.elements[i][i]); ea.z = (float)atan2(mat.elements[j][i], -mat.elements[k][i]); } else { ea.x = (float)atan2(-mat.elements[j][k], mat.elements[j][j]); ea.y = (float)atan2(sy, mat.elements[i][i]); ea.z = 0; } } else { float cy = (float)sqrt(mat.elements[i][i]*mat.elements[i][i] + mat.elements[j][i]*mat.elements[j][i]); if (cy > 16*FLT_EPSILON) { ea.x = (float)atan2(mat.elements[k][j], mat.elements[k][k]); ea.y = (float)atan2(-mat.elements[k][i], cy); ea.z = (float)atan2(mat.elements[j][i], mat.elements[i][i]); } else { ea.x = (float)atan2(-mat.elements[j][k], mat.elements[j][j]); ea.y = (float)atan2(-mat.elements[k][i], cy); ea.z = 0; } } if (n==EulParOdd) { ea.x = -ea.x; ea.y = - ea.y; ea.z = -ea.z; } if (f==EulFrmR) { float t = ea.x; ea.x = ea.z; ea.z = t; } //ea.w = order; return (ea); } ================================================ FILE: glQuat.cpp ================================================ /*----------------------------------------------------------------------------- glQuat.cpp 2006 Shamus Young ------------------------------------------------------------------------------- Functions for dealing with Quaternions -----------------------------------------------------------------------------*/ #include #include #include #include #include "math.h" #include "glTypes.h" enum QuatPart {X, Y, Z, W}; /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLquat glQuat (float x, float y, float z, float w) { GLquat result; result.x = x; result.y = y; result.z = z; result.w = w; return result; } /* Convert quaternion to Euler angles (in radians). */ /* EulerAngles Eul_FromQuat(Quat q, int order) { HMatrix M; double Nq = q.x*q.x+q.y*q.y+q.z*q.z+q.w*q.w; double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0; double xs = q.x*s, ys = q.y*s, zs = q.z*s; double wx = q.w*xs, wy = q.w*ys, wz = q.w*zs; double xx = q.x*xs, xy = q.x*ys, xz = q.x*zs; double yy = q.y*ys, yz = q.y*zs, zz = q.z*zs; M[X][X] = 1.0 - (yy + zz); M[X][Y] = xy - wz; M[X][Z] = xz + wy; M[Y][X] = xy + wz; M[Y][Y] = 1.0 - (xx + zz); M[Y][Z] = yz - wx; M[Z][X] = xz - wy; M[Z][Y] = yz + wx; M[Z][Z] = 1.0 - (xx + yy); M[W][X]=M[W][Y]=M[W][Z]=M[X][W]=M[Y][W]=M[Z][W]=0.0; M[W][W]=1.0; return (Eul_FromHMatrix(M, order)); } */ GLvector glQuatToEuler (GLquat q, int order) { GLmatrix M; float Nq = q.x*q.x+q.y*q.y+q.z*q.z+q.w*q.w; float s = (Nq > 0.0f) ? (2.0f / Nq) : 0.0f; float xs = q.x*s, ys = q.y*s, zs = q.z*s; float wx = q.w*xs, wy = q.w*ys, wz = q.w*zs; float xx = q.x*xs, xy = q.x*ys, xz = q.x*zs; float yy = q.y*ys, yz = q.y*zs, zz = q.z*zs; M.elements[X][X] = 1.0f - (yy + zz); M.elements[X][Y] = xy - wz; M.elements[X][Z] = xz + wy; M.elements[Y][X] = xy + wz; M.elements[Y][Y] = 1.0f - (xx + zz); M.elements[Y][Z] = yz - wx; M.elements[Z][X] = xz - wy; M.elements[Z][Y] = yz + wx; M.elements[Z][Z] = 1.0f - (xx + yy); M.elements[W][X] = M.elements[W][Y] = M.elements[W][Z] = M.elements[X][W] = M.elements[Y][W] = M.elements[Z][W] = 0.0f; M.elements[W][W] = 1.0f; return (glMatrixToEuler(M, order)); } ================================================ FILE: glRgba.cpp ================================================ /*----------------------------------------------------------------------------- glRgba.cpp 2009 Shamus Young ------------------------------------------------------------------------------- Functions for dealing with RGBA color values. -----------------------------------------------------------------------------*/ #include #include #include #include #include "math.h" #include "glTypes.h" #include "macro.h" /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaFromHsl (float h, float sl, float l) { float v; float r,g,b; r = l; // default to gray g = l; b = l; v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl); if (v > 0) { float m; float sv; int sextant; float fract, vsf, mid1, mid2; m = l + l - v; sv = (v - m ) / v; h *= 6.0f; sextant = (int)h; fract = h - sextant; vsf = v * sv * fract; mid1 = m + vsf; mid2 = v - vsf; switch (sextant) { case 0: r = v; g = mid1; b = m; break; case 1: r = mid2; g = v; b = m; break; case 2: r = m; g = v; b = mid1; break; case 3: r = m; g = mid2; b = v; break; case 4: r = mid1; g = m; b = v; break; case 5: r = v; g = m; b = mid2; break; } } return glRgba (r, g, b); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta) { GLrgba result; result.red = MathInterpolate (c1.red, c2.red, delta); result.green = MathInterpolate (c1.green, c2.green, delta); result.blue = MathInterpolate (c1.blue, c2.blue, delta); result.alpha = MathInterpolate (c1.alpha, c2.alpha, delta); return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaAdd (GLrgba c1, GLrgba c2) { GLrgba result; result.red = c1.red + c2.red; result.green = c1.green + c2.green; result.blue = c1.blue + c2.blue; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2) { GLrgba result; result.red = c1.red - c2.red; result.green = c1.green - c2.green; result.blue = c1.blue - c2.blue; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2) { GLrgba result; result.red = c1.red * c2.red; result.green = c1.green * c2.green; result.blue = c1.blue * c2.blue; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgbaScale (GLrgba c, float scale) { c.red *= scale; c.green *= scale; c.blue *= scale; return c; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (char* string) { long color; char buffer[10]; char* pound; GLrgba result; strncmp (buffer, string, 10); if (pound = strchr (buffer, '#')) pound[0] = ' '; if (sscanf (string, "%x", &color) != 1) return glRgba (0.0f); result.red = (float)GetBValue (color) / 255.0f; result.green = (float)GetGValue (color) / 255.0f; result.blue = (float)GetRValue (color) / 255.0f; result.alpha = 1.0f; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (int red, int green, int blue) { GLrgba result; result.red = (float)red / 255.0f; result.green = (float)green / 255.0f; result.blue = (float)blue / 255.0f; result.alpha = 1.0f; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (float red, float green, float blue) { GLrgba result; result.red = red; result.green = green; result.blue = blue; result.alpha = 1.0f; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (float red, float green, float blue, float alpha) { GLrgba result; result.red = red; result.green = green; result.blue = blue; result.alpha = alpha; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (long c) { GLrgba result; result.red = (float)GetRValue (c) / 255.0f; result.green = (float)GetGValue (c) / 255.0f; result.blue = (float)GetBValue (c) / 255.0f; result.alpha = 1.0f; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLrgba glRgba (float luminance) { GLrgba result; result.red = luminance; result.green = luminance; result.blue = luminance; result.alpha = 1.0f; return result; } /*----------------------------------------------------------------------------- Takes the given index and returns a "random" color unique for that index. 512 Unique values: #0 and #512 will be the same, as will #1 and #513, etc Useful for visual debugging in some situations. -----------------------------------------------------------------------------*/ GLrgba glRgbaUnique (int i) { GLrgba c; c.alpha = 1.0f; c.red = 0.4f + ((i & 1) ? 0.2f : 0.0f) + ((i & 8) ? 0.3f : 0.0f) - ((i & 64) ? 0.3f : 0.0f); c.green = 0.4f + ((i & 2) ? 0.2f : 0.0f) + ((i & 32) ? 0.3f : 0.0f) - ((i & 128) ? 0.3f : 0.0f); c.blue = 0.4f + ((i & 4) ? 0.2f : 0.0f) + ((i & 16) ? 0.3f : 0.0f) - ((i & 256) ? 0.3f : 0.0f); return c; } /*----------------------------------------------------------------------------- + operator -----------------------------------------------------------------------------*/ GLrgba GLrgba::operator+ (const GLrgba& c) { return glRgba (red + c.red, green + c.green, blue + c.blue, alpha); } GLrgba GLrgba::operator+ (const float& c) { return glRgba (red + c, green + c, blue + c, alpha); } void GLrgba::operator+= (const GLrgba& c) { red += c.red; green += c.green; blue += c.blue; } void GLrgba::operator+= (const float& c) { red += c; green += c; blue += c; } /*----------------------------------------------------------------------------- - operator -----------------------------------------------------------------------------*/ GLrgba GLrgba::operator- (const GLrgba& c) { return glRgba (red - c.red, green - c.green, blue - c.blue); } GLrgba GLrgba::operator- (const float& c) { return glRgba (red - c, green - c, blue - c, alpha); } void GLrgba::operator-= (const GLrgba& c) { red -= c.red; green -= c.green; blue -= c.blue; } void GLrgba::operator-= (const float& c) { red -= c; green -= c; blue -= c; } /*----------------------------------------------------------------------------- * operator -----------------------------------------------------------------------------*/ GLrgba GLrgba::operator* (const GLrgba& c) { return glRgba (red * c.red, green * c.green, blue * c.blue); } GLrgba GLrgba::operator* (const float& c) { return glRgba (red * c, green * c, blue * c, alpha); } void GLrgba::operator*= (const GLrgba& c) { red *= c.red; green *= c.green; blue *= c.blue; } void GLrgba::operator*= (const float& c) { red *= c; green *= c; blue *= c; } /*----------------------------------------------------------------------------- / operator -----------------------------------------------------------------------------*/ GLrgba GLrgba::operator/ (const GLrgba& c) { return glRgba (red / c.red, green / c.green, blue / c.blue); } GLrgba GLrgba::operator/ (const float& c) { return glRgba (red / c, green / c, blue / c, alpha); } void GLrgba::operator/= (const GLrgba& c) { red /= c.red; green /= c.green; blue /= c.blue; } void GLrgba::operator/= (const float& c) { red /= c; green /= c; blue /= c; } bool GLrgba::operator== (const GLrgba& c) { return (red == c.red && green == c.green && blue == c.blue); } ================================================ FILE: glTypes.h ================================================ #ifndef glTYPES #define glTYPES #define GL_CLAMP_TO_EDGE 0x812F #define OPERATORS(type) \ type operator+ (const type& c); \ type operator+ (const float& c);\ void operator+= (const type& c);\ void operator+= (const float& c);\ type operator- (const type& c);\ type operator- (const float& c);\ void operator-= (const type& c);\ void operator-= (const float& c);\ type operator* (const type& c);\ type operator* (const float& c);\ void operator*= (const type& c);\ void operator*= (const float& c);\ type operator/ (const type& c);\ type operator/ (const float& c);\ void operator/= (const type& c);\ void operator/= (const float& c);\ bool operator== (const type& c); #define JOINT_MAX_CHILDREN 8 struct GLquat { float x; float y; float z; float w; }; struct GLvector { float x; float y; float z; OPERATORS(GLvector); }; typedef GLvector GLvector3; struct GLvector2 { float x; float y; OPERATORS(GLvector2); }; struct GLrgba { float red; float green; float blue; float alpha; OPERATORS(GLrgba); }; struct GLmatrix { float elements[4][4]; }; struct GLbbox { GLvector3 min; GLvector3 max; }; struct GLvertex { GLvector3 position; GLvector2 uv; GLrgba color; int bone; }; struct GLrect { float left; float top; float right; float bottom; }; struct GLtriangle { int v1; int v2; int v3; int normal1; int normal2; int normal3; }; /* class GLmodel { public: unsigned vertex_count; unsigned triangle_count; unsigned normal_count; GLvertex* vertex; GLvector* normal; GLtriangle* triangle; void TriangleRender (unsigned n); GLtriangle* TriangleAdd (unsigned v1, int unsigned, int unsigned); GLtriangle* TriangleAdd (GLtriangle c); void NormalAdd (GLvector n); void VertexAdd (GLvertex v); GLmodel (); ~GLmodel (); void Render (); GLbbox BBox (); private: GLbbox m_bbox; }; struct GLkeyframe { float time; GLvector offset; GLvector rotation; }; struct GLsegment { int index; GLvector rotation; GLvector offset; GLkeyframe keyframes[255]; int frame_count; }; class GLanimate { public: GLanimate (); void KeyframeAdd (int joint, float time, GLquat q); void TimeSet (float time); void PositionSet (float pos); GLvector Rotation (int); GLvector Offset (int); private: GLsegment* m_segments; int m_segment_count; float m_length; }; */ GLbbox glBboxClear (void); GLbbox glBboxContainPoint (GLbbox box, GLvector point); bool glBboxTestPoint (GLbbox box, GLvector point); GLrgba glRgba (char* string); GLrgba glRgba (float red, float green, float blue); GLrgba glRgba (float luminance); GLrgba glRgba (float red, float green, float blue, float alpha); GLrgba glRgba (long c); GLrgba glRgba (int red, int green, int blue); GLrgba glRgbaAdd (GLrgba c1, GLrgba c2); GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2); GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta); GLrgba glRgbaScale (GLrgba c, float scale); GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2); GLrgba glRgbaUnique (int i); GLrgba glRgbaFromHsl (float h, float s, float l); GLmatrix glMatrixIdentity (void); void glMatrixElementsSet (GLmatrix* m, float* in); GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b); GLvector glMatrixTransformPoint (GLmatrix m, GLvector in); GLmatrix glMatrixTranslate (GLmatrix m, GLvector in); GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, float z); GLvector glMatrixToEuler (GLmatrix mat, int order); GLquat glQuat (float x, float y, float z, float w); GLvector glQuatToEuler (GLquat q, int order); GLvector glVector (float x, float y, float z); GLvector glVectorCrossProduct (GLvector v1, GLvector v2); float glVectorDotProduct (GLvector v1, GLvector v2); void glVectorGl (GLvector v); GLvector glVectorInterpolate (GLvector v1, GLvector v2, float scalar); float glVectorLength (GLvector v); GLvector glVectorNormalize (GLvector v); GLvector glVectorReflect (GLvector3 ray, GLvector3 normal); GLvector2 glVector (float x, float y); GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2); GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2); GLvector2 glVectorNormalize (GLvector2 v); GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar); GLvector2 glVectorSinCos (float angle); float glVectorLength (GLvector2 v); #endif #ifndef NULL #define NULL 0 #endif ================================================ FILE: glVector2.cpp ================================================ /*----------------------------------------------------------------------------- Vector2.cpp 2006 Shamus Young ------------------------------------------------------------------------------- Functions for dealing with 2d (usually texture mapping) values. -----------------------------------------------------------------------------*/ #include #include #include #include #include "glTypes.h" #include "math.h" #include "macro.h" /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVectorNormalize (GLvector2 v) { float length; length = glVectorLength (v); if (length < 0.000001f) return v; return v * (1.0f / length); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ float glVectorLength (GLvector2 v) { return (float)sqrt (v.x * v.x + v.y * v.y); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVectorSinCos (float a) { GLvector2 val; a *= DEGREES_TO_RADIANS; val.x = sinf (a); val.y = cosf (a); return val; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVector (float x, float y) { GLvector2 val; val.x = x; val.y = y; return val; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2) { GLvector2 result; result.x = val1.x + val2.x; result.y = val1.y + val2.y; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar) { GLvector2 result; result.x = MathInterpolate (v1.x, v2.x, scalar); result.y = MathInterpolate (v1.y, v2.y, scalar); return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2) { GLvector2 result; result.x = val1.x - val2.x; result.y = val1.y - val2.y; return result; } /*----------------------------------------------------------------------------- + -----------------------------------------------------------------------------*/ GLvector2 GLvector2::operator+ (const GLvector2& c) { return glVector (x + c.x, y + c.y); } GLvector2 GLvector2::operator+ (const float& c) { return glVector (x + c, y + c); } void GLvector2::operator+= (const GLvector2& c) { x += c.x; y += c.y; } void GLvector2::operator+= (const float& c) { x += c; y += c; } GLvector2 GLvector2::operator- (const GLvector2& c) { return glVector (x - c.x, y - c.y); } GLvector2 GLvector2::operator- (const float& c) { return glVector (x - c, y - c); } void GLvector2::operator-= (const GLvector2& c) { x -= c.x; y -= c.y; } void GLvector2::operator-= (const float& c) { x -= c; y -= c; } GLvector2 GLvector2::operator* (const GLvector2& c) { return glVector (x * c.x, y * c.y); } GLvector2 GLvector2::operator* (const float& c) { return glVector (x * c, y * c); } void GLvector2::operator*= (const GLvector2& c) { x *= c.x; y *= c.y; } void GLvector2::operator*= (const float& c) { x *= c; y *= c; } GLvector2 GLvector2::operator/ (const GLvector2& c) { return glVector (x / c.x, y / c.y); } GLvector2 GLvector2::operator/ (const float& c) { return glVector (x / c, y / c); } void GLvector2::operator/= (const GLvector2& c) { x /= c.x; y /= c.y; } void GLvector2::operator/= (const float& c) { x /= c; y /= c; } bool GLvector2::operator== (const GLvector2& c) { if (x == c.x && y == c.y) return true; return false; } ================================================ FILE: glVector3.cpp ================================================ /*----------------------------------------------------------------------------- glVector3.cpp 2006 Shamus Young ------------------------------------------------------------------------------- Functions for dealing with 3d vectors. -----------------------------------------------------------------------------*/ #include #include #include #include #include "macro.h" #include "math.h" #include "glTypes.h" /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector glVectorReflect (GLvector3 ray, GLvector3 normal) { float dot; dot = glVectorDotProduct (ray, normal); return ray - (normal * (2.0f * dot)); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVector (float x, float y, float z) { GLvector3 result; result.x = x; result.y = y; result.z = z; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVectorInterpolate (GLvector3 v1, GLvector3 v2, float scalar) { GLvector3 result; result.x = MathInterpolate (v1.x, v2.x, scalar); result.y = MathInterpolate (v1.y, v2.y, scalar); result.z = MathInterpolate (v1.z, v2.z, scalar); return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ float glVectorLength (GLvector3 v) { return (float)sqrt (v.x * v.x + v.y * v.y + v.z * v.z); } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ float glVectorDotProduct (GLvector3 v1, GLvector3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVectorCrossProduct (GLvector3 v1, GLvector3 v2) { GLvector3 result; result.x = v1.y * v2.z - v2.y * v1.z; result.y = v1.z * v2.x - v2.z * v1.x; result.z = v1.x * v2.y - v2.x * v1.y; return result; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVectorInvert (GLvector3 v) { v.x *= -v.x; v.y *= -v.y; v.z *= -v.z; return v; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVectorScale (GLvector3 v, float scale) { v.x *= scale; v.y *= scale; v.z *= scale; return v; } /*----------------------------------------------------------------------------- -----------------------------------------------------------------------------*/ GLvector3 glVectorNormalize (GLvector3 v) { float length; length = glVectorLength (v); if (length < 0.000001f) return v; return glVectorScale (v, 1.0f / length); } /*----------------------------------------------------------------------------- + -----------------------------------------------------------------------------*/ GLvector GLvector::operator+ (const GLvector& c) { return glVector (x + c.x, y + c.y, z + c.z); } GLvector GLvector::operator+ (const float& c) { return glVector (x + c, y + c, z + c); } void GLvector::operator+= (const GLvector& c) { x += c.x; y += c.y; z += c.z; } void GLvector::operator+= (const float& c) { x += c; y += c; z += c; } GLvector GLvector::operator- (const GLvector& c) { return glVector (x - c.x, y - c.y, z - c.z); } GLvector GLvector::operator- (const float& c) { return glVector (x - c, y - c, z - c); } void GLvector::operator-= (const GLvector& c) { x -= c.x; y -= c.y; z -= c.z; } void GLvector::operator-= (const float& c) { x -= c; y -= c; z -= c; } GLvector GLvector::operator* (const GLvector& c) { return glVector (x * c.x, y * c.y, z * c.z); } GLvector GLvector::operator* (const float& c) { return glVector (x * c, y * c, z * c); } void GLvector::operator*= (const GLvector& c) { x *= c.x; y *= c.y; z *= c.z; } void GLvector::operator*= (const float& c) { x *= c; y *= c; z *= c; } GLvector GLvector::operator/ (const GLvector& c) { return glVector (x / c.x, y / c.y, z / c.z); } GLvector GLvector::operator/ (const float& c) { return glVector (x / c, y / c, z / c); } void GLvector::operator/= (const GLvector& c) { x /= c.x; y /= c.y; z /= c.z; } void GLvector::operator/= (const float& c) { x /= c; y /= c; z /= c; } bool GLvector::operator== (const GLvector& c) { if (x == c.x && y == c.y && z == c.z) return true; return false; }