diff --git a/Building.cpp b/Building.cpp new file mode 100644 index 0000000..8e20597 --- /dev/null +++ b/Building.cpp @@ -0,0 +1,848 @@ +/*----------------------------------------------------------------------------- + + 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" + +//This is used by the recursive roof builder to decide what items may be added. +enum +{ + ADDON_NONE, + ADDON_LOGO, + ADDON_TRIM, + ADDON_LIGHTS, + ADDON_COUNT +}; + +static GLvector vector_buffer[MAX_VBUFFER]; + +/*----------------------------------------------------------------------------- + + This is the constructor for our building constructor. + +-----------------------------------------------------------------------------*/ + +CBuilding::CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color) +{ + + _x = x; + _y = y; + _width = width; + _depth = depth; + _height = height; + _center = glVector ((float)(_x + width / 2), 0.0f, (float)(_y + depth / 2)); + _seed = seed; + _texture_type = RandomVal (); + _color = color; + _color.alpha = 0.1f; + _have_lights = false; + _have_logo = false; + _have_trim = false; + _roof_tiers = 0; + //Pick a color for logos & roof lights + //_trim_color = WorldLightColor (seed); + _trim_color = glRgbaFromHsl (0.5f, 1.0f, 0.9f); + _mesh = new CMesh; //The main textured mesh for the building + _mesh_flat = new CMesh; //Flat-color mesh for untextured detail items. + switch (type) { + case BUILDING_SIMPLE: + CreateSimple (); + break; + case BUILDING_MODERN: + CreateModern (); + break; + case BUILDING_TOWER: + CreateTower (); + break; + case BUILDING_BLOCKY: + CreateBlocky (); + break; + } + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CBuilding::~CBuilding () +{ + + if (_mesh) + delete _mesh; + if (_mesh_flat) + delete _mesh_flat; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +unsigned CBuilding::Texture () +{ + + return TextureRandomBuilding (_texture_type); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int CBuilding::PolyCount () +{ + + return _mesh->PolyCount () + _mesh_flat->PolyCount (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::Render () +{ + + glColor3fv (&_color.red); + _mesh->Render (); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::RenderFlat (bool colored) +{ + + if (colored) + glColor3fv (&_color.red); + _mesh_flat->Render (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::ConstructCube (int left, int right, int front, int back, int bottom, int top) +{ + + GLvertex p[10]; + float x1, x2, z1, z2, y1, y2; + int i; + int index_list[10]; + float u, v1, v2; + float mapping; + int base_index; + int height; + + height = top - bottom; + x1 = (float)left; + x2 = (float)right; + y1 = (float)bottom; + y2 = (float)top; + z1 = (float)front; + z2 = (float)back; + base_index = _mesh->VertexCount (); + + mapping = (float)SEGMENTS_PER_TEXTURE; + u = (float)(RandomVal () % SEGMENTS_PER_TEXTURE) / (float)SEGMENTS_PER_TEXTURE; + v1 = (float)bottom / (float)mapping; + v2 = (float)top / (float)mapping; + + p[0].position = glVector (x1, y1, z1); p[0].uv = glVector (u, v1); + p[1].position = glVector (x1, y2, z1); p[1].uv = glVector (u, v2); + u += (float)_width / mapping; + p[2].position = glVector (x2, y1, z1); p[2].uv = glVector (u, v1); + p[3].position = glVector (x2, y2, z1); p[3].uv = glVector (u, v2); + u += (float)_depth / mapping; + p[4].position = glVector (x2, y1, z2); p[4].uv = glVector (u, v1); + p[5].position = glVector (x2, y2, z2); p[5].uv = glVector (u, v2); + u += (float)_width / mapping; + p[6].position = glVector (x1, y1, z2); p[6].uv = glVector (u, v1); + p[7].position = glVector (x1, y2, z2); p[7].uv = glVector (u, v2); + u += (float)_width / mapping; + p[8].position = glVector (x1, y1, z1); p[8].uv = glVector (u, v1); + p[9].position = glVector (x1, y2, z1); p[9].uv = glVector (u, v2); + for (i = 0; i < 10; i++) { + p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE; + _mesh->VertexAdd (p[i]); + index_list[i] = base_index + i; + } + _mesh->CubeAdd (&index_list[0]); + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::ConstructCube (float left, float right, float front, float back, float bottom, float top) +{ + + GLvertex p[10]; + float x1, x2, z1, z2, y1, y2; + int i; + int index_list[10]; + int base_index; + + x1 = left; + x2 = right; + y1 = bottom; + y2 = top; + z1 = front; + z2 = back; + base_index = _mesh_flat->VertexCount (); + + p[0].position = glVector (x1, y1, z1); p[0].uv = glVector (0.0f, 0.0f); + p[1].position = glVector (x1, y2, z1); p[1].uv = glVector (0.0f, 0.0f); + p[2].position = glVector (x2, y1, z1); p[2].uv = glVector (0.0f, 0.0f); + p[3].position = glVector (x2, y2, z1); p[3].uv = glVector (0.0f, 0.0f); + p[4].position = glVector (x2, y1, z2); p[4].uv = glVector (0.0f, 0.0f); + p[5].position = glVector (x2, y2, z2); p[5].uv = glVector (0.0f, 0.0f); + p[6].position = glVector (x1, y1, z2); p[6].uv = glVector (0.0f, 0.0f); + p[7].position = glVector (x1, y2, z2); p[7].uv = glVector (0.0f, 0.0f); + p[8].position = glVector (x1, y1, z1); p[8].uv = glVector (0.0f, 0.0f); + p[9].position = glVector (x1, y2, z1); p[9].uv = glVector (0.0f, 0.0f); + for (i = 0; i < 10; i++) { + p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE; + _mesh_flat->VertexAdd (p[i]); + index_list[i] = base_index + i; + } + _mesh_flat->CubeAdd (&index_list[0]); + + +} + +/*----------------------------------------------------------------------------- + + This will take the given area and populate it with rooftop stuff like + air conditioners or light towers. + +-----------------------------------------------------------------------------*/ + +void CBuilding::ConstructRoof (float left, float right, float front, float back, float bottom) +{ + + int air_conditioners; + int i; + int width, depth, height; + int face; + int addon; + int max_tiers; + float ac_x; + float ac_y; + float ac_base; + float ac_size; + float ac_height; + float tower_height; + float logo_offset; + CDeco* d; + GLvector2 start, end; + + _roof_tiers++; + max_tiers = _height / 10; + width = (int)(right - left); + depth = (int)(back - front); + height = 5 - _roof_tiers; + logo_offset = 0.2f; + //See if this building is special and worthy of fancy roof decorations. + if (bottom > 35.0f) + addon = RandomVal (ADDON_COUNT); + //Build the roof slab + ConstructCube (left, right, front, back, bottom, bottom + (float)height); + //Consider putting a logo on the roof, if it's tall enough + if (addon == ADDON_LOGO && !_have_logo) { + d = new CDeco; + if (width > depth) + face = COIN_FLIP ? NORTH : SOUTH; + else + face = COIN_FLIP ? EAST : WEST; + switch (face) { + case NORTH: + start = glVector ((float)left, (float)back + logo_offset); + end = glVector ((float)right, (float)back + logo_offset); + break; + case SOUTH: + start = glVector ((float)right, (float)front - logo_offset); + end = glVector ((float)left, (float)front - logo_offset); + break; + case EAST: + start = glVector ((float)right + logo_offset, (float)back); + end = glVector ((float)right + logo_offset, (float)front); + break; + case WEST: + default: + start = glVector ((float)left - logo_offset, (float)front); + end = glVector ((float)left - logo_offset, (float)back); + break; + } + d->CreateLogo (start, end, bottom, WorldLogoIndex (), _trim_color); + _have_logo = true; + } else if (addon == ADDON_TRIM) { + d = new CDeco; + vector_buffer[0] = glVector (left, bottom, back); + vector_buffer[1] = glVector (left, bottom, front); + vector_buffer[2] = glVector (right, bottom, front); + vector_buffer[3] = glVector (right, bottom, back); + d->CreateLightTrim (vector_buffer, 4, (float)RandomVal (2) + 1.0f, _seed, _trim_color); + } else if (addon == ADDON_LIGHTS && !_have_lights) { + new CLight (glVector (left, (float)(bottom + 2), front), _trim_color, 2); + new CLight (glVector (right, (float)(bottom + 2), front), _trim_color, 2); + new CLight (glVector (right, (float)(bottom + 2), back), _trim_color, 2); + new CLight (glVector (left, (float)(bottom + 2), back), _trim_color, 2); + _have_lights = true; + } + bottom += (float)height; + //If the roof is big enough, consider making another layer + if (width > 7 && depth > 7 && _roof_tiers < max_tiers) { + ConstructRoof (left + 1, right - 1, front + 1, back - 1, bottom); + return; + } + //1 air conditioner block for every 15 floors sounds reasonble + air_conditioners = _height / 15; + for (i = 0; i < air_conditioners; i++) { + ac_size = (float)(10 + RandomVal (30)) / 10; + ac_height = (float)RandomVal (20) / 10 + 1.0f; + ac_x = left + (float)RandomVal (width); + ac_y = front + (float)RandomVal (depth); + //make sure the unit doesn't hang off the right edge of the building + if (ac_x + ac_size > (float)right) + ac_x = (float)right - ac_size; + //make sure the unit doesn't hang off the back edge of the building + if (ac_y + ac_size > (float)back) + ac_y = (float)back - ac_size; + ac_base = (float)bottom; + //make sure it doesn't hang off the edge + ConstructCube (ac_x, ac_x + ac_size, ac_y, ac_y + ac_size, ac_base, ac_base + ac_height); + } + + if (_height > 45) { + d = new CDeco; + tower_height = (float)(12 + RandomVal (8)); + d->CreateRadioTower (glVector ((float)(left + right) / 2.0f, (float)bottom, (float)(front + back) / 2.0f), 15.0f); + } + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::ConstructSpike (int left, int right, int front, int back, int bottom, int top) +{ + + GLvertex p; + int index_list[6]; + int i; + GLvector center; + + for (i = 0; i < 5; i++) + index_list[i] = _mesh_flat->VertexCount () + i; + index_list[5] = index_list[1]; + p.uv = glVector (0.0f, 0.0f); + center.x = ((float)left + (float)right) / 2.0f; + center.z = ((float)front + (float)back) / 2.0f; + p.position = glVector (center.x, (float)top, center.z); + _mesh_flat->VertexAdd (p); + + p.position = glVector ((float)left, (float)bottom, (float)back); + _mesh_flat->VertexAdd (p); + + p.position = glVector ((float)right, (float)bottom, (float)back); + _mesh_flat->VertexAdd (p); + + p.position = glVector ((float)right, (float)bottom, (float)front); + _mesh_flat->VertexAdd (p); + + p.position = glVector ((float)left, (float)bottom, (float)front); + _mesh_flat->VertexAdd (p); + + _mesh_flat->FanAdd (&index_list[0], 6); + +} + +/*----------------------------------------------------------------------------- + + This builds an outer wall of a building, with blank (windowless) areas + deliberately left. It creates a chain of segments that alternate + between windowed and windowless, and it always makes sure the wall + is symetrical. window_groups tells it how many windows to place in a row. + +-----------------------------------------------------------------------------*/ + +float CBuilding::ConstructWall (int start_x, int start_y, int start_z, int direction, int length, int height, int window_groups, float uv_start, bool blank_corners) +{ + + int x, z; + int step_x, step_z; + int i; + int index_list[100]; + int current_index; + int column; + int mid; + int odd; + GLvertex v; + bool blank; + bool last_blank; + + switch (direction) { + case NORTH: + step_z = 1; step_x = 0; break; + case WEST: + step_z = 0; step_x = -1; break; + case SOUTH: + step_z = -1; step_x = 0; break; + case EAST: + step_z = 0; step_x = 1; break; + } + x = start_x;; + z = start_z; + current_index = 0; + mid = (length / 2) - 1; + odd = 1 - (length % 2); + if (length % 2) + mid++; + //mid = (length / 2); + v.uv.x = (float)(x + z) / SEGMENTS_PER_TEXTURE; + v.uv.x = uv_start; + blank = false; + for (i = 0; i <= length; i++) { + //column counts up to the mid point, then back down, to make it symetrical + if (i <= mid) + column = i - odd; + else + column = (mid) - (i - (mid)); + last_blank = blank; + blank = (column % window_groups) > window_groups / 2; + if (blank_corners && i == 0) + blank = true; + if (blank_corners && i == (length - 1)) + blank = true; + if (last_blank != blank || i == 0 || i == length) { + v.position = glVector ((float)x, (float)start_y, (float)z); + v.uv.y = (float)start_y / SEGMENTS_PER_TEXTURE; + _mesh->VertexAdd (v); + index_list[current_index] = _mesh->VertexCount () - 1; + current_index++; + v.position.y = (float)(start_y + height); + v.uv.y = (float)(start_y + height) / SEGMENTS_PER_TEXTURE;; + _mesh->VertexAdd (v); + index_list[current_index] = _mesh->VertexCount () - 1; + current_index++; + } + //if (!blank && i != 0 && i != (length - 1)) + if (!blank && i != length) + v.uv.x += 1.0f / SEGMENTS_PER_TEXTURE; + x += step_x; + z += step_z; + } + _mesh->QuadStripAdd (&index_list[0], current_index); + return v.uv.x; + +} + +static int maxt; + +/*----------------------------------------------------------------------------- + + This makes a big chunky building of intersecting cubes. + +-----------------------------------------------------------------------------*/ + +void CBuilding::CreateBlocky () +{ + + int min_height; + int left, right, front, back; + int max_left, max_right, max_front, max_back; + int height; + int mid_x, mid_z; + int half_depth, half_width; + int tiers; + int max_tiers; + int grouping; + float lid_height; + float uv_start; + bool skip; + bool blank_corners; + + //Choose if the corners of the building are to be windowless. + blank_corners = COIN_FLIP; + //Choose a random column on our texture; + uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE; + //Choose how the windows are grouped + grouping = 2 + RandomVal (4); + //Choose how tall the lid should be on top of each section + lid_height = (float)(RandomVal (3) + 1); + //find the center of the building. + mid_x = _x + _width / 2; + mid_z = _y + _depth / 2; + max_left = max_right = max_front = max_back = 1; + height = _height; + min_height = _height / 2; + min_height = 3; + half_depth = _depth / 2; + half_width = _width / 2; + tiers = 0; + if (_height > 40) + max_tiers = 15; + else if (_height > 30) + max_tiers = 10; + else if (_height > 20) + max_tiers = 5; + else if (_height > 10) + max_tiers = 2; + else + max_tiers = 1; + max_tiers = MIN (maxt, max_tiers); + maxt++; + maxt %= 8; + //We begin at the top of the building, and work our way down. + //Viewed from above, the sections of the building are randomly sized + //rectangles that ALWAYS include the center of the building somewhere within + //their area. + while (1) { + if (height < min_height) + break; + if (tiers >= max_tiers) + break; + //pick new locationsfor our four outer walls + left = (RandomVal () % half_width) + 1; + right = (RandomVal () % half_width) + 1; + front = (RandomVal () % half_depth) + 1; + back = (RandomVal () % half_depth) + 1; + skip = false; + //At least ONE of the walls must reach out beyond a previous maximum. + //Otherwise, this tier would be completely hidden within a previous one. + if (left <= max_left && right <= max_right && front <= max_front && back <= max_back) + skip = true; + //If any of the four walls is in the same position as the previous max,then + //skip this tier, or else the two walls will end up z-fightng. + if (left == max_left || right == max_right || front == max_front || back == max_back) + skip = true; + if (!skip) { + //if this is the top, then put some lights up here + max_left = MAX (left, max_left); + max_right = MAX (right, max_right); + max_front = MAX (front, max_front); + max_back = MAX (back, max_back); + //Now build the four walls of this part + uv_start = ConstructWall (mid_x - left, 0, mid_z + back, SOUTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (mid_x - left, 0, mid_z - front, EAST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (mid_x + right, 0, mid_z - front, NORTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (mid_x + right, 0, mid_z + back, WEST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + if (!tiers) + ConstructRoof ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height); + else //add a flat-color lid onto this section + ConstructCube ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height, (float)height + lid_height); + height -= (RandomVal () % 10) + 1; + tiers++; + } + height--; + } + ConstructCube (mid_x - half_width, mid_x + half_width, mid_z - half_depth, mid_z + half_depth, 0, 2); + _mesh->Compile (); + _mesh_flat->Compile (); + +} + +/*----------------------------------------------------------------------------- + + A single-cube building. Good for low-rise buildings and stuff that will be + far from the camera; + +-----------------------------------------------------------------------------*/ + +void CBuilding::CreateSimple () +{ + + GLvertex p; + float x1, x2, z1, z2, y1, y2; + int index_list[] = {0,1,2,3,4,5,6,7,8,9,10}; + float u, v1, v2; + float cap_height; + float ledge; + + //How tall the flat-color roof is + cap_height = (float)(1 + RandomVal (4)); + //how much the ledge sticks out + ledge = (float)RandomVal (10) / 30.0f; + + x1 = (float)_x; + x2 = (float)(_x + _width); + y1 = (float)0.0f; + y2 = (float)_height; + z2 = (float)_y; + z1 = (float)(_y + _depth); + + u = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE; + v1 = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE; + v2 = v1 + (float)_height * ONE_SEGMENT; + + p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + u += (float)_depth / SEGMENTS_PER_TEXTURE; + + p.position = glVector (x1, y1, z2); p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + p.position = glVector (x1, y2, z2); p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + u += (float)_width / SEGMENTS_PER_TEXTURE; + + p.position = glVector (x2, y1, z2); p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + p.position = glVector (x2, y2, z2); p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + u += (float)_depth / SEGMENTS_PER_TEXTURE; + + p.position = glVector (x2, y1, z1); p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + p.position = glVector (x2, y2, z1); p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + u += (float)_depth / SEGMENTS_PER_TEXTURE; + + p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + + _mesh->QuadStripAdd (index_list, 10); + ConstructCube (x1 - ledge, x2 + ledge, z2 - ledge, z1 + ledge, (float)_height, (float)_height + cap_height); + _mesh->Compile (); + +} + +/*----------------------------------------------------------------------------- + + This makes a deformed cylinder building. + +-----------------------------------------------------------------------------*/ + +void CBuilding::CreateModern () +{ + + GLvertex p; + GLvector center; + GLvector pos; + GLvector2 radius; + GLvector2 start, end; + int angle; + int windows; + int cap_height; + int half_depth, half_width; + float dist; + float length; + int* index_list; + int points; + int skip_interval; + int skip_counter; + int skip_delta; + bool logo_done; + bool do_trim; + CDeco* d; + + logo_done = false; + //How tall the windowless section on top will be. + cap_height = 1 + RandomVal (5); + //How many 10-degree segments to build before the next skip. + skip_interval = 1 + RandomVal (8); + //When a skip happens, how many degrees should be skipped + skip_delta = (1 + RandomVal (2)) * 30; //30 60 or 90 + //See if this is eligible for fancy lighting trim on top + if (_height > 48 && RandomVal (3) == 0) + do_trim = true; + else + do_trim = false; + //Get the center and radius of the circle + half_depth = _depth / 2; + half_width = _width / 2; + center = glVector ((float)(_x + half_width), 0.0f, (float)(_y + half_depth)); + radius = glVector ((float)half_width, (float)half_depth); + dist = 0; + windows = 0; + p.uv.x = 0.0f; + points = 0; + skip_counter = 0; + for (angle = 0; angle <= 360; angle += 10) { + if (skip_counter >= skip_interval && (angle + skip_delta < 360)) { + angle += skip_delta; + skip_counter = 0; + } + pos.x = center.x - sinf ((float)angle * DEGREES_TO_RADIANS) * radius.x; + pos.z = center.z + cosf ((float)angle * DEGREES_TO_RADIANS) * radius.y; + if (angle > 0 && skip_counter == 0) { + length = MathDistance (p.position.x, p.position.z, pos.x, pos.z); + windows += (int)length; + if (length > 10 && !logo_done) { + logo_done = true; + start = glVector (pos.x, pos.z); + end = glVector (p.position.x, p.position.z); + d = new CDeco; + d->CreateLogo (start, end, (float)_height, WorldLogoIndex (), RANDOM_COLOR); + } + } else if (skip_counter != 1) + windows++; + p.position = pos; + p.uv.x = (float)windows / (float)SEGMENTS_PER_TEXTURE; + p.uv.y = 0.0f; + p.position.y = 0.0f; + _mesh->VertexAdd (p); + p.position.y = (float)_height; + p.uv.y = (float)_height / (float)SEGMENTS_PER_TEXTURE; + _mesh->VertexAdd (p); + _mesh_flat->VertexAdd (p); + p.position.y += (float)cap_height; + _mesh_flat->VertexAdd (p); + vector_buffer[points / 2] = p.position; + vector_buffer[points / 2].y = (float)_height + cap_height / 4; + points += 2; + skip_counter++; + } + //if this is a big building and it didn't get a logo, consider giving it a light strip + if (!logo_done && do_trim) { + d = new CDeco; + d->CreateLightTrim (vector_buffer, (points / 2) - 2, (float)cap_height / 2, _seed, RANDOM_COLOR); + } + index_list = new int[points]; + //Add the outer walls + for (int i = 0; i < points; i++) + index_list[i] = i; + _mesh->QuadStripAdd (index_list, points); + _mesh_flat->QuadStripAdd (index_list, points); + //add the fan to cap the top of the buildings + for (i = 0; i < points / 2; i++) + index_list[i + 1] = points - (1 + i * 2); + p.position.x = _center.x; + p.position.z = _center.z; + _mesh_flat->VertexAdd (p); + index_list[0] = points; + _mesh_flat->FanAdd (index_list, 1 + points / 2); + delete index_list; + radius /= 2.0f; + //ConstructRoof ((int)(_center.x - radius), (int)(_center.x + radius), (int)(_center.z - radius), (int)(_center.z + radius), _height + cap_height); + _mesh->Compile (); + _mesh_flat->Compile (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CBuilding::CreateTower () +{ + + int left, right, front, back, bottom; + int section_height, section_width, section_depth; + int remaining_height; + int ledge_height; + int tier_fraction; + int grouping; + int foundation; + float ledge; + float uv_start; + bool blank_corners; + bool roof_spike; + bool narrowing; + bool tower; + + //How much ledges protrude from the building + ledge = (float)RandomVal (3) * 0.25f; + //How tall the ledges are, in stories + ledge_height = RandomVal (3) + 1; + //How the windows are grouped + grouping = RandomVal (3) + 2; + //if the corners of the building have no windows + blank_corners = COIN_FLIP; + //if the roof is pointed or has infrastructure on it + roof_spike = RandomVal (3) == 0; + //What fraction of the remaining height should be given to each tier + tier_fraction = 2 + RandomVal (3); + //Does the tower get narrower towards the top? + narrowing = RandomVal (3) == 0; + //The height of the windowsless slab at the bottom + foundation = 2 + RandomVal (3); + //The odds that we'll have a big fancy spikey top + tower = RandomVal (5) != 0 && _height > 40; + //set our initial parameters + left = _x; + right = _x + _width; + front = _y; + back = _y + _depth; + bottom = 0; + //build the foundations. + ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)foundation); + bottom += foundation; + //now add tiers until we reach the top + while (1) { + remaining_height = _height - bottom; + section_depth = back - front; + section_width = right - left; + section_height = MAX (remaining_height / tier_fraction, 2); + if (remaining_height < 10) + section_height = remaining_height; + //Build the four walls + uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE; + uv_start = ConstructWall (left, bottom, back, SOUTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (left, bottom, front, EAST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (right, bottom, front, NORTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + uv_start = ConstructWall (right, bottom, back, WEST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; + bottom += section_height; + //Build the slab / ledges to cap this section. + if (bottom + ledge_height > _height) + break; + ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)(bottom + ledge_height)); + bottom += ledge_height; + if (bottom > _height) + break; + if (ledge_height > 1 && narrowing) + ledge_height--; + if (narrowing) { + if (section_width > 7) { + left+=1; + right-=1; + } + if (section_depth > 7) { + front+=1; + back-=1; + } + } + } + ConstructRoof ((float)left, (float)right, (float)front, (float)back, (float)bottom); + _mesh->Compile (); + _mesh_flat->Compile (); + +} + diff --git a/Building.h b/Building.h new file mode 100644 index 0000000..db0ff80 --- /dev/null +++ b/Building.h @@ -0,0 +1,53 @@ +#ifndef ENTITY +#include "entity.h" +#endif + +enum +{ + BUILDING_SIMPLE, + BUILDING_BLOCKY, + BUILDING_MODERN, + BUILDING_TOWER +}; + +class CBuilding : public CEntity +{ +private: + + int _x; + int _y; + int _width; + int _depth; + int _height; + int _texture_type; + int _seed; + int _roof_tiers; + GLrgba _color; + GLrgba _trim_color; + class CMesh* _mesh; + class CMesh* _mesh_flat; + bool _have_lights; + bool _have_trim; + bool _have_logo; + + + void CreateSimple (); + void CreateBlocky (); + void CreateModern (); + void CreateTower (); + + float ConstructWall (int start_x, int start_y, int start_z, int direction, int length, int height, int window_groups, float uv_start, bool blank_corners); + void ConstructSpike (int left, int right, int front, int back, int bottom, int top); + void ConstructCube (int left, int right, int front, int back, int bottom, int top); + void ConstructCube (float left, float right, float front, float back, float bottom, float top); + void ConstructRoof (float left, float right, float front, float back, float bottom); + +public: + CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color); + ~CBuilding (); + void Render (void); + int PolyCount (); + void RenderFlat (bool colored); + unsigned Texture (); + +}; diff --git a/Camera.cpp b/Camera.cpp new file mode 100644 index 0000000..b2900d9 --- /dev/null +++ b/Camera.cpp @@ -0,0 +1,403 @@ +/*----------------------------------------------------------------------------- + + Camera.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This tracks the position and oritentation of the camera. In screensaver + mode, it moves the camera around the world in order to create dramatic + views of the hot zone. + +-----------------------------------------------------------------------------*/ + +#define EYE_HEIGHT 2.0f +#define MAX_PITCH 85 +#define FLYCAM_CIRCUT 60000 +#define FLYCAM_CIRCUT_HALF (FLYCAM_CIRCUT / 2) +#define FLYCAM_LEG (FLYCAM_CIRCUT / 4) +#define ONE_SECOND 1000 +#define CAMERA_CHANGE_INTERVAL 15 +#define CAMERA_CYCLE_LENGTH (CAMERA_MODES*CAMERA_CHANGE_INTERVAL) + +#include +#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 float movement; +static bool moving; +static bool cam_auto; +static float tracker; +static unsigned last_update; +static int camera_behavior; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + + +static GLvector flycam_position (unsigned t) +{ + + unsigned leg; + float delta; + GLvector start, end; + GLbbox hot_zone; + + hot_zone = WorldHotZone (); + t %= FLYCAM_CIRCUT; + leg = t / FLYCAM_LEG; + delta = (float)(t % FLYCAM_LEG) / FLYCAM_LEG; + switch (leg) { + case 0: + start = glVector (hot_zone.min.x, 25.0f, hot_zone.min.z); + end = glVector (hot_zone.min.x, 60.0f, hot_zone.max.z); + break; + case 1: + start = glVector (hot_zone.min.x, 60.0f, hot_zone.max.z); + end = glVector (hot_zone.max.x, 25.0f, hot_zone.max.z); + break; + case 2: + start = glVector (hot_zone.max.x, 25.0f, hot_zone.max.z); + end = glVector (hot_zone.max.x, 60.0f, hot_zone.min.z); + break; + case 3: + start = glVector (hot_zone.max.x, 60.0f, hot_zone.min.z); + end = glVector (hot_zone.min.x, 25.0f, hot_zone.min.z); + break; + } + delta = MathScalarCurve (delta); + return glVectorInterpolate (start, end, delta); + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void do_auto_cam () +{ + + float dist; + unsigned t; + unsigned elapsed; + unsigned now; + int behavior; + GLvector target; + + now = GetTickCount (); + elapsed = now - last_update; + elapsed = MIN (elapsed, 1000); //limit to 1 second worth of time + if (elapsed == 0) + return; + last_update = now; + t = time (NULL) % CAMERA_CYCLE_LENGTH; +#if SCREENSAVER + behavior = t / CAMERA_CHANGE_INTERVAL; +#else + behavior = camera_behavior; +#endif + tracker += (float)elapsed / 100.0f; + //behavior = CAMERA_FLYCAM1; + switch (behavior) { + case CAMERA_ORBIT_INWARD: + auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 150.0f; + auto_position.y = 60.0f; + auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 150.0f; + target = glVector (WORLD_HALF, 40.0f, WORLD_HALF); + break; + case CAMERA_ORBIT_OUTWARD: + auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 250.0f; + auto_position.y = 60.0f; + auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 250.0f; + target = glVector (WORLD_HALF, 30.0f, WORLD_HALF); + break; + case CAMERA_ORBIT_ELLIPTICAL: + dist = 150.0f + sinf (tracker * DEGREES_TO_RADIANS / 1.1f) * 50; + auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * dist; + auto_position.y = 60.0f; + auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * dist; + target = glVector (WORLD_HALF, 50.0f, WORLD_HALF); + break; + case CAMERA_FLYCAM1: + case CAMERA_FLYCAM2: + case CAMERA_FLYCAM3: + auto_position = (flycam_position (now) + flycam_position (now + 4000)) / 2.0f; + target = flycam_position (now + FLYCAM_CIRCUT_HALF - ONE_SECOND * 3); + break; + case CAMERA_SPEED: + auto_position = (flycam_position (now) + flycam_position (now + 500)) / 2.0f; + target = flycam_position (now + ONE_SECOND * 5); + auto_position.y /= 2; + target.y /= 2; + break; + case CAMERA_SPIN: + default: + target.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 300.0f; + target.y = 30.0f; + target.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 300.0f; + auto_position.x = WORLD_HALF + sinf (tracker * DEGREES_TO_RADIANS) * 50.0f; + auto_position.y = 60.0f; + auto_position.z = WORLD_HALF + cosf (tracker * DEGREES_TO_RADIANS) * 50.0f; + } + dist = MathDistance (auto_position.x, auto_position.z, target.x, target.z); + auto_angle.y = MathAngle (-MathAngle (auto_position.x, auto_position.z, target.x, target.z)); + auto_angle.x = 90.0f + MathAngle (0, auto_position.y, dist, target.y); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraAutoToggle () +{ + + cam_auto = !cam_auto; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraNextBehavior () +{ + + camera_behavior++; + camera_behavior %= CAMERA_MODES; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraYaw (float delta) +{ + + moving = true; + angle.y -= delta; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraPitch (float delta) +{ + + moving = true; + angle.x -= delta; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraPan (float delta) +{ + + float move_x, move_y; + + moving = true; + move_x = (float)sin (-angle.y * DEGREES_TO_RADIANS) / 10.0f; + move_y = (float)cos (-angle.y * DEGREES_TO_RADIANS) / 10.0f; + position.x -= move_y * delta; + position.z -= -move_x * delta; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraForward (float delta) +{ + + float move_x, move_y; + + moving = true; + move_y = (float)sin (-angle.y * DEGREES_TO_RADIANS) / 10.0f; + move_x = (float)cos (-angle.y * DEGREES_TO_RADIANS) / 10.0f; + position.x -= move_y * delta; + position.z -= move_x * delta; + +} + + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraSelectionPitch (float delta) +{ + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraSelectionZoom (float delta) +{ + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraSelectionYaw (float delta) +{ + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector CameraPosition (void) +{ + + if (cam_auto) + return auto_position; + return position; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraReset () +{ + + position.y = 50.0f; + position.x = WORLD_HALF; + position.z = WORLD_HALF; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraPositionSet (GLvector new_pos) +{ + + position = new_pos; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector CameraAngle (void) +{ + + if (cam_auto) + return auto_angle; + return angle; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraAngleSet (GLvector new_angle) +{ + + angle = new_angle; + angle.x = CLAMP (angle.x, -80.0f, 80.0f); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraInit (void) +{ + + angle = IniVector ("CameraAngle"); + position = IniVector ("CameraPosition"); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraUpdate (void) +{ + +#if SCREENSAVER + cam_auto = true; +#endif + if (cam_auto) + do_auto_cam (); + if (moving) + movement *= 1.1f; + else + movement = 0.0f; + movement = CLAMP (movement, 0.01f, 1.0f); + + if (angle.y < 0.0f) + angle.y = 360.0f - (float)fmod (fabs (angle.y), 360.0f); + angle.y = (float)fmod (angle.y, 360.0f); + angle.x = CLAMP (angle.x, -MAX_PITCH, MAX_PITCH); + moving = false; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CameraTerm (void) +{ + + //just store our most recent position in the ini + IniVectorSet ("CameraAngle", angle); + IniVectorSet ("CameraPosition", position); + +} diff --git a/Camera.h b/Camera.h new file mode 100644 index 0000000..8302cb3 --- /dev/null +++ b/Camera.h @@ -0,0 +1,24 @@ +#ifndef TYPES +#include "glTypes.h" +#endif + +GLvector CameraAngle (void); +void CameraAngleSet (GLvector new_angle); +void CameraAutoToggle (); +float CameraDistance (void); +void CameraDistanceSet (float new_distance); +void CameraInit (void); +void CameraNextBehavior (void); +GLvector CameraPosition (void); +void CameraPositionSet (GLvector new_pos); +void CameraReset (); +void CameraUpdate (void); +void CameraTerm (void); + +void CameraForward (float delta); +void CameraSelectionPitch (float delta_y); +void CameraSelectionYaw (float delta_x); +void CameraSelectionZoom (float delta_y); +void CameraPan (float delta_x); +void CameraPitch (float delta_y); +void CameraYaw (float delta_x); diff --git a/Car.cpp b/Car.cpp new file mode 100644 index 0000000..d67e69c --- /dev/null +++ b/Car.cpp @@ -0,0 +1,322 @@ +/*----------------------------------------------------------------------------- + + Car.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This creates the little two-triangle cars and moves them around the map. + +-----------------------------------------------------------------------------*/ + +#define DEAD_ZONE 200 +#define STUCK_TIME 230 +#define UPDATE_INTERVAL 50 //milliseconds +#define MOVEMENT_SPEED 0.61f +#define CAR_SIZE 3.0f + +#include +#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" + +static GLvector direction[] = +{ + 0.0f, 0.0f, -1.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + -1.0f, 0.0f, 0.0f, +}; + +static int dangles[] = { 0, 90, 180, 270}; + +static GLvector2 angles[360]; +static bool angles_done; +static unsigned char carmap[WORLD_SIZE][WORLD_SIZE]; +static CCar* head; +static unsigned next_update; +static int count; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int CarCount () +{ + + return count; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CarClear () +{ + + CCar* c; + + for (c = head; c; c = c->m_next) + c->Park (); + ZeroMemory (carmap, sizeof (carmap)); + count = 0; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CarRender () +{ + + CCar* c; + + if (!angles_done) { + for (int i = 0 ;i < 360; i++) { + angles[i].x = cosf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE; + angles[i].y = sinf ((float)i * DEGREES_TO_RADIANS) * CAR_SIZE; + } + } + glDepthMask (false); + glEnable (GL_BLEND); + glDisable (GL_CULL_FACE); + glBlendFunc (GL_ONE, GL_ONE); + glBindTexture (GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_HEADLIGHT)); + for (c = head; c; c = c->m_next) + c->Render (); + glDepthMask (true); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CarUpdate () +{ + + CCar* c; + unsigned now; + + if (!TextureReady () || !EntityReady ()) + return; + now = GetTickCount (); + if (next_update > now) + return; + next_update = now + UPDATE_INTERVAL; + for (c = head; c; c = c->m_next) + c->Update (); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CCar::CCar () +{ + + m_ready = false; + m_next = head; + head = this; + count++; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool CCar::TestPosition (int row, int col) +{ + + //test the given position and see if it's already occupied + if (carmap[row][col]) + return false; + //now make sure that the lane is going the right direction + if (WorldCell (row, col) != WorldCell (m_row, m_col)) + return false; + return true; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CCar::Update (void) +{ + + int new_row, new_col; + GLvector old_pos; + GLvector camera; + + //If the car isn't ready, place it on the map and get it moving + camera = CameraPosition (); + if (!m_ready) { + //if the car isn't ready, we need to place it somewhere on the map + m_row = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2); + m_col = DEAD_ZONE + RandomVal (WORLD_SIZE - DEAD_ZONE * 2); + //if there is already a car here, forget it. + if (carmap[m_row][m_col] > 0) + return; + //if this spot is not a road, forget it + if (!(WorldCell (m_row, m_col) & CLAIM_ROAD)) + return; + if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col))) + return; + //good spot. place the car + m_position = glVector ((float)m_row, 0.1f, (float)m_col); + m_drive_position = m_position; + m_ready = true; + if (WorldCell (m_row, m_col) & MAP_ROAD_NORTH) + m_direction = NORTH; + if (WorldCell (m_row, m_col) & MAP_ROAD_EAST) + m_direction = EAST; + if (WorldCell (m_row, m_col) & MAP_ROAD_SOUTH) + m_direction = SOUTH; + if (WorldCell (m_row, m_col) & MAP_ROAD_WEST) + m_direction = WEST; + m_drive_angle = dangles[m_direction]; + m_max_speed = (float)(4 + RandomVal (6)) / 10.0f; + m_speed = 0.0f; + m_change = 3; + m_stuck = 0; + carmap[m_row][m_col]++; + } + //take the car off the map and move it + carmap[m_row][m_col]--; + old_pos = m_position; + m_speed += m_max_speed * 0.05f; + m_speed = MIN (m_speed, m_max_speed); + m_position += direction[m_direction] * MOVEMENT_SPEED * m_speed; + //If the car has moved out of view, there's no need to keep simulating it. + if (!Visible (glVector ((float)m_row, 0.0f, (float)m_col))) + m_ready = false; + //if the car is far away, remove it. We use manhattan units because buildings almost always + //block views of cars on the diagonal. + if (fabs (camera.x - m_position.x) + fabs (camera.z - m_position.z) > RenderFogDistance ()) + m_ready = false; + //if the car gets too close to the edge of the map, take it out of play + if (m_position.x < DEAD_ZONE || m_position.x > (WORLD_SIZE - DEAD_ZONE)) + m_ready = false; + if (m_position.z < DEAD_ZONE || m_position.z > (WORLD_SIZE - DEAD_ZONE)) + m_ready = false; + if (m_stuck >= STUCK_TIME) + m_ready = false; + if (!m_ready) + return; + //Check the new position and make sure its not in another car + new_row = (int)m_position.x; + new_col = (int)m_position.z; + if (new_row != m_row || new_col != m_col) { + //see if the new position places us on top of another car + if (carmap[new_row][new_col]) { + m_position = old_pos; + m_speed = 0.0f; + m_stuck++; + } else { + //look at the new position and decide if we're heading towards or away from the camera + m_row = new_row; + m_col = new_col; + m_change--; + m_stuck = 0; + if (m_direction == NORTH) + m_front = camera.z < m_position.z; + else if (m_direction == SOUTH) + m_front = camera.z > m_position.z; + else if (m_direction == EAST) + m_front = camera.x > m_position.x; + else + m_front = camera.x < m_position.x; + } + } + m_drive_position = (m_drive_position + m_position) / 2.0f; + //place the car back on the map + carmap[m_row][m_col]++; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CCar::Render () +{ + + GLvector pos; + int angle; + int turn; + + if (!m_ready) + return; + if (!Visible (m_drive_position)) + return; + if (m_front) + glColor3f (1, 1, 0.8f); + else + glColor3f (1, 0.2f, 0); + + glBegin (GL_QUADS); + + angle = dangles[m_direction]; + pos = m_drive_position;// + angle = 360 - (int)MathAngle (m_position.x, m_position.z, pos.x, pos.z); + angle %= 360; + turn = (int)MathAngleDifference ((float)m_drive_angle, (float)angle); + m_drive_angle += SIGN (turn); + pos += glVector (0.5f, 0.0f, 0.5f); + + + glTexCoord2f (0, 0); + glVertex3f (pos.x + angles[angle].x, -CAR_SIZE, pos.z + angles[angle].y); + glTexCoord2f (1, 0); + glVertex3f (pos.x - angles[angle].x, -CAR_SIZE, pos.z - angles[angle].y); + glTexCoord2f (1, 1); + glVertex3f (pos.x - angles[angle].x, CAR_SIZE, pos.z - angles[angle].y); + glTexCoord2f (0, 1); + glVertex3f (pos.x + angles[angle].x, CAR_SIZE, pos.z + angles[angle].y); + + + /* + glVertex3f (m_position.x, m_position.y, m_position.z); + glVertex3f (m_position.x, m_position.y, m_position.z + 1); + glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1); + glVertex3f (m_position.x + 1, m_position.y, m_position.z); +*/ + /* + glTexCoord2f (0, 0); + glVertex3f (m_position.x, m_position.y, m_position.z + 0.2f); + glTexCoord2f (0, 2); + glVertex3f (m_position.x, m_position.y, m_position.z + 1 - 0.2f); + glTexCoord2f (1, 2); + glVertex3f (m_position.x + 1, m_position.y, m_position.z + 1 - 0.2f); + glTexCoord2f (1, 0); + glVertex3f (m_position.x + 1, m_position.y, m_position.z + 0.2f); + +*/ + + glEnd (); + +} \ No newline at end of file diff --git a/Car.h b/Car.h new file mode 100644 index 0000000..47529bd --- /dev/null +++ b/Car.h @@ -0,0 +1,30 @@ +class CCar +{ + GLvector m_position; + GLvector m_drive_position; + bool m_ready; + bool m_front; + int m_drive_angle; + int m_row; + int m_col; + int m_direction; + int m_change; + int m_stuck; + float m_speed; + float m_max_speed; + +public: + CCar (); + bool TestPosition (int row, int col); + void Render (); + void Update (); + void Park () { m_ready = false;} + class CCar* m_next; + +}; + +void CarClear (); +int CarCount (); +void CarRender (); +void CarUpdate (); + diff --git a/Deco.cpp b/Deco.cpp new file mode 100644 index 0000000..9511fc6 --- /dev/null +++ b/Deco.cpp @@ -0,0 +1,285 @@ +/*----------------------------------------------------------------------------- + + Deco.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This handles building and rendering decoration objects - infrastructure & + such around the city. + +-----------------------------------------------------------------------------*/ + +#define LOGO_OFFSET 0.2f //How far a logo sticks out from the given surface + +#include +#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 () +{ + + _mesh = new CMesh (); + _use_alpha = false; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::Render () +{ + + glColor3fv (&_color.red); + _mesh->Render (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::RenderFlat (bool colored) +{ + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool CDeco::Alpha () +{ + + return _use_alpha; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int CDeco::PolyCount () +{ + + return _mesh->PolyCount (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +unsigned CDeco::Texture () +{ + + return _texture; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::CreateRadioTower (GLvector pos, float height) +{ + + CLight* l; + float offset; + GLvertex v; + int index_list[] = {0,1,2,3,4,5}; + + offset = height / 15.0f; + _center = pos; + _use_alpha = true; + //Radio tower + v.position = glVector (_center.x, _center.y + height, _center.z); v.uv = glVector (0,1); + _mesh->VertexAdd (v); + v.position = glVector (_center.x - offset, _center.y, _center.z - offset); v.uv = glVector (1,0); + _mesh->VertexAdd (v); + v.position = glVector (_center.x + offset, _center.y, _center.z - offset); v.uv = glVector (0,0); + _mesh->VertexAdd (v); + v.position = glVector (_center.x + offset, _center.y, _center.z + offset); v.uv = glVector (1,0); + _mesh->VertexAdd (v); + v.position = glVector (_center.x - offset, _center.y, _center.z + offset); v.uv = glVector (0,0); + _mesh->VertexAdd (v); + v.position = glVector (_center.x - offset, _center.y, _center.z - offset); v.uv = glVector (1,0); + _mesh->VertexAdd (v); + _mesh->FanAdd (&index_list[0], 6); + l = new CLight (glVector (_center.x, _center.y + height + 1.0f, _center.z), glRgba (255,192,160), 1); + l->Blink (); + _texture = TextureId (TEXTURE_LATTICE); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::CreateLogo (GLvector2 start, GLvector2 end, float bottom, int seed, GLrgba color) +{ + + GLvertex p; + int index_list[] = {0,1,3,2}; + float u1, u2, v1, v2; + float top; + float height, length; + GLvector2 center2d; + GLvector to; + GLvector out; + int logo_index; + + _use_alpha = true; + _color = color; + logo_index = seed % LOGO_ROWS; + to = glVector (start.x, 0.0f, start.y) - glVector (end.x, 0.0f, end.y); + to = glVectorNormalize (to); + out = glVectorCrossProduct (glVector (0.0f, 1.0f, 0.0f), to) * LOGO_OFFSET; + center2d = (start + end) / 2; + _center = glVector (center2d.x, bottom, center2d.y); + length = glVectorLength (start - end); + height = (length / 8.0f) * 1.5f; + top = bottom + height; + u1 = 0.0f; + u2 = 0.5f;//We actually only use the left half of the texture + v1 = (float)logo_index / LOGO_ROWS; + v2 = v1 + (1.0f / LOGO_ROWS); + p.position = glVector (start.x, bottom, start.y) + out; p.uv = glVector (u1,v1); + _mesh->VertexAdd (p); + p.position = glVector (end.x, bottom, end.y) + out; p.uv = glVector (u2, v1); + _mesh->VertexAdd (p); + p.position = glVector (end.x, top, end.y) + out; p.uv = glVector (u2, v2); + _mesh->VertexAdd (p); + p.position = glVector (start.x, top, start.y) + out; p.uv = glVector (u1, v2); + _mesh->VertexAdd (p); + _mesh->QuadStripAdd (&index_list[0], 4); + _texture = TextureId (TEXTURE_LOGOS); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::CreateLightStrip (float x, float z, float width, float depth, float height, GLrgba color) +{ + + GLvertex p; + int index_list1[] = {0,1,3,2}; + int index_list2[] = {4,5,7,6}; + float u, v; + + _color = color; + _use_alpha = true; + _center = glVector (x + width / 2, height, z + depth / 2); + if (width < depth) { + u = 1.0f; + v = (float)((int)(depth / width)); + } else { + v = 1.0f; + u = (float)((int)(width / depth)); + } + //u = MAX (width, 1); + //v = MAX (depth, 1); + _texture = TextureId (TEXTURE_LIGHT); + p.position = glVector (x, height, z); p.uv = glVector (0.0f, 0.0f); + _mesh->VertexAdd (p); + p.position = glVector (x, height, z + depth); p.uv = glVector (0.0f, v); + _mesh->VertexAdd (p); + p.position = glVector (x + width, height, z + depth); p.uv = glVector (u, v); + _mesh->VertexAdd (p); + p.position = glVector (x + width, height, z); p.uv = glVector (u, 0.0f); + _mesh->VertexAdd (p); + + p.position = glVector (x - 1, height, z - 1); p.uv = glVector (0, 0); + _mesh->VertexAdd (p); + p.position = glVector (x - 1, height, z + depth + 1); p.uv = glVector (0, 1); + _mesh->VertexAdd (p); + p.position = glVector (x + width + 1, height, z + depth + 1); p.uv = glVector (1, 1); + _mesh->VertexAdd (p); + p.position = glVector (x + width + 1, height, z - 1); p.uv = glVector (1, 0); + _mesh->VertexAdd (p); + + _mesh->QuadStripAdd (&index_list1[0], 4); + //_mesh->QuadStripAdd (&index_list2[0], 4); + _mesh->Compile (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CDeco::CreateLightTrim (GLvector* chain, int count, float height, int seed, GLrgba color) +{ + + GLvertex p; + GLvector to; + GLvector out; + int i; + int index; + int prev, next; + float u, v1, v2; + float row; + int* index_list; + + _color = color; + _center = glVector (0.0f, 0.0f, 0.0f); + index_list = new int[count * 2 + 2]; + for (i = 0; i < count; i++) + _center += chain[i]; + _center /= (float)count; + row = (float)(seed % TRIM_ROWS); + v1 = row * TRIM_SIZE; + v2 = (row + 1.0f) * TRIM_SIZE; + index = 0; + u = 0.0f; + for (i = 0; i < count + 1; i++) { + if (i) + u += glVectorLength (chain[i % count] - p.position) * 0.1f; + //Add the bottom point + prev = i - 1; + if (prev < 0) + prev = count + prev; + next = (i + 1) % count; + to = glVectorNormalize (chain[next] - chain[prev]); + out = glVectorCrossProduct (glVector (0.0f, 1.0f, 0.0f), to) * LOGO_OFFSET; + p.position = chain[i % count] + out; p.uv = glVector (u, v2); + _mesh->VertexAdd (p); + index_list[index] = index; + index++; + //Top point + p.position.y += height;p.uv = glVector (u, v1); + _mesh->VertexAdd (p); + index_list[index] = index; + index++; + } + _mesh->QuadStripAdd (index_list, index); + delete index_list; + _texture = TextureId (TEXTURE_TRIM); + _mesh->Compile (); + + +} \ No newline at end of file diff --git a/Deco.h b/Deco.h new file mode 100644 index 0000000..01245ae --- /dev/null +++ b/Deco.h @@ -0,0 +1,28 @@ +#ifndef ENTITY +#include "entity.h" +#endif + +class CDeco : CEntity +{ +// CDeco* _next; + GLrgba _color; + class CMesh* _mesh; + int _type; + unsigned _texture; + bool _use_alpha; + +public: + + CDeco (); + void CreateLogo (GLvector2 start, GLvector2 end, float base, int seed, GLrgba color); + void CreateLightStrip (float x, float z, float width, float depth, float height, GLrgba color); + void CreateLightTrim (GLvector* chain, int count, float height, int seed, GLrgba color); + void CreateRadioTower (GLvector pos, float height); + void Render (void); + void RenderFlat (bool colored); + bool Alpha (); + int PolyCount (); + + unsigned Texture (); + +}; \ No newline at end of file diff --git a/Entity.cpp b/Entity.cpp new file mode 100644 index 0000000..87549a9 --- /dev/null +++ b/Entity.cpp @@ -0,0 +1,412 @@ +/*----------------------------------------------------------------------------- + + Entity.cpp + + Copyright (c) 2005 Shamus Young + All Rights Reserved + +------------------------------------------------------------------------------- + + An entity is any renderable stationary object in the world. This is an + abstract class. This module gathers up the Entities, sorts them by + texture use and location, and then stores them in OpenGL render lists + for faster rendering. + +-----------------------------------------------------------------------------*/ + +#include +#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" + +struct entity +{ + CEntity* object; +}; + + +struct cell +{ + unsigned list_textured; + unsigned list_flat; + unsigned list_flat_wireframe; + unsigned list_alpha; + GLvector pos; +}; + +static cell cell_list[GRID_SIZE][GRID_SIZE]; +static int entity_count; +static entity* entity_list; +static bool sorted; +static bool compiled; +static int polycount; +static int compile_x; +static int compile_y; +static int compile_count; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static int do_compare (const void *arg1, const void *arg2 ) +{ + + struct entity* e1 = (struct entity*)arg1; + struct entity* e2 = (struct entity*)arg2; + + if (e1->object->Alpha () && !e2->object->Alpha ()) + return 1; + if (!e1->object->Alpha () && e2->object->Alpha ()) + return -1; + if (e1->object->Texture () > e2->object->Texture ()) + return 1; + else if (e1->object->Texture () < e2->object->Texture ()) + return -1; + return 0; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void add (CEntity* b) +{ + + entity_list = (entity*)realloc (entity_list, sizeof (entity) * (entity_count + 1)); + entity_list[entity_count].object = b; + entity_count++; + polycount = 0; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void do_compile () +{ + + int i; + int x, y; + + if (compiled) + return; + x = compile_x; + y = compile_y; + //Changing textures is pretty expensive, and thus sorting the entites so that + //they are grouped by texture used can really improve framerate. + //qsort (entity_list, entity_count, sizeof (struct entity), do_compare); + //sorted = true; + //Now group entites on the grid + //make a list for the textured objects in this region + if (!cell_list[x][y].list_textured) + cell_list[x][y].list_textured = glGenLists(1); + glNewList (cell_list[x][y].list_textured, GL_COMPILE); + cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION); + for (i = 0; i < entity_count; i++) { + GLvector pos = entity_list[i].object->Center (); + if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) { + glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ()); + entity_list[i].object->Render (); + } + } + glEndList(); + + //Make a list of flat-color stuff (A/C units, ledges, roofs, etc.) + if (!cell_list[x][y].list_flat) + cell_list[x][y].list_flat = glGenLists(1); + glNewList (cell_list[x][y].list_flat, GL_COMPILE); + glEnable (GL_CULL_FACE); + cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION); + for (i = 0; i < entity_count; i++) { + GLvector pos = entity_list[i].object->Center (); + if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) { + entity_list[i].object->RenderFlat (false); + } + } + glEndList(); + //Now a list of flat-colored stuff that will be wireframe friendly + if (!cell_list[x][y].list_flat_wireframe) + cell_list[x][y].list_flat_wireframe = glGenLists(1); + glNewList (cell_list[x][y].list_flat_wireframe, GL_COMPILE); + glEnable (GL_CULL_FACE); + cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION); + for (i = 0; i < entity_count; i++) { + GLvector pos = entity_list[i].object->Center (); + if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && !entity_list[i].object->Alpha ()) { + entity_list[i].object->RenderFlat (true); + } + } + glEndList(); + //Now a list of stuff to be alpha-blended, and thus rendered last + if (!cell_list[x][y].list_alpha) + cell_list[x][y].list_alpha = glGenLists(1); + glNewList (cell_list[x][y].list_alpha, GL_COMPILE); + cell_list[x][y].pos = glVector (GRID_TO_WORLD(x), 0.0f, (float)y * GRID_RESOLUTION); + glDepthMask (false); + glEnable (GL_BLEND); + glDisable (GL_CULL_FACE); + for (i = 0; i < entity_count; i++) { + GLvector pos = entity_list[i].object->Center (); + if (WORLD_TO_GRID(pos.x) == x && WORLD_TO_GRID(pos.z) == y && entity_list[i].object->Alpha ()) { + glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ()); + entity_list[i].object->Render (); + } + } + glDepthMask (true); + glEndList(); + + //now walk the grid + compile_x++; + if (compile_x == GRID_SIZE) { + compile_x = 0; + compile_y++; + if (compile_y == GRID_SIZE) + compiled = true; + } + compile_count++; + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool EntityReady () +{ + + return compiled; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +float EntityProgress () +{ + + return (float)compile_count / (GRID_SIZE * GRID_SIZE); + + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void EntityUpdate () +{ + + if (!TextureReady ()) { + sorted = false; + return; + } + if (!sorted) { + qsort (entity_list, entity_count, sizeof (struct entity), do_compare); + sorted = true; + } + + if (!compiled) + for (int i = 0; i < 10; i++) + do_compile (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void xEntityRender () +{ + + int i; + bool wireframe; + int polymode[2]; + + glGetIntegerv (GL_POLYGON_MODE, &polymode[0]); + wireframe = polymode[0] != GL_FILL; + for (i = 0; i < entity_count; i++) { + if (Visible (entity_list[i].object->Center ())) { + glBindTexture(GL_TEXTURE_2D, entity_list[i].object->Texture ()); + entity_list[i].object->Render (); + } + } + glBindTexture(GL_TEXTURE_2D, 0); + glColor3f (0,0,0); + for (i = 0; i < entity_count; i++) { + if (Visible (entity_list[i].object->Center ())) { + entity_list[i].object->RenderFlat (wireframe); + } + } + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void EntityRender () +{ + + int polymode[2]; + bool wireframe; + int x, y; + + //Draw all textured objects + glGetIntegerv (GL_POLYGON_MODE, &polymode[0]); + wireframe = polymode[0] != GL_FILL; + if (RenderFlat ()) + glDisable (GL_TEXTURE_2D); + for (x = 0; x < GRID_SIZE; x++) { + for (y = 0; y < GRID_SIZE; y++) { + if (Visible (x,y)) + glCallList (cell_list[x][y].list_textured); + } + } + //draw all flat colored objects + glBindTexture(GL_TEXTURE_2D, 0); + glColor3f (0, 0, 0); + for (x = 0; x < GRID_SIZE; x++) { + for (y = 0; y < GRID_SIZE; y++) { + if (Visible (x, y)) { + if (wireframe) + glCallList (cell_list[x][y].list_flat_wireframe); + else + glCallList (cell_list[x][y].list_flat); + } + } + } + //draw all alpha-blended objects + glBindTexture(GL_TEXTURE_2D, 0); + glColor3f (0, 0, 0); + glEnable (GL_BLEND); + for (x = 0; x < GRID_SIZE; x++) { + for (y = 0; y < GRID_SIZE; y++) { + if (Visible (x,y)) { + glCallList (cell_list[x][y].list_alpha); + } + } + } + +} + + + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void EntityClear () +{ + + for (int i = 0; i < entity_count; i++) { + delete entity_list[i].object; + } + if (entity_list) + free (entity_list); + entity_list = NULL; + entity_count = 0; + compile_x = 0; + compile_y = 0; + compile_count = 0; + compiled = false; + sorted = false; + + int x, y; + + for (x = 0; x < GRID_SIZE; x++) { + for (y = 0; y < GRID_SIZE; y++) { + glNewList (cell_list[x][y].list_textured, GL_COMPILE); + glEndList(); + glNewList (cell_list[x][y].list_alpha, GL_COMPILE); + glEndList(); + glNewList (cell_list[x][y].list_flat_wireframe, GL_COMPILE); + glEndList(); + glNewList (cell_list[x][y].list_flat, GL_COMPILE); + glEndList(); + } + } + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int EntityCount () +{ + + return entity_count; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void EntityInit (void) +{ + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int EntityPolyCount (void) +{ + + if (!sorted) + return 0; + if (polycount) + return polycount; + for (int i = 0; i < entity_count; i++) + polycount += entity_list[i].object->PolyCount (); + return polycount; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CEntity::CEntity (void) +{ + + add (this); + +} + +void CEntity::Render (void) +{ + +} + +void CEntity::RenderFlat (bool wireframe) +{ + +} + +void CEntity::Update (void) +{ + + +} + + diff --git a/Entity.h b/Entity.h new file mode 100644 index 0000000..9c58a93 --- /dev/null +++ b/Entity.h @@ -0,0 +1,36 @@ +#ifndef TYPES +#include "glTypes.h" +#endif + +#ifndef ENTITY + +#define ENTITY + +class CEntity +{ +private: +protected: + + GLvector _center; + +public: + CEntity (void); + GLvector Center () { return _center; } + virtual void Render (void); + virtual void RenderFlat (bool wirefame); + virtual unsigned Texture () { return 0; } + virtual void Update (void); + virtual bool Alpha () { return false; } + virtual int PolyCount () { return 0; } + +}; + +void EntityClear (); +int EntityCount (void); +float EntityProgress (); +bool EntityReady (); +void EntityRender (void); +void EntityUpdate (void); +int EntityPolyCount (void); + +#endif \ No newline at end of file diff --git a/Ini.cpp b/Ini.cpp new file mode 100644 index 0000000..bd3ab45 --- /dev/null +++ b/Ini.cpp @@ -0,0 +1,137 @@ +/*----------------------------------------------------------------------------- + + Ini.cpp + + 2009 Shamus Young + + +------------------------------------------------------------------------------- + + This takes various types of data and dumps them into a predefined ini file. + +-----------------------------------------------------------------------------*/ + +#define FORMAT_VECTOR "%f %f %f" +#define MAX_RESULT 256 +#define FORMAT_FLOAT "%1.2f" +#define INI_FILE ".\\" APP ".ini" +#define SECTION "Settings" + +#include +#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; + +} diff --git a/Ini.h b/Ini.h new file mode 100644 index 0000000..7a51d81 --- /dev/null +++ b/Ini.h @@ -0,0 +1,8 @@ +int IniInt (char* entry); +void IniIntSet (char* entry, int val); +float IniFloat (char* entry); +void IniFloatSet (char* entry, float val); +char* IniString (char* entry); +void IniStringSet (char* entry, char* val); +void IniVectorSet (char* entry, GLvector v); +GLvector IniVector (char* entry); diff --git a/Light.cpp b/Light.cpp new file mode 100644 index 0000000..354c802 --- /dev/null +++ b/Light.cpp @@ -0,0 +1,174 @@ +/*----------------------------------------------------------------------------- + + Light.cpp + + 2006 Shamus Young + +------------------------------------------------------------------------------- + + This tracks and renders the light sources. (Note that they do not really + CAST light in the OpenGL sense of the world, these are just simple panels.) + These are NOT subclassed to entities because these are dynamic. Some lights + blink, and thus they can't go into the fixed render lists managed by + Entity.cpp. + +-----------------------------------------------------------------------------*/ + +#define MAX_SIZE 5 + +#include +#include +#include +#include +#include +#include "glTypes.h" + +#include "camera.h" +#include "light.h" +#include "macro.h" +#include "math.h" +#include "random.h" +#include "render.h" +#include "texture.h" +#include "visible.h" + +static GLvector2 angles[5][360]; +static CLight* head; +static bool angles_done; +static int count; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void LightClear () +{ + + CLight* l; + + while (head) { + l = head; + head = l->_next; + delete l; + } + count = 0; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int LightCount () +{ + + return count; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void LightRender () +{ + + CLight* l; + + if (!angles_done) { + for (int size = 0; size < MAX_SIZE; size++) { + for (int i = 0 ;i < 360; i++) { + angles[size][i].x = cosf ((float)i * DEGREES_TO_RADIANS) * ((float)size + 0.5f); + angles[size][i].y = sinf ((float)i * DEGREES_TO_RADIANS) * ((float)size + 0.5f); + } + } + } + glDepthMask (false); + glEnable (GL_BLEND); + glDisable (GL_CULL_FACE); + glBlendFunc (GL_ONE, GL_ONE); + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_LIGHT)); + glDisable (GL_CULL_FACE); + glBegin (GL_QUADS); + for (l = head; l; l = l->_next) + l->Render (); + glEnd (); + glDepthMask (true); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CLight::CLight (GLvector pos, GLrgba color, int size) +{ + + _position = pos; + _color = color * 0.5f; + _size = CLAMP (size, 0, (MAX_SIZE - 1)); + _vert_size = (float)_size + 0.5f; + _flat_size = _vert_size + 0.5f; + _blink = false; + _cell_x = WORLD_TO_GRID(pos.x); + _cell_z = WORLD_TO_GRID(pos.z); + _next = head; + head = this; + count++; + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CLight::Blink () +{ + + _blink = true; + //we don't want blinkers to be in sync, so have them blink at + //slightly different rates. (Milliseconds) + _blink_interval = 1500 + RandomVal (500); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CLight::Render () +{ + + int angle; + GLvector pos; + GLvector camera; + GLvector camera_position; + GLvector2 offset; + + if (!Visible (_cell_x, _cell_z)) + return; + camera = CameraAngle (); + camera_position = CameraPosition (); + if (fabs (camera_position.x - _position.x) > RenderFogDistance ()) + return; + if (fabs (camera_position.z - _position.z) > RenderFogDistance ()) + return; + if (_blink && (GetTickCount () % _blink_interval) > 200) + return; + angle = (int)MathAngle (camera.y); + offset = angles[_size][angle]; + pos = _position; + //m_color.alpha = 0.25f; + glColor4fv (&_color.red); + glTexCoord2f (0, 0); + glVertex3f (pos.x + offset.x, pos.y - _vert_size, pos.z + offset.y); + glTexCoord2f (0, 1); + glVertex3f (pos.x - offset.x, pos.y - _vert_size, pos.z - offset.y); + glTexCoord2f (1, 1); + glVertex3f (pos.x - offset.x, pos.y + _vert_size, pos.z - offset.y); + glTexCoord2f (1, 0); + glVertex3f (pos.x + offset.x, pos.y + _vert_size, pos.z + offset.y); + +} \ No newline at end of file diff --git a/Light.h b/Light.h new file mode 100644 index 0000000..42ec7e1 --- /dev/null +++ b/Light.h @@ -0,0 +1,23 @@ +class CLight +{ + GLvector _position; + GLrgba _color; + int _size; + float _vert_size; + float _flat_size; + bool _blink; + unsigned _blink_interval; + int _cell_x; + int _cell_z; + +public: + CLight(GLvector pos, GLrgba color, int size); + class CLight* _next; + void Render (); + void Blink (); + +}; + +void LightRender (); +void LightClear (); +int LightCount (); diff --git a/Macro.h b/Macro.h new file mode 100644 index 0000000..e0a8361 --- /dev/null +++ b/Macro.h @@ -0,0 +1,15 @@ +#define LIMIT_INTERVAL(interval) { static unsigned next_update; if (next_update > GetTickCount ()) return; next_update = GetTickCount () + interval;} +#define DEGREES_TO_RADIANS .017453292F +#define RADIANS_TO_DEGREES 57.29577951F +#define PI ((double)3.1415926535F) +#define PI2 PI*PI +#define GRAVITY 9.5f +#define CLAMP(a,b,c) (a < b ? b : (a > c ? c : a)) +#define WRAP(x,y) ((unsigned)x % y) +#define SIGN(x) (((x) > 0) ? 1 : ((x) < 0) ? -1 : 0) +#define ABS(x) (((x) < 0 ? (-x) : (x))) +#define SMALLEST(x,y) (ABS(x) < ABS(y) ? 0 : x) +#define MIN(x,y) ((x) < (y) ? x : y) +#define MAX(x,y) ((x) > (y) ? x : y) +#define POW(x,y) (float)pow(x,y) +#define SWAP(a,b) {int temp = a;a = b; b = temp;} diff --git a/Math.cpp b/Math.cpp new file mode 100644 index 0000000..0aecaba --- /dev/null +++ b/Math.cpp @@ -0,0 +1,181 @@ +/*----------------------------------------------------------------------------- + + 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.0); + if (result > 180.0) + return result - 360.0F; + if (result < -180.0) + return result + 360.0F; + return result; + +} + +/*----------------------------------------------------------------------------- +interpolate between two values +-----------------------------------------------------------------------------*/ + +float MathInterpolate (float n1, float n2, float delta) +{ + + return n1 * (1.0f - delta) + n2 * delta; + +} + +/*----------------------------------------------------------------------------- +return a scalar of 0.0 to 1.0, based an the given values position within a range +-----------------------------------------------------------------------------*/ + +float MathSmoothStep (float val, float a, float b) +{ + + if (b == a) + return 0.0f; + val -= a; + val /= (b - a); + return CLAMP (val, 0.0f, 1.0f); + +} + +/*----------------------------------------------------------------------------- +Average two values +-----------------------------------------------------------------------------*/ + +float MathAverage (float n1, float n2) +{ + + return (n1 + n2) / 2.0f; + +} + +/*----------------------------------------------------------------------------- + This will take linear input values from 0.0 to 1.0 and convert them to + values along a curve. This could also be acomplished with sin (), but this + way avoids converting to radians and back. +-----------------------------------------------------------------------------*/ + +float MathScalarCurve (float val) +{ + + float sign; + + val = (val - 0.5f) * 2.0f; + if (val < 0.0f) + sign = -1.0f; + else + sign = 1.0f; + if (val < 0.0f) + val = -val; + val = 1.0f - val; + val *= val; + val = 1.0f - val; + val *= sign; + val = (val + 1.0f) / 2.0f; + return val; + +} \ No newline at end of file diff --git a/Math.h b/Math.h new file mode 100644 index 0000000..a155295 --- /dev/null +++ b/Math.h @@ -0,0 +1,10 @@ +float MathAngle (float angle); +float MathAngle (float x1, float y1, float x2, float y2); +float MathAngleDifference (float a1, float a2); +float MathAverage (float n1, float n2); +float MathInterpolate (float n1, float n2, float delta); +float MathLine_distance (float x1, float y1, float x2, float y2, float px, float py); +float MathDistance (float x1, float y1, float x2, float y2); +float MathDistance2 (float x1, float y1, float x2, float y2); +float MathSmoothStep (float val, float a, float b); +float MathScalarCurve (float val); \ No newline at end of file diff --git a/Mesh.cpp b/Mesh.cpp new file mode 100644 index 0000000..11d7490 --- /dev/null +++ b/Mesh.cpp @@ -0,0 +1,216 @@ +/*----------------------------------------------------------------------------- + + Mesh.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This class is used to make constructing objects easier. It handles + allocating vertex lists, polygon lists, and suchlike. + + If you were going to implement vertex buffers, this would be the place to + do it. Take away the _vertex member variable and store verts for ALL meshes + in a common list, which could then be unloaded onto the good 'ol GPU. + +-----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "glTypes.h" + +#include "mesh.h" + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CMesh::CMesh () +{ + + _vertex_count = 0; + _triangle_count = 0; + _quad_strip_count = 0; + _fan_count = 0; + _cube_count = 0; + _polycount = 0; + _list = 0; + _compiled = false; + _vertex = NULL; + _normal = NULL; + _triangle = NULL; + _cube = NULL; + _quad_strip = NULL; + _fan = NULL; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CMesh::~CMesh () +{ + + unsigned i; + + if (_vertex) + free (_vertex); + if (_normal) + free (_normal); + if (_triangle) + free (_triangle); + if (_cube) + free (_cube); + for (i = 0; i < _quad_strip_count; i++) + delete _quad_strip[i].index_list; + delete _quad_strip; + for (i = 0; i < _fan_count; i++) + delete _fan[i].index_list; + delete _fan; + if (_list) + glDeleteLists (_list, 1); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::VertexAdd (GLvertex v) +{ + + _vertex = (GLvertex*)realloc (_vertex, sizeof (GLvertex) * (_vertex_count + 1)); + _vertex[_vertex_count] = v; + _vertex_count++; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::CubeAdd (int* index) +{ + + _cube = (cube*)realloc (_cube, sizeof (cube) * (_cube_count + 1)); + memcpy (&_cube[_cube_count].index_list[0], index, sizeof (int) * 10); + _cube_count++; + _polycount += 5; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::QuadStripAdd (int* index, int count) +{ + + _quad_strip = (quad_strip*)realloc (_quad_strip, sizeof (quad_strip) * (_quad_strip_count + 1)); + _quad_strip[_quad_strip_count].index_list = (int*)malloc (sizeof (int) * count); + _quad_strip[_quad_strip_count].count = count; + memcpy (&_quad_strip[_quad_strip_count].index_list[0], &index[0], sizeof (int) * count); + _quad_strip_count++; + _polycount += (count - 2) / 2; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::FanAdd (int* index, int count) +{ + + _fan = (fan*)realloc (_fan, sizeof (fan) * (_fan_count + 1)); + _fan[_fan_count].index_list = (int*)malloc (sizeof (int) * count); + _fan[_fan_count].count = count; + memcpy (&_fan[_fan_count].index_list[0], &index[0], sizeof (int) * count); + _fan_count++; + _polycount += count - 2; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::Render () +{ + + unsigned i, n; + int* index; + + if (_compiled) { + glCallList (_list); + return; + } + for (i = 0; i < _quad_strip_count; i++) { + index = &_quad_strip[i].index_list[0]; + glBegin (GL_QUAD_STRIP); + for (n = 0; n < _quad_strip[i].count; n++) { + glTexCoord2fv (&_vertex[index[n]].uv.x); + glVertex3fv (&_vertex[index[n]].position.x); + } + glEnd (); + } + for (i = 0; i < _cube_count; i++) { + index = &_cube[i].index_list[0]; + glBegin (GL_QUAD_STRIP); + for (n = 0; n < 10; n++) { + glTexCoord2fv (&_vertex[index[n]].uv.x); + glVertex3fv (&_vertex[index[n]].position.x); + } + glEnd (); + + glBegin (GL_QUADS); + glTexCoord2fv (&_vertex[index[7]].uv.x); + glVertex3fv (&_vertex[index[7]].position.x); + glVertex3fv (&_vertex[index[5]].position.x); + glVertex3fv (&_vertex[index[3]].position.x); + glVertex3fv (&_vertex[index[1]].position.x); + glEnd (); + + glBegin (GL_QUADS); + glTexCoord2fv (&_vertex[index[6]].uv.x); + glVertex3fv (&_vertex[index[0]].position.x); + glVertex3fv (&_vertex[index[2]].position.x); + glVertex3fv (&_vertex[index[4]].position.x); + glVertex3fv (&_vertex[index[6]].position.x); + glEnd (); + + + } + for (i = 0; i < _fan_count; i++) { + index = &_fan[i].index_list[0]; + glBegin (GL_TRIANGLE_FAN); + for (n = 0; n < _fan[i].count; n++) { + glTexCoord2fv (&_vertex[index[n]].uv.x); + glVertex3fv (&_vertex[index[n]].position.x); + } + glEnd (); + } + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CMesh::Compile () +{ + + if (!_list) + _list = glGenLists(1); + glNewList (_list, GL_COMPILE); + Render (); + glEndList(); + _compiled = true; + +} \ No newline at end of file diff --git a/Mesh.h b/Mesh.h new file mode 100644 index 0000000..0613dd6 --- /dev/null +++ b/Mesh.h @@ -0,0 +1,54 @@ + + +struct cube +{ + int index_list[10]; +}; + +struct quad_strip +{ + int* index_list; + unsigned count; +}; + +struct fan +{ + int* index_list; + unsigned count; +}; + +class CMesh +{ +public: + CMesh (); + ~CMesh (); + unsigned _vertex_count; + unsigned _triangle_count; + unsigned _cube_count; + unsigned _quad_strip_count; + unsigned _fan_count; + unsigned _normal_count; + unsigned _list; + int _polycount; + GLvertex* _vertex; + GLvector* _normal; + GLtriangle* _triangle; + cube* _cube; + quad_strip* _quad_strip; + fan* _fan; + bool _compiled; + + //void TriangleRender (unsigned n); + //GLtriangle* TriangleAdd (unsigned v1, int unsigned, int unsigned); + //GLtriangle* TriangleAdd (GLtriangle c); + void NormalAdd (GLvector n); + void VertexAdd (GLvertex v); + int VertexCount () { return _vertex_count; } + int PolyCount () { return _polycount; } + void CubeAdd (int* index); + void QuadStripAdd (int* index, int count); + void FanAdd (int* index, int count); + void Render (); + void Compile (); + +}; diff --git a/PixelCity.dsp b/PixelCity.dsp new file mode 100644 index 0000000..b4130e5 --- /dev/null +++ b/PixelCity.dsp @@ -0,0 +1,266 @@ +# Microsoft Developer Studio Project File - Name="PixelCity" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=PixelCity - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PixelCity.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PixelCity.mak" CFG="PixelCity - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PixelCity - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "PixelCity - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "PixelCity" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PixelCity - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/PixelCity.scr" + +!ELSEIF "$(CFG)" == "PixelCity - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "PixelCity - Win32 Release" +# Name "PixelCity - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "glTypes" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\glBbox.cpp +# End Source File +# Begin Source File + +SOURCE=.\glMatrix.cpp +# End Source File +# Begin Source File + +SOURCE=.\glQuat.cpp +# End Source File +# Begin Source File + +SOURCE=.\glRgba.cpp +# End Source File +# Begin Source File + +SOURCE=.\glVector2.cpp +# End Source File +# Begin Source File + +SOURCE=.\glVector3.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Building.cpp +# End Source File +# Begin Source File + +SOURCE=.\Camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\Car.cpp +# End Source File +# Begin Source File + +SOURCE=.\Deco.cpp +# End Source File +# Begin Source File + +SOURCE=.\Entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\Ini.cpp +# End Source File +# Begin Source File + +SOURCE=.\Light.cpp +# End Source File +# Begin Source File + +SOURCE=.\Math.cpp +# End Source File +# Begin Source File + +SOURCE=.\Mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\Random.cpp +# End Source File +# Begin Source File + +SOURCE=.\Render.cpp +# End Source File +# Begin Source File + +SOURCE=.\Sky.cpp +# End Source File +# Begin Source File + +SOURCE=.\Texture.cpp +# End Source File +# Begin Source File + +SOURCE=.\Visible.cpp +# End Source File +# Begin Source File + +SOURCE=.\Win.cpp +# End Source File +# Begin Source File + +SOURCE=.\World.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Building.h +# End Source File +# Begin Source File + +SOURCE=.\Camera.h +# End Source File +# Begin Source File + +SOURCE=.\Car.h +# End Source File +# Begin Source File + +SOURCE=.\Deco.h +# End Source File +# Begin Source File + +SOURCE=.\Entity.h +# End Source File +# Begin Source File + +SOURCE=.\glTypes.h +# End Source File +# Begin Source File + +SOURCE=.\Ini.h +# End Source File +# Begin Source File + +SOURCE=.\Light.h +# End Source File +# Begin Source File + +SOURCE=.\Macro.h +# End Source File +# Begin Source File + +SOURCE=.\Math.h +# End Source File +# Begin Source File + +SOURCE=.\Mesh.h +# End Source File +# Begin Source File + +SOURCE=.\Random.h +# End Source File +# Begin Source File + +SOURCE=.\Render.h +# End Source File +# Begin Source File + +SOURCE=.\Sky.h +# End Source File +# Begin Source File + +SOURCE=.\Texture.h +# End Source File +# Begin Source File + +SOURCE=.\Visible.h +# End Source File +# Begin Source File + +SOURCE=.\Win.h +# End Source File +# Begin Source File + +SOURCE=.\World.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Random.cpp b/Random.cpp new file mode 100644 index 0000000..41888c0 --- /dev/null +++ b/Random.cpp @@ -0,0 +1,93 @@ +/*----------------------------------------------------------------------------- + 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; + +} + diff --git a/Random.h b/Random.h new file mode 100644 index 0000000..e9d8420 --- /dev/null +++ b/Random.h @@ -0,0 +1,5 @@ +#define COIN_FLIP (RandomVal (2) == 0) + +unsigned long RandomVal (int range); +unsigned long RandomVal (void); +void RandomInit (unsigned long seed); diff --git a/Render.cpp b/Render.cpp new file mode 100644 index 0000000..0a2cb5d --- /dev/null +++ b/Render.cpp @@ -0,0 +1,777 @@ +/*----------------------------------------------------------------------------- + + Render.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This is the core of the gl rendering functions. This contains the main + rendering function RenderUpdate (), which initiates the various + other renders in the other modules. + +-----------------------------------------------------------------------------*/ + +#define RENDER_DISTANCE 1280 +#define MAX_TEXT 256 +#define YOUFAIL(message) {WinPopup (message);return;} +#define HELP_SIZE sizeof(help) +#define COLOR_CYCLE_TIME 10000 //milliseconds +#define COLOR_CYCLE (COLOR_CYCLE_TIME / 4) +#define FONT_COUNT (sizeof (fonts) / sizeof (struct glFont)) +#define FONT_SIZE (LOGO_PIXELS - LOGO_PIXELS / 8) +#define BLOOM_SCALING 0.07f + +#include +#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_DEBUG, + EFFECT_DEBUG_OVERBLOOM, + EFFECT_COUNT +}; +#else +enum +{ + EFFECT_NONE, + EFFECT_BLOOM, + EFFECT_COUNT, + EFFECT_DEBUG, + EFFECT_DEBUG_OVERBLOOM, + EFFECT_BLOOM_RADIAL, + EFFECT_COLOR_CYCLE, + EFFECT_GLASS_CITY, +}; +#endif + +static HDC hDC; +static HGLRC hRC; +static float render_aspect; +static float fog_distance; +static int render_width; +static int render_height; +static bool letterbox; +static int letterbox_offset; +static int effect; +static int max_texture; +static unsigned next_fps; +static unsigned current_fps; +static unsigned frames; +static bool show_wireframe; +static bool bloom; +static bool flat; +static bool show_fps; +static bool show_fog; +static bool show_help; + +/*----------------------------------------------------------------------------- + + Draw a clock-ish progress.. widget... thing. It's cute. + +-----------------------------------------------------------------------------*/ + +static void do_progress (float center_x, float center_y, float radius, float opacity, float progress) +{ + + int i; + int end_angle; + float inner, outer; + float angle; + float s, c; + float gap; + + //Outer Ring + gap = radius * 0.05f; + outer = radius; + inner = radius - gap * 2; + glColor4f (1,1,1, opacity); + glBegin (GL_QUAD_STRIP); + for (i = 0; i <= 360; i+= 15) { + //GLrgba col = glRgbaUnique (i); + //glColor3fv (&col.red); + angle = (float)i * DEGREES_TO_RADIANS; + s = sinf (angle); + c = -cosf (angle); + glVertex2f (center_x + s * outer, center_y + c * outer); + glVertex2f (center_x + s * inner, center_y + c * inner); + } + glEnd (); + //Progress indicator + glColor4f (1,1,1, opacity); + end_angle = (int)(360 * progress); + outer = radius - gap * 3; + glBegin (GL_TRIANGLE_FAN); + glVertex2f (center_x, center_y); + for (i = 0; i <= end_angle; i+= 3) { + angle = (float)i * DEGREES_TO_RADIANS; + s = sinf (angle); + c = -cosf (angle); + glVertex2f (center_x + s * outer, center_y + c * outer); + } + glEnd (); + //Tic lines + glLineWidth (2.0f); + outer = radius - gap * 1; + inner = radius - gap * 2; + glColor4f (0,0,0, opacity); + glBegin (GL_LINES); + for (i = 0; i <= 360; i+= 15) { + angle = (float)i * DEGREES_TO_RADIANS; + s = sinf (angle); + c = -cosf (angle); + glVertex2f (center_x + s * outer, center_y + c * outer); + glVertex2f (center_x + s * inner, center_y + c * inner); + } + glEnd (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void do_effects (int type) +{ + + float hue1, hue2, hue3, hue4; + GLrgba color; + float fade; + int radius; + int x, y; + int i; + int bloom_radius; + int bloom_step; + + fade = WorldFade (); + bloom_radius = 15; + bloom_step = bloom_radius / 3; + if (!TextureReady () && fade == 0.0f) + return; + //Now change projection modes so we can render full-screen effects + glDisable(GL_DEPTH_TEST); + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + glOrtho (0, render_width, render_height, 0, 0.1f, 2048); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity(); + glTranslatef(0, 0, -1.0f); + glDisable (GL_CULL_FACE); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + //Render full-screen effects + + glBlendFunc (GL_ONE, GL_ONE); + glEnable (GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_BLOOM)); + switch (type) { + case EFFECT_DEBUG: + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_LOGOS)); + glDisable (GL_BLEND); + glBegin (GL_QUADS); + glColor3f (1, 1, 1); + glTexCoord2f (0, 0); glVertex2i (0, render_height / 4); + glTexCoord2f (0, 1); glVertex2i (0, 0); + glTexCoord2f (1, 1); glVertex2i (render_width / 4, 0); + glTexCoord2f (1, 0); glVertex2i (render_width / 4, render_height / 4); + + glTexCoord2f (0, 0); glVertex2i (0, 512); + glTexCoord2f (0, 1); glVertex2i (0, 0); + glTexCoord2f (1, 1); glVertex2i (512, 0); + glTexCoord2f (1, 0); glVertex2i (512, 512); + glEnd (); + break; + case EFFECT_BLOOM_RADIAL: + //Psychedelic bloom + glEnable (GL_BLEND); + glBegin (GL_QUADS); + color = WorldBloomColor () * BLOOM_SCALING; + glColor3fv (&color.red); + for (i = 0; i <= 100; i+=10) { + glTexCoord2f (0, 0); glVertex2i (-i, i + render_height); + glTexCoord2f (0, 1); glVertex2i (-i, -i); + glTexCoord2f (1, 1); glVertex2i (i + render_width, -i); + glTexCoord2f (1, 0); glVertex2i (i + render_width, i + render_height); + } + glEnd (); + break; + case EFFECT_COLOR_CYCLE: + //Oooh. Pretty colors. Tint the scene according to screenspace. + hue1 = (float)(GetTickCount () % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME; + hue2 = (float)((GetTickCount () + COLOR_CYCLE) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME; + hue3 = (float)((GetTickCount () + COLOR_CYCLE * 2) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME; + hue4 = (float)((GetTickCount () + COLOR_CYCLE * 3) % COLOR_CYCLE_TIME) / COLOR_CYCLE_TIME; + glBindTexture(GL_TEXTURE_2D, 0); + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR); + glBegin (GL_QUADS); + color = glRgbaFromHsl (hue1, 1.0f, 0.6f); + glColor3fv (&color.red); + glTexCoord2f (0, 0); glVertex2i (0, render_height); + color = glRgbaFromHsl (hue2, 1.0f, 0.6f); + glColor3fv (&color.red); + glTexCoord2f (0, 1); glVertex2i (0, 0); + color = glRgbaFromHsl (hue3, 1.0f, 0.6f); + glColor3fv (&color.red); + glTexCoord2f (1, 1); glVertex2i (render_width, 0); + color = glRgbaFromHsl (hue4, 1.0f, 0.6f); + glColor3fv (&color.red); + glTexCoord2f (1, 0); glVertex2i (render_width, render_height); + glEnd (); + break; + case EFFECT_BLOOM: + //Simple bloom effect + glBegin (GL_QUADS); + color = WorldBloomColor () * BLOOM_SCALING; + glColor3fv (&color.red); + for (x = -bloom_radius; x <= bloom_radius; x += bloom_step) { + for (y = -bloom_radius; y <= bloom_radius; y += bloom_step) { + if (abs (x) == abs (y) && x) + continue; + glTexCoord2f (0, 0); glVertex2i (x, y + render_height); + glTexCoord2f (0, 1); glVertex2i (x, y); + glTexCoord2f (1, 1); glVertex2i (x + render_width, y); + glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height); + } + } + glEnd (); + break; + case EFFECT_DEBUG_OVERBLOOM: + //This will punish that uppity GPU. Good for testing low frame rate behavior. + glBegin (GL_QUADS); + color = WorldBloomColor () * 0.06f; + glColor3fv (&color.red); + for (x = -50; x <= 50; x+=5) { + for (y = -50; y <= 50; y+=5) { + glTexCoord2f (0, 0); glVertex2i (x, y + render_height); + glTexCoord2f (0, 1); glVertex2i (x, y); + glTexCoord2f (1, 1); glVertex2i (x + render_width, y); + glTexCoord2f (1, 0); glVertex2i (x + render_width, y + render_height); + } + } + glEnd (); + break; + } + //Do the fade to / from darkness used to hide scene transitions + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); + glDisable (GL_TEXTURE_2D); + glColor4f (0, 0, 0, fade); + glBegin (GL_QUADS); + glVertex2i (0, 0); + glVertex2i (0, render_height); + glVertex2i (render_width, render_height); + glVertex2i (render_width, 0); + glEnd (); + if (TextureReady () && !EntityReady () && fade != 0.0f) { + radius = render_width / 16; + do_progress ((float)render_width / 2, (float)render_height / 2, (float)radius, fade, EntityProgress ()); + RenderPrint (render_width / 2 - LOGO_PIXELS, render_height / 2 + LOGO_PIXELS, 0, glRgba (0.5f), "%1.2f%%", EntityProgress () * 100.0f); + } + glPopMatrix (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt, ...) +{ + + char text[MAX_TEXT]; + va_list ap; + + text[0] = 0; + if (fmt == NULL) + return; + va_start(ap, fmt); + vsprintf(text, fmt, ap); + va_end(ap); + glPushAttrib(GL_LIST_BIT); + glListBase(fonts[font % FONT_COUNT].base_char - 32); + glColor3fv (&color.red); + glRasterPos2i (x, y); + glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderPrint (int line, const char *fmt, ...) +{ + + char text[MAX_TEXT]; + va_list ap; + + text[0] = 0; + if (fmt == NULL) + return; + va_start (ap, fmt); + vsprintf (text, fmt, ap); + va_end (ap); + glDepthMask (false); + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + glOrtho (0, render_width, render_height, 0, 0.1f, 2048); + glDisable(GL_DEPTH_TEST); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity(); + glTranslatef(0, 0, -1.0f); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_DEPTH_TEST); + RenderPrint (0, line * FONT_SIZE - 2, 0, glRgba (0.0f), text); + RenderPrint (4, line * FONT_SIZE + 2, 0, glRgba (0.0f), text); + RenderPrint (2, line * FONT_SIZE, 0, glRgba (1.0f), text); + glPopAttrib(); + glPopMatrix (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void static do_help (void) +{ + + char* text; + int line; + char parse[HELP_SIZE]; + int x; + + strcpy (parse, help); + line = 0; + text = strtok (parse, "\n"); + x = 10; + while (text) { + RenderPrint (line + 1, text); + text = strtok (NULL, "\n"); + line++; + } + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderResize (void) +{ + + float fovy; + + render_width = WinWidth (); + render_height = WinHeight (); + if (letterbox) { + letterbox_offset = render_height / 6; + render_height = render_height - letterbox_offset * 2; + } else + letterbox_offset = 0; + //render_aspect = (float)render_height / (float)render_width; + glViewport (0, letterbox_offset, render_width, render_height); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + render_aspect = (float)render_width / (float)render_height; + fovy = 60.0f; + if (render_aspect > 1.0f) + fovy /= render_aspect; + gluPerspective (fovy, render_aspect, 0.1f, RENDER_DISTANCE); + glMatrixMode (GL_MODELVIEW); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderTerm (void) +{ + + if (!hRC) + return; + wglDeleteContext (hRC); + hRC = NULL; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderInit (void) +{ + + HWND hWnd; + unsigned PixelFormat; + HFONT font; + HFONT oldfont; + + hWnd = WinHwnd (); + if (!(hDC = GetDC (hWnd))) + YOUFAIL ("Can't Create A GL Device Context.") ; + if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) + YOUFAIL ("Can't Find A Suitable PixelFormat.") ; + if(!SetPixelFormat(hDC,PixelFormat,&pfd)) + YOUFAIL ("Can't Set The PixelFormat."); + if (!(hRC = wglCreateContext (hDC))) + YOUFAIL ("Can't Create A GL Rendering Context."); + if(!wglMakeCurrent(hDC,hRC)) + YOUFAIL ("Can't Activate The GL Rendering Context."); + //Load the fonts for printing debug info to the window. + for (int i = 0; i < FONT_COUNT; i++) { + fonts[i].base_char = glGenLists(96); + font = CreateFont (FONT_SIZE, 0, 0, 0, + FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH, + fonts[i].name); + oldfont = (HFONT)SelectObject(hDC, font); + wglUseFontBitmaps(hDC, 32, 96, fonts[i].base_char); + SelectObject(hDC, oldfont); + DeleteObject(font); + } + //load in our settings + letterbox = IniInt ("Letterbox") != 0; + show_wireframe = IniInt ("Wireframe") != 0; + show_fps = IniInt ("ShowFPS") != 0; + show_fog = IniInt ("ShowFog") != 0; + bloom = IniInt ("Bloom") != 0; + effect = IniInt ("Effect"); + flat = IniInt ("Flat") != 0; + fog_distance = WORLD_HALF; + //clear the viewport so the user isn't looking at trash while the program starts + glViewport (0, 0, WinWidth (), WinHeight ()); + glClearColor (0.0f, 0.0f, 0.0f, 1.0f); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SwapBuffers (hDC); + RenderResize (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderFPSToggle () +{ + + show_fps = !show_fps; + IniIntSet ("ShowFPS", show_fps ? 1 : 0); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool RenderFog () +{ + + return show_fog; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderFogToggle () +{ + + show_fog = !show_fog; + IniIntSet ("ShowFog", show_fog ? 1 : 0); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderLetterboxToggle () +{ + + letterbox = !letterbox; + IniIntSet ("Letterbox", letterbox ? 1 : 0); + RenderResize (); + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderWireframeToggle () +{ + + show_wireframe = !show_wireframe; + IniIntSet ("Wireframe", show_wireframe ? 1 : 0); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool RenderWireframe () +{ + + return show_wireframe; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderEffectCycle () +{ + + effect = (effect + 1) % EFFECT_COUNT; + IniIntSet ("Effect", effect); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool RenderBloom () +{ + + return effect == EFFECT_BLOOM || effect == EFFECT_BLOOM_RADIAL + || effect == EFFECT_DEBUG_OVERBLOOM || effect == EFFECT_COLOR_CYCLE; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool RenderFlat () +{ + + return flat; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderFlatToggle () +{ + + flat = !flat; + IniIntSet ("Flat", flat ? 1 : 0); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderHelpToggle () +{ + + show_help = !show_help; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +float RenderFogDistance () +{ + + return fog_distance; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void RenderUpdate (void) +{ + + GLvector pos; + GLvector angle; + GLrgba color; + + glViewport (0, 0, WinWidth (), WinHeight ()); + glClearColor (0.0f, 0.0f, 0.0f, 1.0f); + if (letterbox) + glViewport (0, letterbox_offset, render_width, render_height); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glShadeModel(GL_SMOOTH); + glFogi (GL_FOG_MODE, GL_LINEAR); + if (show_fog) { + glEnable (GL_FOG); + glFogf (GL_FOG_START, fog_distance - 100); + glFogf (GL_FOG_END, fog_distance); + color = glRgba (0.0f); + glFogfv (GL_FOG_COLOR, &color.red); + } else + glDisable (GL_FOG); + //glEnable (GL_COLOR_MATERIAL); + glDepthFunc(GL_LEQUAL); + glEnable(GL_DEPTH_TEST); + glEnable (GL_CULL_FACE); + glCullFace (GL_BACK); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glMatrixMode (GL_TEXTURE); + glLoadIdentity(); + glMatrixMode (GL_MODELVIEW); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + glLoadIdentity(); + glLineWidth (2.0f); + pos = CameraPosition (); + angle = CameraAngle (); + glRotatef (angle.x, 1.0f, 0.0f, 0.0f); + glRotatef (angle.y, 0.0f, 1.0f, 0.0f); + glRotatef (angle.z, 0.0f, 0.0f, 1.0f); + glTranslatef (-pos.x, -pos.y, -pos.z); + glEnable (GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + //Render all the stuff in the whole entire world. + SkyRender (); + WorldRender (); + if (effect == EFFECT_GLASS_CITY) { + glDisable (GL_CULL_FACE); + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthFunc (false); + glDisable(GL_DEPTH_TEST); + glMatrixMode (GL_TEXTURE); + glTranslatef ((pos.x + pos.z) / SEGMENTS_PER_TEXTURE, 0, 0); + glMatrixMode (GL_MODELVIEW); + } else { + glEnable (GL_CULL_FACE); + glDisable (GL_BLEND); + } + EntityRender (); + LightRender (); + CarRender (); + if (show_wireframe) { + glDisable (GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + EntityRender (); + } + //do_effects (EntityReady () ? effect : -1); + do_effects (effect); + //Framerate tracker + if (GetTickCount () > next_fps) { + current_fps = frames; + frames = 0; + next_fps = GetTickCount () + 1000; + } + if (show_fps && !show_help) { + RenderPrint (1, "FPS=%d", current_fps); + RenderPrint (2, "Entities=%d", EntityCount () + LightCount () + CarCount ()); + RenderPrint (3, "Lights=%d", LightCount ()); + RenderPrint (4, "Polys=%d", EntityPolyCount () + LightCount () + CarCount ()); + RenderPrint (5, "Building=%1.2f", EntityProgress () * 100); + } + //Show the help overlay + if (show_help) + do_help (); + glDepthMask (true); + frames++; + SwapBuffers (hDC); + +} diff --git a/Render.h b/Render.h new file mode 100644 index 0000000..cb45449 --- /dev/null +++ b/Render.h @@ -0,0 +1,24 @@ +bool RenderBloom (); +void RenderEffectCycle (); +bool RenderFlat (); +void RenderFlatToggle (); +float RenderFogDistance (); +bool RenderFog (); +void RenderFogToggle (); +void RenderFPSToggle (); +void RenderInit (); +void RenderLetterboxToggle (); +void RenderResize (); +void RenderTerm (); +void RenderUpdate (); +bool RenderWireframe (); +void RenderWireframeToggle (); +void RenderHelpToggle (); +void RenderPrint (int x, int y, int font, GLrgba color, const char *fmt, ...); + + + + + + + diff --git a/Sky.cpp b/Sky.cpp new file mode 100644 index 0000000..4324654 --- /dev/null +++ b/Sky.cpp @@ -0,0 +1,146 @@ +/*----------------------------------------------------------------------------- + + Sky.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + Did this need to be written as a class? It did not. There will never be + more than one sky in play, so the whole class structure here is superflous, + but harmless. + +-----------------------------------------------------------------------------*/ + +#define SKYPOINTS 24 + +#include +#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 (!RenderFog ()) + return; + glDepthMask (false); + glPushAttrib (GL_POLYGON_BIT | GL_FOG_BIT); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable (GL_FOG); + glDisable (GL_CULL_FACE); + glPushMatrix (); + glLoadIdentity(); + angle = CameraAngle (); + position = CameraPosition (); + glRotatef (angle.x, 1.0f, 0.0f, 0.0f); + glRotatef (angle.y, 0.0f, 1.0f, 0.0f); + glRotatef (angle.z, 0.0f, 0.0f, 1.0f); + glTranslatef (0.0f, -position.y / 100.0f, 0.0f); + glEnable (GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_SKY)); + glCallList (m_list); + glEnable (GL_BLEND); + glBindTexture(GL_TEXTURE_2D, TextureId (TEXTURE_CLOUDS)); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCallList (m_list); + glPopMatrix (); + glPopAttrib (); + glDepthMask (true); + glEnable (GL_COLOR_MATERIAL); + + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CSky::CSky () +{ + + GLvertex circle[SKYPOINTS]; + GLvector pos; + float angle; + int i; + float size; + float rad; + float lum; + + size = 10.0f; + for (i = 0; i < SKYPOINTS; i++) { + angle = (float)i / (float)(SKYPOINTS - 1); + angle *= 360; + angle *= DEGREES_TO_RADIANS; + circle[i].position.x = sinf (angle) * size; + circle[i].position.y = 0.1f; + circle[i].position.z = cosf (angle) * size; + circle[i].uv.x = ((float)i / (float)(SKYPOINTS - 1)) * 5.0f; + circle[i].uv.y = 0.5f; + rad = ((float)i / (SKYPOINTS - 1)) * 180.0f * DEGREES_TO_RADIANS; + lum = sinf (rad); + lum = (float)pow (lum, 5); + circle[i].color = glRgba (lum); + } + m_list = glGenLists(1); + glNewList (m_list, GL_COMPILE); + glColor3f (1, 1, 1); + + glBegin (GL_QUAD_STRIP); + for (i = 0; i < SKYPOINTS; i++) { + glTexCoord2f (circle[i].uv.x, 0.0f); + glVertex3fv (&circle[i].position.x); + pos = circle[i].position; + pos.y = size / 3.5f; + glTexCoord2f (circle[i].uv.x, 1.0f); + glVertex3fv (&pos.x); + } + glEnd (); + glEndList(); + glEndList(); + sky = this; + +} \ No newline at end of file diff --git a/Sky.h b/Sky.h new file mode 100644 index 0000000..8269261 --- /dev/null +++ b/Sky.h @@ -0,0 +1,24 @@ +#define SKY_GRID 21 +#define SKY_HALF (SKY_GRID / 2) + +struct sky_point +{ + GLrgba color; + GLvector position; +}; + +class CSky +{ +private: + int m_list; + int m_stars_list; + sky_point m_grid[SKY_GRID][SKY_GRID]; + +public: + CSky (); + void Render (void); + +}; + +void SkyRender (); +void SkyClear (); diff --git a/Texture.cpp b/Texture.cpp new file mode 100644 index 0000000..f0124f0 --- /dev/null +++ b/Texture.cpp @@ -0,0 +1,887 @@ +/*----------------------------------------------------------------------------- + + Texture.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This procedurally builds all of the textures. + + I apologize in advance for the apalling state of this module. It's the victim + of iterative and experimental development. It has cruft, poorly named + functions, obscure code, poorly named variables, a is poorly organized. Even + the formatting sucks in places. Its only saving grace is that it works. + +-----------------------------------------------------------------------------*/ + +#define RANDOM_COLOR_SHIFT ((float)(RandomVal (10)) / 50.0f) +#define RANDOM_COLOR_VAL ((float)(RandomVal (256)) / 256.0f) +#define RANDOM_COLOR_LIGHT ((float)(200 + RandomVal (56)) / 256.0f) +#define SKY_BANDS (sizeof (sky_pos) / sizeof (int)) +#define PREFIX_COUNT (sizeof (prefix) / sizeof (char*)) +#define SUFFIX_COUNT (sizeof (suffix) / sizeof (char*)) +#define NAME_COUNT (sizeof (name) / sizeof (char*)) + +#include +#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" + +static char* prefix[] = +{ + "i", + "Green ", + "Mega", + "Super ", + "Omni", + "e", + "Hyper", + "Global ", + "Vital", + "Next ", + "Pacific ", + "Metro", + "Unity ", + "G-", + "Trans", + "Infinity ", + "Superior ", + "Monolith ", + "Best ", + "Atlantic ", + "First ", + "Union ", + "National ", +}; + +static char* name[] = +{ + "Biotic", + "Info", + "Data", + "Solar", + "Aerospace", + "Motors", + "Nano", + "Online", + "Circuits", + "Energy", + "Med", + "Robotic", + "Exports", + "Security", + "Systems", + "Financial", + "Industrial", + "Media", + "Materials", + "Foods", + "Networks", + "Shipping", + "Tools", + "Medical", + "Publishing", + "Enterprises", + "Audio", + "Health", + "Bank", + "Imports", + "Apparel", + "Petroleum", + "Studios", +}; + +static char* suffix[] = +{ + "Corp", + " Inc.", + "Co", + "World", + ".Com", + " USA", + " Ltd.", + "Net", + " Tech", + " Labs", + " Mfg.", + " UK", + " Unlimited", + " One", +}; + +class CTexture +{ +public: + int _my_id; + unsigned _glid; + int _size; + int _half; + int _segment_size; + bool _ready; + bool _masked; + bool _mipmap; + bool _clamp; +public: + CTexture* _next; + CTexture (int id, int size, bool mipmap, bool clamp, bool masked); + void Clear () { _ready = false; } + void Rebuild (); + void DrawWindows (); +}; + +static CTexture* head; +static bool textures_done; +static GLrgba horizon_color; +static GLrgba cloud_color; +static bool prefix_used[PREFIX_COUNT]; +static bool name_used[NAME_COUNT]; +static bool suffix_used[SUFFIX_COUNT]; +static int build_time; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void drawrect_simple (int left, int top, int right, int bottom, GLrgba color) +{ + + glColor3fv (&color.red); + glBegin (GL_QUADS); + glVertex2i (left, top); + glVertex2i (right, top); + glVertex2i (right, bottom); + glVertex2i (left, bottom); + glEnd (); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void drawrect_simple (int left, int top, int right, int bottom, GLrgba color1, GLrgba color2) +{ + + glColor3fv (&color1.red); + glBegin (GL_TRIANGLE_FAN); + glVertex2i ((left + right) / 2, (top + bottom) / 2); + glColor3fv (&color2.red); + glVertex2i (left, top); + glVertex2i (right, top); + glVertex2i (right, bottom); + glVertex2i (left, bottom); + glVertex2i (left, top); + glEnd (); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void drawrect (int left, int top, int right, int bottom, GLrgba color) +{ + + float average; + float hue; + int potential; + int repeats; + int height; + int i, j; + bool bright; + GLrgba color_noise; + + glDisable (GL_CULL_FACE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); + glLineWidth (1.0f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glColor3fv (&color.red); + + if (left == right) { //in low resolution, a "rect" might be 1 pixel wide + glBegin (GL_LINES); + glVertex2i (left, top); + glVertex2i (left, bottom); + glEnd (); + } if (top == bottom) { //in low resolution, a "rect" might be 1 pixel wide + glBegin (GL_LINES); + glVertex2i (left, top); + glVertex2i (right, top); + glEnd (); + } else { // draw one of those fancy 2-dimensional rectangles + glBegin (GL_QUADS); + glVertex2i (left, top); + glVertex2i (right, top); + glVertex2i (right, bottom); + glVertex2i (left, bottom); + glEnd (); + + + average = (color.red + color.blue + color.green) / 3.0f; + bright = average > 0.5f; + potential = (int)(average * 255.0f); + + if (bright) { + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBegin (GL_POINTS); + for (i = left + 1; i < right - 1; i++) { + for (j = top + 1; j < bottom - 1; j++) { + glColor4i (255, 0, RandomVal (potential), 255); + hue = 0.2f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f + (float)RandomVal (100) / 300.0f; + color_noise = glRgbaFromHsl (hue, 0.3f, 0.5f); + color_noise.alpha = (float)RandomVal (potential) / 144.0f; + glColor4f (RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, RANDOM_COLOR_VAL, (float)RandomVal (potential) / 144.0f); + glColor4fv (&color_noise.red); + glVertex2i (i, j); + } + } + glEnd (); + } + repeats = RandomVal (6) + 1; + height = (bottom - top) + (RandomVal (3) - 1) + (RandomVal(3) - 1); + for (i = left; i < right; i++) { + if (RandomVal (3) == 0) + repeats = RandomVal (4) + 1; + if (RandomVal (6) == 0) { + height = bottom - top; + height = RandomVal (height); + height = RandomVal (height); + height = RandomVal (height); + height = ((bottom - top) + height) / 2; + } + for (j = 0; j < 1; j++) { + glBegin (GL_LINES); + glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f); + glVertex2i (i, bottom - height); + glColor4f (0, 0, 0, (float)RandomVal (256) / 256.0f); + glVertex2i (i, bottom); + glEnd (); + } + } + } +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void window (int x, int y, int size, int id, GLrgba color) +{ + + int margin; + int half; + int i; + + margin = size / 3; + half = size / 2; + //color = (color * 0.9f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT); + //glColor3fv (&color.red); + switch (id) { + case TEXTURE_BUILDING1: //filled, 1-pixel frame + drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); + break; + case TEXTURE_BUILDING2: //vertical + drawrect (x + margin, y + 1, x + size - margin, y + size - 1, color); + break; + case TEXTURE_BUILDING3: //side-by-side pair + drawrect (x + 1, y + 1, x + half - 1, y + size - margin, color); + drawrect (x + half + 1, y + 1, x + size - 1, y + size - margin, color); + break; + case TEXTURE_BUILDING4: //windows with blinds + drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); + i = RandomVal (size - 2); + drawrect (x + 1, y + 1, x + size - 1, y + i + 1, color * 0.3f); + + break; + case TEXTURE_BUILDING5: //vert stripes + drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); + drawrect (x + margin, y + 1, x + margin, y + size - 1, color * 0.7f); + drawrect (x + size - margin - 1, y + 1, x + size - margin - 1, y + size - 1, color * 0.3f); + break; + case TEXTURE_BUILDING6: //wide horz line + drawrect (x + 1, y + 1, x + size - 1, y + size - margin, color); + break; + case TEXTURE_BUILDING7: //4-pane + drawrect (x + 2, y + 1, x + size - 1, y + size - 1, color); + drawrect (x + 2, y + half, x + size - 1, y + half, color * 0.2f); + drawrect (x + half, y + 1, x + half, y + size - 1, color * 0.2f); + break; + case TEXTURE_BUILDING8: // Single narrow window + drawrect (x + half - 1, y + 1, x + half + 1, y + size - margin, color); + break; + case TEXTURE_BUILDING9: //horizontal + drawrect (x + 1, y + margin, x + size - 1, y + size - margin - 1, color); + break; + } + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void do_bloom (CTexture* t) +{ + + glBindTexture(GL_TEXTURE_2D, 0); + glViewport(0, 0, t->_size , t->_size); + glCullFace (GL_BACK); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask (true); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_DEPTH_TEST); + glEnable (GL_CULL_FACE); + glCullFace (GL_BACK); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_FOG); + glFogf (GL_FOG_START, RenderFogDistance () / 2); + glFogf (GL_FOG_END, RenderFogDistance ()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glClearColor (0.0f, 0.0f, 0.0f, 0.0f); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + WorldRender (); + glEnable (GL_TEXTURE_2D); + EntityRender (); + CarRender (); + LightRender (); + glBindTexture(GL_TEXTURE_2D, t->_glid); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, t->_size, t->_size, 0); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +CTexture::CTexture (int id, int size, bool mipmap, bool clamp, bool masked) +{ + + glGenTextures (1, &_glid); + _my_id = id; + _mipmap = mipmap; + _clamp = clamp; + _masked = masked; + _size = size; + _half = size / 2; + _segment_size = size / SEGMENTS_PER_TEXTURE; + _ready = false; + _next = head; + head = this; + +} + +/*----------------------------------------------------------------------------- + + This draws all of the windows on a building texture. lit_density controls + how many lights are on. (1 in n chance that the light is on. Higher values + mean less lit windows. run_length controls how often it will consider + changing the lit / unlit status. 1 produces a complete scatter, higher + numbers make long strings of lights. + +-----------------------------------------------------------------------------*/ + +void CTexture::DrawWindows () +{ + + + int x, y; + int run; + int run_length; + int lit_density; + GLrgba color; + bool lit; + + //color = glRgbaUnique (_my_id); + for (y = 0; y < SEGMENTS_PER_TEXTURE; y++) { + //Every few floors we change the behavior + if (!(y % 8)) { + run = 0; + run_length = RandomVal (9) + 2; + lit_density = 2 + RandomVal(2) + RandomVal(2); + lit = false; + } + for (x = 0; x < SEGMENTS_PER_TEXTURE; x++) { + //if this run is over reroll lit and start a new one + if (run < 1) { + run = RandomVal (run_length); + lit = RandomVal (lit_density) == 0; + //if (lit) + //color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT); + } + if (lit) + color = glRgba (0.5f + (float)(RandomVal () % 128) / 256.0f) + glRgba (RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT, RANDOM_COLOR_SHIFT); + else + color = glRgba ((float)(RandomVal () % 40) / 256.0f); + window (x * _segment_size, y * _segment_size, _segment_size, _my_id, color); + run--; + + } + } + +} + +/*----------------------------------------------------------------------------- + + Here is where ALL of the procedural textures are created. It's filled with + obscure logic, magic numbers, and messy code. Part of this is because + there is a lot of "art" being done here, and lots of numbers that could be + endlessly tweaked. Also because I'm lazy. + +-----------------------------------------------------------------------------*/ + +void CTexture::Rebuild () +{ + + int i, j; + int x, y; + int name_num, prefix_num, suffix_num; + float radius; + GLvector2 pos; + GLrgba color; + bool use_framebuffer; + unsigned char* bits; + unsigned start; + int lapsed; + + start = GetTickCount (); + glBindTexture(GL_TEXTURE_2D, _glid); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (_clamp) { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + //Set up our viewport so that drawing into our texture will be as easy + //as possible. We make the viewport and projection simply match the given + //texture size. + glViewport(0, 0, _size , _size); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, _size, _size, 0, 0.1f, 2048); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity(); + glDisable (GL_CULL_FACE); + glBindTexture(GL_TEXTURE_2D, 0); + glTranslatef(0, 0, -10.0f); + glClearColor (0, 0, 0, _masked ? 0.0f : 1.0f); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + use_framebuffer = true; + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + switch (_my_id) { + case TEXTURE_GROUND: + unsigned char icolor[4]; + char cell; + + //memset (buffer, 0, 1024 * 1024 * 4); + bits = new unsigned char[_size * _size * 4]; + ZeroMemory (bits, sizeof (bits)); + icolor[3] = 255; + for (x = 0; x < _size; x++) { + for (y = 0; y < _size; y++) { + cell = WorldCell (x, y); + memset (icolor, 0, 3); + if (cell & CLAIM_ROAD) + icolor[0] = icolor[1] = icolor[2] = 12; + if (cell == CLAIM_WALK) + icolor[0] = icolor[1] = icolor[2] = 64; + icolor[0] += (unsigned char)RandomVal (4); + icolor[1] += (unsigned char)RandomVal (4); + icolor[2] += (unsigned char)RandomVal (4); + if (1) { //use this to make the road lanes visible + if (cell & MAP_ROAD_EAST) + icolor[0] += 128; + if (cell & MAP_ROAD_WEST) + icolor[1] += 128; + if (cell & MAP_ROAD_NORTH) + icolor[2] += 128; + if (cell & MAP_ROAD_SOUTH) { + icolor[1] += 64; + icolor[2] += 64; + } + } + memcpy (&bits[(x + y * _size) * 4], &icolor[0], 4); + } + } + glBindTexture(GL_TEXTURE_2D, _glid); + + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits); + use_framebuffer = false; + delete bits; + break; + case TEXTURE_LATTICE: + glLineWidth (2.0f); + + glColor3f (0,0,0); + glBegin (GL_LINES); + glVertex2i (0, 0); glVertex2i (_size, _size);//diagonal + glVertex2i (0, 0); glVertex2i (0, _size);//vertical + glVertex2i (0, 0); glVertex2i (_size, 0);//vertical + glEnd (); + glBegin (GL_LINE_STRIP); + glVertex2i (0, 0); + for (i = 0; i < _size; i += 9) { + if (i % 2) + glVertex2i (0, i); + else + glVertex2i (i, i); + } + for (i = 0; i < _size; i += 9) { + if (i % 2) + glVertex2i (i, 0); + else + glVertex2i (i, i); + } + glEnd (); + break; + case TEXTURE_SOFT_CIRCLE: + //Make a simple circle of light, bright in the center and fading out + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + radius = ((float)_half) - 3; + glBegin (GL_TRIANGLE_FAN); + glColor4f (1, 1, 1, 1); + glVertex2i (_half, _half); + glColor4f (0, 0, 0, 0); + for (i = 0; i <= 360; i++) { + pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius; + pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius; + glVertex2i (_half + (int)pos.x, _half + (int)pos.y); + } + glEnd (); + break; + case TEXTURE_LIGHT: + // + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + radius = ((float)_half) - 3; + for (j = 0; j < 2; j++) { + glBegin (GL_TRIANGLE_FAN); + glColor4f (1, 1, 1, 1); + glVertex2i (_half, _half); + if (!j) + radius = ((float)_half / 2); + else + radius = 8; + glColor4f (1, 1, 0, 0); + for (i = 0; i <= 360; i++) { + pos.x = sinf ((float)i * DEGREES_TO_RADIANS) * radius; + pos.y = cosf ((float)i * DEGREES_TO_RADIANS) * radius; + glVertex2i (_half + (int)pos.x, _half + (int)pos.y); + } + glEnd (); + } + break; + case TEXTURE_HEADLIGHT: + //Make a simple circle of light, bright in the center and fading out + radius = ((float)_half) - 20; + x = _half - 20; + y = _half; + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBegin (GL_TRIANGLE_FAN); + glColor4f (0.8f, 0.8f, 0.8f, 0.6f); + glVertex2i (_half - 5, y); + glColor4f (0, 0, 0, 0); + for (i = 0; i <= 360; i += 36) { + pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius; + pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius; + glVertex2i (x + (int)pos.x, _half + (int)pos.y); + } + glEnd (); + x = _half + 20; + glBegin (GL_TRIANGLE_FAN); + glColor4f (0.8f, 0.8f, 0.8f, 0.6f); + glVertex2i (_half + 5, y); + glColor4f (0, 0, 0, 0); + for (i = 0; i <= 360; i += 36) { + pos.x = sinf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius; + pos.y = cosf ((float)(i % 360) * DEGREES_TO_RADIANS) * radius; + glVertex2i (x + (int)pos.x, _half + (int)pos.y); + } + glEnd (); + x = _half - 6; + drawrect_simple (x - 3, y - 2, x + 2, y + 2, glRgba (1.0f)); + x = _half + 6; + drawrect_simple (x - 2, y - 2, x + 3, y + 2, glRgba (1.0f)); + break; + case TEXTURE_LOGOS: + i = 0; + glDepthMask (false); + glDisable (GL_BLEND); + name_num = RandomVal (NAME_COUNT); + prefix_num = RandomVal (PREFIX_COUNT); + suffix_num = RandomVal (SUFFIX_COUNT); + glColor3f (1,1,1); + while (i < _size) { + //randomly use a prefix OR suffix, but not both. Too verbose. + /* + if (COIN_FLIP) + RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", prefix[prefix_num], name[name_num]); + else + RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "%s%s", name[name_num], suffix[suffix_num]); + */ + RenderPrint (2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba (1.0f), "Pixel City"); + name_num = (name_num + 1) % NAME_COUNT; + prefix_num = (prefix_num + 1) % PREFIX_COUNT; + suffix_num = (suffix_num + 1) % SUFFIX_COUNT; + i += LOGO_PIXELS; + } + break; + case TEXTURE_CLOUDS: + int width, height; + int offset; + float scale; + + for (i = _size - 30; i > 5; i -= 1) { + x = RandomVal (_size); + y = i; + + scale = 1.0f - ((float)y / (float)_size); + width = RandomVal (_half / 2) + (int)((float)_half * scale) / 2; + scale = 1.0f - (float)y / (float)_size; + height = (int)((float)(width) * scale); + height = MAX (height, 4); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_CULL_FACE); + glEnable (GL_TEXTURE_2D); + glBindTexture (GL_TEXTURE_2D, TextureId (TEXTURE_SOFT_CIRCLE)); + glDepthMask (false); + glBegin (GL_QUADS); + for (offset = -_size; offset <= _size; offset += _size) { + for (scale = 1.0f; scale > 0.0f; scale -= 0.25f) { + int width_adjust; + int height_adjust; + float inv_scale; + + inv_scale = 1.0f - (scale); + + if (scale < 0.4f) + color = cloud_color; + else + color = glRgba (0.0f); + color.alpha = 1.0f; + glColor4fv (&color.red); + //width_adjust = (int)((1.0f - scale) * ((float)width / 2.0f)); + width_adjust = (int)((float)width / 2.0f + (int)(inv_scale * ((float)width / 2.0f))); + height_adjust = height + (int)(scale * (float)height * 0.99f); + + glTexCoord2f (0, 0); glVertex2i (offset + x - width_adjust, y + height - height_adjust); + glTexCoord2f (0, 1); glVertex2i (offset + x - width_adjust, y + height); + glTexCoord2f (1, 1); glVertex2i (offset + x + width_adjust, y + height); + glTexCoord2f (1, 0); glVertex2i (offset + x + width_adjust, y + height - height_adjust); + } + + } + glEnd (); + } + break; + case TEXTURE_TRIM: + int margin; + y = 0; + margin = MAX (TRIM_PIXELS / 4, 1); + for (x = 0; x < _size; x += TRIM_PIXELS) + drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f)); + y += TRIM_PIXELS; + for (x = 0; x < _size; x += TRIM_PIXELS * 2) + drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f)); + y += TRIM_PIXELS; + for (x = 0; x < _size; x += TRIM_PIXELS * 3) + drawrect_simple (x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f)); + y += TRIM_PIXELS; + for (x = 0; x < _size; x += TRIM_PIXELS) + drawrect_simple (x + margin, y + margin * 2, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba (1.0f), glRgba (0.5f)); + break; + case TEXTURE_SKY: + glDisable (GL_BLEND); + glBegin (GL_QUAD_STRIP); + glColor3f (0,0,0); + glVertex2i (0, _half); + glVertex2i (_size, _half); + glColor3fv (&horizon_color.red); + glVertex2i (0, _size - 2); + glVertex2i (_size, _size - 2); + glEnd (); + //Draw a bunch of little faux-buildings on the horizon. + for (i = 0; i < _size; i += 5) + drawrect (i, _size - RandomVal (8) - RandomVal (8) - RandomVal (8), i + RandomVal (9), _size, glRgba (0.0f)); + break; + default: //building textures + DrawWindows (); + break; + } + glPopMatrix (); + //Now blit the finished image into our texture + if (use_framebuffer) { + glBindTexture(GL_TEXTURE_2D, _glid); + glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _size, _size, 0); + } + if (_mipmap) { + bits = (unsigned char*)malloc (_size * _size * 4); + glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits); + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, _size, _size, GL_RGBA, GL_UNSIGNED_BYTE, bits); + free (bits); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + } else + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + //cleanup and restore the viewport + RenderResize (); + _ready = true; + lapsed = GetTickCount () - start; + build_time += lapsed; + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +unsigned TextureId (int id) +{ + + for (CTexture* t = head; t; t = t->_next) { + if (t->_my_id == id) + return t->_glid; + } + return 0; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +unsigned TextureRandomBuilding (int index) +{ + + index = abs (index) % BUILDING_COUNT; + return TextureId (TEXTURE_BUILDING1 + index); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void TextureReset (void) +{ + + float hue, sat; + + textures_done = false; + build_time = 0; + for (CTexture* t = head; t; t = t->_next) + t->Clear (); + hue = 0.5f + (float)RandomVal (20) / 100.0f; + sat = 0.1f + (float)RandomVal (80) / 100.0f; + horizon_color = glRgbaFromHsl (hue, sat, 0.15f); + cloud_color = glRgbaFromHsl (hue, 0.15f, 0.1f); + ZeroMemory (prefix_used, sizeof (prefix_used)); + ZeroMemory (name_used, sizeof (name_used)); + ZeroMemory (suffix_used, sizeof (suffix_used)); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool TextureReady () +{ + + return textures_done; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void TextureUpdate (void) +{ + + if (textures_done) { + if (!RenderBloom ()) + return; + CTexture* t; + + for (t = head; t; t = t->_next) { + if (t->_my_id != TEXTURE_BLOOM) + continue; + do_bloom (t); + return; + } + } + for (CTexture* t = head; t; t = t->_next) { + if (!t->_ready) { + t->Rebuild(); + return; + } + } + textures_done = true; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void TextureTerm (void) +{ + + CTexture* t; + + while (head) { + t = head->_next; + free (head); + head = t; + } + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void TextureInit (void) +{ + + new CTexture (TEXTURE_SKY, 512, true, false, false); + new CTexture (TEXTURE_CLOUDS, 256, true, false, true); + new CTexture (TEXTURE_LATTICE, 128, true, true, true); + new CTexture (TEXTURE_LIGHT, 128, false, false, true); + new CTexture (TEXTURE_SOFT_CIRCLE, 128, false, false, true); + new CTexture (TEXTURE_HEADLIGHT, 128, false, false, true); + new CTexture (TEXTURE_TRIM, TRIM_RESOLUTION, true, false, false); + if (SHOW_DEBUG_GROUND) + new CTexture (TEXTURE_GROUND, 1024, false, false, false); + new CTexture (TEXTURE_LOGOS, LOGO_RESOLUTION, true, false, true); + for (int i = TEXTURE_BUILDING1; i <= TEXTURE_BUILDING9; i++) + new CTexture (i, 512, true, false, false); + new CTexture (TEXTURE_BLOOM, 512, true, false, false); + int names = PREFIX_COUNT * NAME_COUNT + SUFFIX_COUNT * NAME_COUNT; + +} diff --git a/Texture.h b/Texture.h new file mode 100644 index 0000000..541017b --- /dev/null +++ b/Texture.h @@ -0,0 +1,49 @@ +#define SEGMENTS_PER_TEXTURE 64 +#define ONE_SEGMENT (1.0f / SEGMENTS_PER_TEXTURE) +#define LANES_PER_TEXTURE 8 +#define LANE_SIZE (1.0f / LANES_PER_TEXTURE) +#define LANE_PIXELS (_size / LANES_PER_TEXTURE) +#define TRIM_RESOLUTION 256 +#define TRIM_ROWS 4 +#define TRIM_SIZE (1.0f / TRIM_ROWS) +#define TRIM_PIXELS (TRIM_RESOLUTION / TRIM_ROWS) +#define LOGO_RESOLUTION 512 +#define LOGO_ROWS 16 +#define LOGO_SIZE (1.0f / LOGO_ROWS) +#define LOGO_PIXELS (LOGO_RESOLUTION / LOGO_ROWS) + +enum +{ + TEXTURE_GROUND, + TEXTURE_LIGHT, + TEXTURE_SOFT_CIRCLE, + TEXTURE_SKY, + TEXTURE_CLOUDS, + TEXTURE_LOGOS, + TEXTURE_TRIM, + TEXTURE_BLOOM, + TEXTURE_HEADLIGHT, + TEXTURE_LATTICE, + TEXTURE_BUILDING1, + TEXTURE_BUILDING2, + TEXTURE_BUILDING3, + TEXTURE_BUILDING4, + TEXTURE_BUILDING5, + TEXTURE_BUILDING6, + TEXTURE_BUILDING7, + TEXTURE_BUILDING8, + TEXTURE_BUILDING9, + TEXTURE_COUNT, +}; + +#define BUILDING_COUNT ((TEXTURE_BUILDING9 - TEXTURE_BUILDING1) + 1) + +unsigned TextureFromName (char* name); +unsigned TextureId (int id); +void TextureInit (void); +void TextureTerm (void); +unsigned TextureRandomBuilding (int index); +bool TextureReady (); +void TextureReset (void); +void TextureUpdate (void); + diff --git a/Visible.cpp b/Visible.cpp new file mode 100644 index 0000000..c4c227a --- /dev/null +++ b/Visible.cpp @@ -0,0 +1,132 @@ +/*----------------------------------------------------------------------------- + + Visible.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This module runs the visibility grid, a 2-dimensional array that aids in + culling objects during rendering. + + There are many ways this could be refined or sped up, although tests indicate + it's not a huge drain on performance. + +-----------------------------------------------------------------------------*/ + + +#include +#include + +#include "glTypes.h" +#include "camera.h" +#include "macro.h" +#include "math.h" +#include "visible.h" +#include "world.h" + +static bool vis_grid[GRID_SIZE][GRID_SIZE]; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool Visible (GLvector pos) +{ + + return vis_grid[WORLD_TO_GRID(pos.x)][WORLD_TO_GRID(pos.z)]; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool Visible (int x, int z) +{ + + return vis_grid[x][z]; + +} + + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void VisibleUpdate (void) +{ + + GLvector angle; + GLvector position; + int x, y, grid_x, grid_z; + int left, right, front, back; + float angle_to; + float angle_diff; + float target_x, target_z; + + LIMIT_INTERVAL (50); + //Clear the visibility table + ZeroMemory (vis_grid, sizeof (vis_grid)); + //Calculate which cell the camera is in + angle = CameraAngle (); + position = CameraPosition (); + grid_x = WORLD_TO_GRID(position.x); + grid_z = WORLD_TO_GRID(position.z); + //Cells directly adjactent to the camera might technically fall out of the fov, + //but still have a few objects poking into screenspace when looking up or down. + //Rather than obsess over sorting those objects properly, it's more efficient to + //just mark them visible. + left = right = front = back = 3; + //Looking north, can't see south. + if (angle.y < 45.0f || angle.y > 315.0f) + front = 0; + //Looking south, can't see north + if (angle.y > 135.0f && angle.y < 225.0f) + back = 0; + //Looking east, can't see west + if (angle.y > 45.0f && angle.y < 135.0f) + left = 0; + //Looking west, can't see east + if (angle.y > 225.0f && angle.y < 315.0f) + right = 0; + //Now mark the block around us the might be visible + for (x = grid_x - left; x <= grid_x + right; x++) { + if (x < 0 || x >= WORLD_SIZE) //just in case the camera leaves the world map + continue; + for (y = grid_z - back; y <= grid_z + front; y++) { + if (y < 0 || y >= WORLD_SIZE) //just in case the camera leaves the world map + continue; + vis_grid[x][y] = true; + } + } + //Doesn't matter where we are facing, objects in current cell are always visible + vis_grid[grid_x][grid_z] = true; + //Here, we look at the angle from the current camera position to the cell + //on the grid, and how much that angle deviates from the current view angle. + for (x = 0; x < GRID_SIZE; x++) { + for (y = 0; y < GRID_SIZE; y++) { + //if we marked it visible earlier, skip all this math + if (vis_grid[x][y]) + continue; + //if the camera is to the left of this cell, use the left edge + if (grid_x < x) + target_x = (float)x * GRID_RESOLUTION; + else + target_x = (float)(x + 1) * GRID_RESOLUTION; + if (grid_z < y) + target_z = (float)y * GRID_RESOLUTION; + else + target_z = (float)(y + 1) * GRID_RESOLUTION; + angle_to = 180 - MathAngle (target_x, target_z, position.x, position.z); + //Store how many degrees the cell is to the + angle_diff = (float)fabs (MathAngleDifference (angle.y, angle_to)); + vis_grid[x][y] = angle_diff < 45; + } + } + + +} + diff --git a/Visible.h b/Visible.h new file mode 100644 index 0000000..329c0a9 --- /dev/null +++ b/Visible.h @@ -0,0 +1,11 @@ +#define GRID_RESOLUTION 32 +#define GRID_CELL (GRID_RESOLUTION / 2) +#define GRID_SIZE (WORLD_SIZE / GRID_RESOLUTION) +#define WORLD_TO_GRID(x) (int)(x / GRID_RESOLUTION) +#define GRID_TO_WORLD(x) ((float)x * GRID_RESOLUTION) + + + +void VisibleUpdate (void); +bool Visible (GLvector pos); +bool Visible (int x, int z); diff --git a/Win.cpp b/Win.cpp new file mode 100644 index 0000000..b96475f --- /dev/null +++ b/Win.cpp @@ -0,0 +1,608 @@ +/*----------------------------------------------------------------------------- + + 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, "glu32.lib") +#pragma comment (lib, "GLaux.lib") +#if SCREENSAVER +#pragma comment (lib, "scrnsave.lib") +#endif + +static HWND hwnd; +static HINSTANCE module; +static int width; +static int height; +static int half_width; +static int half_height; +static bool lmb; +static bool rmb; +static bool mouse_forced; +static POINT select_pos; +static POINT mouse_pos; + +static bool quit; +static HINSTANCE instance; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void CenterCursor () +{ + + int center_x; + int center_y; + RECT rect; + + SetCursor (NULL); + mouse_forced = true; + GetWindowRect (hwnd, &rect); + center_x = rect.left + (rect.right - rect.left) / 2; + center_y = rect.top + (rect.bottom - rect.top) / 2; + SetCursorPos (center_x, center_y); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void MoveCursor (int x, int y) +{ + + int center_x; + int center_y; + RECT rect; + + SetCursor (NULL); + mouse_forced = true; + GetWindowRect (hwnd, &rect); + center_x = rect.left + x; + center_y = rect.top + y; + SetCursorPos (center_x, center_y); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + + + RECT r; + float delta_x, delta_y; + POINT p; + int param; + int key; + + switch (message) { + case WM_SIZE: + param = wParam; // resizing flag + width = LOWORD(lParam); // width of client area + height = HIWORD(lParam); // height of client area + + if (param == SIZE_RESTORED) + IniIntSet ("WindowMaximized", 0); + if (param == SIZE_MAXIMIZED) { + IniIntSet ("WindowMaximized", 1); + } else { + IniIntSet ("WindowWidth", width); + IniIntSet ("WindowHeight", height); + } + return 0; + case WM_MOVE: + GetClientRect (hwnd, &r); + height = r.bottom - r.top; + width = r.right - r.left; + IniIntSet ("WindowX", r.left); + IniIntSet ("WindowY", r.top); + IniIntSet ("WindowWidth", width); + IniIntSet ("WindowHeight", height); + half_width = width / 2; + half_height = height / 2; + break; + case WM_KEYDOWN: + key = (int) wParam; + + if (key == 'R') + WorldReset (); + if (key == 'C') + CameraAutoToggle (); + if (key == 'W') + RenderWireframeToggle (); + if (key == 'E') + RenderEffectCycle (); + if (key == 'L') + RenderLetterboxToggle (); + if (key == 'F') + RenderFPSToggle (); + if (key == 'G') + RenderFogToggle (); + if (key == 'T') + RenderFlatToggle (); + if (key == VK_F1) + RenderHelpToggle (); + if (key == 'B') + CameraNextBehavior (); + if (key == VK_ESCAPE) + quit = true; + if (key == VK_F5) + CameraReset (); + return 0; + case WM_LBUTTONDOWN: + lmb = true; + SetCapture (hwnd); + break; + case WM_RBUTTONDOWN: + rmb = true; + SetCapture (hwnd); + break; + case WM_LBUTTONUP: + lmb = false; + if (!rmb) { + ReleaseCapture (); + MoveCursor (select_pos.x, select_pos.y); + } + break; + case WM_RBUTTONUP: + rmb = false; + if (!lmb) { + ReleaseCapture (); + MoveCursor (select_pos.x, select_pos.y); + } + break; + case WM_MOUSEMOVE: + p.x = LOWORD(lParam); // horizontal position of cursor + p.y = HIWORD(lParam); // vertical position of cursor + if (p.x < 0 || p.x > width) + break; + if (p.y < 0 || p.y > height) + break; + if (!mouse_forced && !lmb && !rmb) { + select_pos = p; + } + if (mouse_forced) { + mouse_forced = false; + } else if (rmb || lmb) { + CenterCursor (); + delta_x = (float)(mouse_pos.x - p.x) * MOUSE_MOVEMENT; + delta_y = (float)(mouse_pos.y - p.y) * MOUSE_MOVEMENT; + if (rmb && lmb) { + GLvector pos; + CameraPan (delta_x); + pos = CameraPosition (); + pos.y += delta_y; + CameraPositionSet (pos); + } else if (rmb) { + CameraPan (delta_x); + CameraForward (delta_y); + } else if (lmb) { + GLvector angle; + angle = CameraAngle (); + angle.y -= delta_x; + angle.x += delta_y; + CameraAngleSet (angle); + } + } + mouse_pos = p; + break; + case WM_CLOSE: + quit = true; + return 0; + } + return DefWindowProc(hWnd, message, wParam, lParam); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +HINSTANCE WinInstance () +{ + + return instance; + +} + +/*----------------------------------------------------------------------------- + n o t e +-----------------------------------------------------------------------------*/ + +void WinPopup (char* message, ...) +{ + + va_list marker; + char buf[1024]; + + va_start (marker, message); + vsprintf (buf, message, marker); + va_end (marker); + MessageBox (NULL, buf, APP_TITLE, MB_ICONSTOP | MB_OK | + MB_TASKMODAL); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int WinWidth (void) +{ + + return width; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WinMousePosition (int* x, int* y) +{ + + *x = select_pos.x; + *y = select_pos.y; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int WinHeight (void) +{ + + return height; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WinTerm (void) +{ +#if !SCREENAVER + DestroyWindow (hwnd); +#endif +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +HWND WinHwnd (void) +{ + + return hwnd; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +bool WinInit (void) +{ + + WNDCLASSEX wcex; + int x, y; + int style; + bool max; + + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = instance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = APP_TITLE; + wcex.hIconSm = NULL; + if (!RegisterClassEx(&wcex)) { + WinPopup ("Cannot create window class"); + return false; + } + x = IniInt ("WindowX"); + y = IniInt ("WindowY"); + style = WS_TILEDWINDOW; + style |= WS_MAXIMIZE; + width = IniInt ("WindowWidth"); + height = IniInt ("WindowHeight"); + width = CLAMP (width, 800, 2048); + height = CLAMP (height, 600, 2048); + half_width = width / 2; + half_height = height / 2; + max = IniInt ("WindowMaximized") == 1; + if (!(hwnd = CreateWindowEx (0, APP_TITLE, APP_TITLE, style, + CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, instance, NULL))) { + WinPopup ("Cannot create window"); + return false; + } + if (max) + ShowWindow (hwnd, SW_MAXIMIZE); + else + ShowWindow (hwnd, SW_SHOW); + UpdateWindow (hwnd); + return true; + +} + + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void AppQuit () +{ + + quit = true; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void AppInit (void) +{ + + RandomInit (1); + CameraInit (); + RenderInit (); + TextureInit (); + WorldInit (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void AppUpdate () +{ + + CameraUpdate (); + WorldUpdate (); + TextureUpdate (); + VisibleUpdate (); + CarUpdate (); + EntityUpdate (); + RenderUpdate (); + +} + +/*----------------------------------------------------------------------------- + W i n M a i n +-----------------------------------------------------------------------------*/ + +void AppTerm (void) +{ + + TextureTerm (); + WorldTerm (); + RenderTerm (); + CameraTerm (); + WinTerm (); + +} + +/*----------------------------------------------------------------------------- + W i n M a i n +-----------------------------------------------------------------------------*/ +#if !SCREENSAVER + +int PASCAL WinMain (HINSTANCE instance_in, HINSTANCE previous_instance, + LPSTR command_line, int show_style) +{ + + MSG msg; + + instance = instance_in; + WinInit (); + AppInit (); + while (!quit) { + if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { + if (msg.message == WM_QUIT) + quit = true; + else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } else { + AppUpdate (); + } + } + AppTerm (); + return 0; + +} + +#else + +static bool terminated; + +LONG WINAPI ScreenSaverProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + + RECT r; + float delta_x, delta_y; + POINT p; + int param; + int key; + + if (terminated) + return DefScreenSaverProc (hWnd, msg, wParam, lParam); + switch (msg) { + case WM_CREATE: + hwnd = hWnd; + AppInit (); + return 0; + case WM_CLOSE: + case WM_DESTROY: + AppTerm (); + terminated = true; + return 0; + case WM_PAINT: + AppUpdate (); + return 0; + case WM_SIZE: + param = wParam; // resizing flag + width = LOWORD(lParam); // width of client area + height = HIWORD(lParam); // height of client area + + if (param == SIZE_MAXIMIZED) { + IniIntSet ("WindowMaximized", 1); + } else { + IniIntSet ("WindowWidth", width); + IniIntSet ("WindowHeight", height); + } + return 0; + case WM_MOVE: + GetClientRect (hwnd, &r); + height = r.bottom - r.top; + width = r.right - r.left; + IniIntSet ("WindowX", r.left); + IniIntSet ("WindowY", r.top); + IniIntSet ("WindowWidth", width); + IniIntSet ("WindowHeight", height); + half_width = width / 2; + half_height = height / 2; + break; + case WM_KEYDOWN: + key = (int) wParam; + + if (key == 'R') + WorldReset (); + else if (key == 'C') + CameraAutoToggle (); + else if (key == 'W') + RenderWireframeToggle (); + else if (key == 'E') + RenderEffectCycle (); + else if (key == 'L') + RenderLetterboxToggle (); + else if (key == 'F') + RenderFPSToggle (); + else if (key == 'G') + RenderFogToggle (); + else if (key == 'T') + RenderFlatToggle (); + else if (key == VK_F1) + RenderHelpToggle (); + else if (key == VK_ESCAPE) + break; + else if (key == VK_F5) + CameraReset (); + else + break; + return 0; + case WM_LBUTTONDOWN: + lmb = true; + SetCapture (hwnd); + break; + case WM_RBUTTONDOWN: + rmb = true; + SetCapture (hwnd); + break; + case WM_LBUTTONUP: + lmb = false; + if (!rmb) { + ReleaseCapture (); + MoveCursor (select_pos.x, select_pos.y); + } + break; + case WM_RBUTTONUP: + rmb = false; + if (!lmb) { + ReleaseCapture (); + MoveCursor (select_pos.x, select_pos.y); + } + break; + case WM_MOUSEMOVE: + p.x = LOWORD(lParam); // horizontal position of cursor + p.y = HIWORD(lParam); // vertical position of cursor + if (p.x < 0 || p.x > width) + break; + if (p.y < 0 || p.y > height) + break; + if (!mouse_forced && !lmb && !rmb) { + select_pos = p; + } + if (mouse_forced) { + mouse_forced = false; + } else if (rmb || lmb) { + CenterCursor (); + delta_x = (float)(mouse_pos.x - p.x) * MOUSE_MOVEMENT; + delta_y = (float)(mouse_pos.y - p.y) * MOUSE_MOVEMENT; + if (rmb && lmb) { + GLvector pos; + CameraPan (delta_x); + pos = CameraPosition (); + pos.y += delta_y; + CameraPositionSet (pos); + } else if (rmb) { + CameraPan (delta_x); + CameraForward (delta_y); + } else if (lmb) { + GLvector angle; + angle = CameraAngle (); + angle.y -= delta_x; + angle.x += delta_y; + CameraAngleSet (angle); + } + } + mouse_pos = p; + break; + + } + return DefScreenSaverProc (hWnd, msg, wParam, lParam); + +} + +BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { return FALSE; } +BOOL WINAPI RegisterDialogClasses(HANDLE hInst) { return TRUE; } + +#endif \ No newline at end of file diff --git a/Win.h b/Win.h new file mode 100644 index 0000000..c74ac3d --- /dev/null +++ b/Win.h @@ -0,0 +1,12 @@ +#define APP_TITLE "PixelCity" +#define APP "pixelcity" +#define SCREENSAVER 0 + + +HWND WinHwnd (void); +void WinPopup (char* message, ...); +void WinTerm (void); +bool WinInit (void); +int WinWidth (void); +int WinHeight (void); +void WinMousePosition (int* x, int* y); \ No newline at end of file diff --git a/World.cpp b/World.cpp new file mode 100644 index 0000000..cad50e3 --- /dev/null +++ b/World.cpp @@ -0,0 +1,745 @@ +/*----------------------------------------------------------------------------- + + World.cpp + + 2009 Shamus Young + +------------------------------------------------------------------------------- + + This holds a bunch of variables used by the other modules. It has the + claim system, which tracks all of the "property" is being used: As roads, + buildings, etc. + +-----------------------------------------------------------------------------*/ + +#define HUE_COUNT (sizeof(hue_list)/sizeof(float)) +#define LIGHT_COLOR_COUNT (sizeof(light_colors)/sizeof(HSL)) +#define CARS 600 +#define WORLD_EDGE 200 +#if SCREENSAVER +#define RESET_INTERVAL 120 //seconds +#define FADE_TIME 500 //milliseconds +#else +#define RESET_INTERVAL 999 //seconds +#define FADE_TIME 1500 //milliseconds +#endif + +#include +#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 "world.h" + +struct plot +{ + int x; + int z; + int width; + int depth; + +}; + +enum { + FADE_IDLE, + FADE_OUT, + FADE_WAIT, + FADE_IN, +}; + +struct HSL +{ + float hue; + float sat; + float lum; +}; + +class CStreet +{ +public: + int _x; + int _y; + int _width; + int _depth; + CMesh* _mesh; + + CStreet (int x, int y, int width, int depth); + ~CStreet(); + void Render (); + +}; + +static HSL light_colors[] = +{ + 0.04f, 0.9f, 0.93f, //Amber / pink + 0.055f, 0.95f, 0.93f, //Slightly brighter amber + 0.08f, 0.7f, 0.93f, //Very pale amber + 0.07f, 0.9f, 0.93f, //Very pale orange + 0.1f, 0.9f, 0.85f, //Peach + 0.13f, 0.9f, 0.93f, //Pale Yellow + 0.15f, 0.9f, 0.93f, //Yellow + 0.17f, 1.0f, 0.85f, //Saturated Yellow + 0.55f, 0.9f, 0.93f, //Cyan + 0.55f, 0.9f, 0.93f, //Cyan - pale, almost white + 0.6f, 0.9f, 0.93f, //Pale blue + 0.65f, 0.9f, 0.93f, //Pale Blue II, The Palening + 0.65f, 0.4f, 0.99f, //Pure white. Bo-ring. + 0.65f, 0.0f, 0.8f, //Dimmer white. + 0.65f, 0.0f, 0.6f, //Dimmest white. +}; + +static float hue_list[] = { 0.04f, 0.07f, 0.1f, 0.5f, 0.6f }; //Yellows and blues - good for lights +static GLrgba bloom_color; +static long last_update; +static char world[WORLD_SIZE][WORLD_SIZE]; +static CSky* sky; +static int fade_state; +static unsigned fade_start; +static float fade_current; +static int modern_count; +static int tower_count; +static int blocky_count; +static bool reset_needed; +static int skyscrapers; +static GLbbox hot_zone; +static unsigned start_time; +static int logo_index; + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static GLrgba get_light_color (float sat, float lum) +{ + + int index; + + index = RandomVal (LIGHT_COLOR_COUNT); + return glRgbaFromHsl (light_colors[index].hue, sat, lum); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void claim (int x, int y, int width, int depth, int val) +{ + + int xx, yy; + + for (xx = x; xx < (x + width); xx++) { + for (yy = y; yy < (y + depth); yy++) { + world[CLAMP (xx,0,WORLD_SIZE - 1)][CLAMP (yy,0,WORLD_SIZE - 1)] |= val; + } + } + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static bool claimed (int x, int y, int width, int depth) +{ + + int xx, yy; + + for (xx = x; xx < x + width; xx++) { + for (yy = y; yy < y + depth; yy++) { + if (world[CLAMP (xx,0,WORLD_SIZE - 1)][CLAMP (yy,0,WORLD_SIZE - 1)]) + return true; + } + } + return false; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void build_road (int x1, int y1, int width, int depth) +{ + + int lanes; + int divider; + int sidewalk; + + //the given rectangle defines a street and its sidewalk. See which way it goes. + if (width > depth) + lanes = depth; + else + lanes = width; + //if we dont have room for both lanes and sidewalk, abort + if (lanes < 4) + return; + //if we have an odd number of lanes, give the extra to a divider. + if (lanes % 2) { + lanes--; + divider = 1; + } else + divider = 0; + //no more than 10 traffic lanes, give the rest to sidewalks + sidewalk = MAX (2, (lanes - 10)); + lanes -= sidewalk; + sidewalk /= 2; + //take the remaining space and give half to each direction + lanes /= 2; + //Mark the entire rectangle as used + claim (x1, y1, width, depth, CLAIM_WALK); + //now place the directional roads + if (width > depth) { + claim (x1, y1 + sidewalk, width, lanes, CLAIM_ROAD | MAP_ROAD_WEST); + claim (x1, y1 + sidewalk + lanes + divider, width, lanes, CLAIM_ROAD | MAP_ROAD_EAST); + } else { + claim (x1 + sidewalk, y1, lanes, depth, CLAIM_ROAD | MAP_ROAD_SOUTH); + claim (x1 + sidewalk + lanes + divider, y1, lanes, depth, CLAIM_ROAD | MAP_ROAD_NORTH); + } + //new CStreet (x1, y1, width, depth); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static plot find_plot (int x, int z) +{ + + plot p; + int x1, x2, z1, z2; + + //We've been given the location of an open bit of land, but we have no + //idea how big it is. Find the boundary. + x1 = x2 = x; + while (!claimed (x1 - 1, z, 1, 1) && x1 > 0) + x1--; + while (!claimed (x2 + 1, z, 1, 1) && x2 < WORLD_SIZE) + x2++; + z1 = z2 = z; + while (!claimed (x, z1 - 1, 1, 1) && z1 > 0) + z1--; + while (!claimed (x, z2 + 1, 1, 1) && z2 < WORLD_SIZE) + z2++; + p.width = (x2 - x1); + p.depth = (z2 - z1); + p.x = x1; + p.z = z1; + return p; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static plot make_plot (int x, int z, int width, int depth) +{ + + plot p = {x, z, width, depth}; + return p; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void do_building (plot p) +{ + + int height; + int seed; + int area; + int type; + GLrgba color; + bool square; + + //now we know how big the rectangle plot is. + area = p.width * p.depth; + color = WorldLightColor (RandomVal ()); + seed = RandomVal (); + //Make sure the plot is big enough for a building + if (p.width < 10 || p.depth < 10) + return; + //If the area is too big for one building, sub-divide it. + if (area > 600) { + if (p.width > p.depth) { + p.width /= 2; + if (COIN_FLIP) + do_building (make_plot (p.x, p.z, p.width, p.depth)); + else + do_building (make_plot (p.x + p.width, p.z, p.width, p.depth)); + return; + } else { + p.depth /= 2; + if (COIN_FLIP) + do_building (make_plot (p.x, p.z, p.width, p.depth)); + else + do_building (make_plot (p.x, p.z + p.depth, p.width, p.depth)); + return; + } + } + if (area < 100) + return; + //The plot is "square" if width & depth are close + square = abs (p.width - p.depth) < 10; + //mark the land as used so other buildings don't appear here, even if we don't use it all. + claim (p.x, p.z, p.width, p.depth, CLAIM_BUILDING); + //The roundy mod buildings look best on square plots. + if (square && p.width > 20) { + height = 45 + RandomVal (10); + modern_count++; + skyscrapers++; + new CBuilding (BUILDING_MODERN, p.x, p.z, height, p.width, p.depth, seed, color); + return; + } + //This spot isn't ideal for any particular building, but try to keep a good mix + if (tower_count < modern_count && tower_count < blocky_count) { + type = BUILDING_TOWER; + tower_count++; + } else if (blocky_count < modern_count) { + type = BUILDING_BLOCKY; + blocky_count++; + } else { + type = BUILDING_MODERN; + modern_count++; + } + height = 45 + RandomVal (10); + new CBuilding (type, p.x, p.z, height, p.width, p.depth, seed, color); + skyscrapers++; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static int build_light_strip (int x1, int z1, int direction) +{ + + CDeco* d; + GLrgba color; + int x2, z2; + int length; + int width, depth; + int dir_x, dir_z; + float size_adjust; + + //We adjust the size of the lights with this. + size_adjust = 2.5f; + color = glRgbaFromHsl (0.09f, 0.99f, 0.85f); + switch (direction) { + case NORTH: + dir_z = 1; dir_x = 0;break; + case SOUTH: + dir_z = 1; dir_x = 0;break; + case EAST: + dir_z = 0; dir_x = 1;break; + case WEST: + dir_z = 0; dir_x = 1;break; + } + //So we know we're on the corner of an intersection + //look in the given until we reach the end of the sidewalk + x2 = x1; + z2 = z1; + length = 0; + while (x2 > 0 && x2 < WORLD_SIZE && z2 > 0 && z2 < WORLD_SIZE) { + if ((world[x2][z2] & CLAIM_ROAD)) + break; + length++; + x2 += dir_x; + z2 += dir_z; + } + if (length < 10) + return length; + width = MAX (abs(x2 - x1), 1); + depth = MAX (abs(z2 - z1), 1); + d = new CDeco; + if (direction == EAST) + d->CreateLightStrip ((float)x1, (float)z1 - size_adjust, (float)width, (float)depth + size_adjust, 2, color); + else if (direction == WEST) + d->CreateLightStrip ((float)x1, (float)z1, (float)width, (float)depth + size_adjust, 2, color); + else if (direction == NORTH) + d->CreateLightStrip ((float)x1, (float)z1, (float)width + size_adjust, (float)depth, 2, color); + else + d->CreateLightStrip ((float)x1 - size_adjust, (float)z1, (float)width + size_adjust, (float)depth, 2, color); + return length; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +static void do_reset (void) +{ + + int x, y; + int width, depth, height; + int attempts; + bool broadway_done; + bool road_left, road_right; + GLrgba light_color; + GLrgba building_color; + float west_street, north_street, east_street, south_street; + + //RandomInit (6); + reset_needed = false; + broadway_done = false; + skyscrapers = 0; + logo_index = 0; + tower_count = blocky_count = modern_count = 0; + hot_zone = glBboxClear (); + EntityClear (); + LightClear (); + CarClear (); + TextureReset (); + //Pick a tint for the bloom + bloom_color = get_light_color(0.5f + (float)RandomVal (10) / 20.0f, 0.75f); + light_color = glRgbaFromHsl (0.11f, 1.0f, 0.65f); + ZeroMemory (world, WORLD_SIZE * WORLD_SIZE); + for (y = WORLD_EDGE; y < WORLD_SIZE - WORLD_EDGE; y += RandomVal (30) + 20) { + if (!broadway_done && y > WORLD_HALF - 20) { + build_road (0, y, WORLD_SIZE, 19); + y += 20; + broadway_done = true; + } else { + depth = 6 + RandomVal (6); + if (y < WORLD_HALF / 2) + north_street = (float)(y + depth / 2); + if (y < (WORLD_SIZE - WORLD_HALF / 2)) + south_street = (float)(y + depth / 2); + build_road (0, y, WORLD_SIZE, depth); + } + } + + broadway_done = false; + for (x = WORLD_EDGE; x < WORLD_SIZE - WORLD_EDGE; x += RandomVal (30) + 20) { + if (!broadway_done && x > WORLD_HALF - 20) { + build_road (x, 0, 19, WORLD_SIZE); + x += 20; + broadway_done = true; + } else { + width = 6 + RandomVal (6); + if (x <= WORLD_HALF / 2) + west_street = (float)(x + width / 2); + if (x <= WORLD_HALF + WORLD_HALF / 2) + east_street = (float)(x + width / 2); + build_road (x, 0, width, WORLD_SIZE); + } + } + //We kept track of the positions of streets that will outline the high-detail hot zone + //in the middle of the world. Save this in a bounding box so that later we can + //have the camera fly around without clipping through buildings. + hot_zone = glBboxContainPoint (hot_zone, glVector (west_street, 0.0f, north_street)); + hot_zone = glBboxContainPoint (hot_zone, glVector (east_street, 0.0f, south_street)); + + //Scan for places to put runs of streetlights on the east & west side of the road + for (x = 1; x < WORLD_SIZE - 1; x++) { + for (y = 0; y < WORLD_SIZE; y++) { + //if this isn't a bit of sidewalk, then keep looking + if (!(world[x][y] & CLAIM_WALK)) + continue; + //If it's used as a road, skip it. + if ((world[x][y] & CLAIM_ROAD)) + continue; + road_left = (world[x + 1][y] & CLAIM_ROAD) != 0; + road_right = (world[x - 1][y] & CLAIM_ROAD) != 0; + //if the cells to our east and west are not road, then we're not on a corner. + if (!road_left && !road_right) + continue; + //if the cell to our east AND west is road, then we're on a median. skip it + if (road_left && road_right) + continue; + y += build_light_strip (x, y, road_right ? SOUTH : NORTH); + } + } + //Scan for places to put runs of streetlights on the north & south side of the road + for (y = 1; y < WORLD_SIZE - 1; y++) { + for (x = 1; x < WORLD_SIZE - 1; x++) { + //if this isn't a bit of sidewalk, then keep looking + if (!(world[x][y] & CLAIM_WALK)) + continue; + //If it's used as a road, skip it. + if ((world[x][y] & CLAIM_ROAD)) + continue; + road_left = (world[x][y + 1] & CLAIM_ROAD) != 0; + road_right = (world[x][y - 1] & CLAIM_ROAD) != 0; + //if the cell to our east AND west is road, then we're on a median. skip it + if (road_left && road_right) + continue; + //if the cells to our north and south are not road, then we're not on a corner. + if (!road_left && !road_right) + continue; + x += build_light_strip (x, y, road_right ? EAST : WEST); + } + } + + //Scan over the center area of the map and place the big buildings + attempts = 0; + while (skyscrapers < 50 && attempts < 350) { + x = (WORLD_HALF / 2) + (RandomVal () % WORLD_HALF); + y = (WORLD_HALF / 2) + (RandomVal () % WORLD_HALF); + if (!claimed (x, y, 1,1)) { + do_building (find_plot (x, y)); + skyscrapers++; + } + attempts++; + } + //now blanket the rest of the world with lesser buildings + for (x = 0; x < WORLD_SIZE; x ++) { + for (y = 0; y < WORLD_SIZE; y ++) { + if (world[CLAMP (x,0,WORLD_SIZE)][CLAMP (y,0,WORLD_SIZE)]) + continue; + width = 12 + RandomVal (20); + depth = 12 + RandomVal (20); + height = MIN (width, depth); + if (x < 30 || y < 30 || x > WORLD_SIZE - 30 || y > WORLD_SIZE - 30) + height = RandomVal (15) + 20; + else if (x < WORLD_HALF / 2) + height /= 2; + while (width > 8 && depth > 8) { + if (!claimed (x, y, width, depth)) { + claim (x, y, width, depth,CLAIM_BUILDING); + building_color = WorldLightColor (RandomVal ()); + //if we're out of the hot zone, use simple buildings + if (x < hot_zone.min.x || x > hot_zone.max.x || y < hot_zone.min.z || y > hot_zone.max.z) { + height = 5 + RandomVal (height) + RandomVal (height); + new CBuilding (BUILDING_SIMPLE, x + 1, y + 1, height, width - 2, depth - 2, RandomVal (), building_color); + } else { //use fancy buildings. + height = 15 + RandomVal (15); + width -=2; + depth -=2; + if (COIN_FLIP) + new CBuilding (BUILDING_TOWER, x + 1, y + 1, height, width, depth, RandomVal (), building_color); + else + new CBuilding (BUILDING_BLOCKY, x + 1, y + 1, height, width, depth, RandomVal (), building_color); + } + break; + } + width--; + depth--; + } + //leave big gaps near the edge of the map, no need to pack detail there. + if (y < WORLD_EDGE || y > WORLD_SIZE - WORLD_EDGE) + y += 32; + } + //leave big gaps near the edge of the map + if (x < WORLD_EDGE || x > WORLD_SIZE - WORLD_EDGE) + x += 28; + } + +} + +/*----------------------------------------------------------------------------- + + This will return a random color which is suitible for light sources, taken + from a narrow group of hues. (Yellows, oranges, blues.) + +-----------------------------------------------------------------------------*/ + +GLrgba WorldLightColor (unsigned index) +{ + + index %= LIGHT_COLOR_COUNT; + return glRgbaFromHsl (light_colors[index].hue, light_colors[index].sat, light_colors[index].lum); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +char WorldCell (int x, int y) +{ + + return world[CLAMP (x, 0,WORLD_SIZE - 1)][CLAMP (y, 0, WORLD_SIZE - 1)]; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLrgba WorldBloomColor () +{ + + return bloom_color; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +int WorldLogoIndex () +{ + + return logo_index++; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLbbox WorldHotZone () +{ + + return hot_zone; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WorldTerm (void) +{ + + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WorldReset (void) +{ + + //If we're already fading out, then this is the developer hammering on the + //"rebuild" button. Let's hurry things up for the nice man... + if (fade_state == FADE_OUT) + do_reset (); + //If reset is called but the world isn't ready, then don't bother fading out. + //The program probably just started. + fade_state = FADE_OUT; + fade_start = GetTickCount (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WorldRender () +{ + + //Cheap - render the crappy one-texture streets + if (!SHOW_DEBUG_GROUND) + return; + glDepthMask (false); + glDisable (GL_CULL_FACE); + glDisable (GL_BLEND); + glEnable (GL_TEXTURE_2D); + glColor3f (1,1,1); + glBindTexture (GL_TEXTURE_2D, TextureId (TEXTURE_GROUND)); + glBegin (GL_QUADS); + glTexCoord2f (0, 0); glVertex3f ( 0., 0, 0); + glTexCoord2f (0, 1); glVertex3f ( 0, 0, 1024); + glTexCoord2f (1, 1); glVertex3f ( 1024, 0, 1024); + glTexCoord2f (1, 0); glVertex3f ( 1024, 0, 0); + glEnd (); + glDepthMask (true); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +float WorldFade (void) +{ + + return fade_current; + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WorldUpdate (void) +{ + + unsigned fade_delta; + unsigned now, elapsed; + + now = GetTickCount (); + if (reset_needed) { + do_reset (); //Now we've faded out the scene, rebuild it + } + if (fade_state != FADE_IDLE) { + if (fade_state == FADE_WAIT && TextureReady () && EntityReady ()) { + fade_state = FADE_IN; + fade_start = now; + fade_current = 1.0f; + } + fade_delta = now - fade_start; + //See if we're done fading in or out + if (fade_delta > FADE_TIME && fade_state != FADE_WAIT) { + if (fade_state == FADE_OUT) { + reset_needed = true; + fade_state = FADE_WAIT; + fade_current = 1.0f; + } else { + fade_state = FADE_IDLE; + fade_current = 0.0f; + start_time = time (NULL); + } + } else { + fade_current = (float)fade_delta / FADE_TIME; + if (fade_state == FADE_IN) + fade_current = 1.0f - fade_current; + if (fade_state == FADE_WAIT) + fade_current = 1.0f; + } + if (!TextureReady ()) + fade_current = 1.0f; + } + if (fade_state == FADE_IDLE && !TextureReady ()) { + fade_state = FADE_IN; + fade_start = now; + } + elapsed = time (NULL) - start_time; + if (fade_state == FADE_IDLE && elapsed > RESET_INTERVAL) + WorldReset (); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +void WorldInit (void) +{ + + last_update = GetTickCount (); + for (int i = 0; i < CARS; i++) + new CCar (); + sky = new CSky (); + WorldReset (); + fade_state = FADE_OUT; + fade_start = 0; + +} diff --git a/World.h b/World.h new file mode 100644 index 0000000..20926f7 --- /dev/null +++ b/World.h @@ -0,0 +1,35 @@ +#define SHOW_DEBUG_GROUND 0 + +#define WORLD_SIZE 1024 +#define WORLD_HALF (WORLD_SIZE / 2) + +#define CLAIM_ROAD 1 +#define CLAIM_WALK 2 +#define CLAIM_BUILDING 4 +#define MAP_ROAD_NORTH 8 +#define MAP_ROAD_SOUTH 16 +#define MAP_ROAD_EAST 32 +#define MAP_ROAD_WEST 64 +#define RANDOM_COLOR (glRgbaFromHsl ((float)RandomVal (255)/255,1.0f, 0.75f)) + +enum +{ + NORTH, + EAST, + SOUTH, + WEST +}; + +GLrgba WorldBloomColor (); +char WorldCell (int x, int y); +GLrgba WorldLightColor (unsigned index); +int WorldLogoIndex (); +GLbbox WorldHotZone (); +void WorldInit (void); +float WorldFade (void); +void WorldRender (); +void WorldReset (void); +void WorldTerm (void); +void WorldUpdate (void); + + diff --git a/foo.h b/foo.h new file mode 100644 index 0000000..7dd814e --- /dev/null +++ b/foo.h @@ -0,0 +1,74 @@ +i +Green +Mega +Super +Omni +e +Hyper +Global +Vital +Next +Pacific +Metro +Unity +G- +Trans +Infinity +Superior +Monolith +Best +Atlantic +First +Union +National + + +Biotic +Info +Data +Solar +Aerospace +Motors +Nano +Online +Circuits +Energy +Med +Robotic +Exports +Security +Systems +Financial +Industrial +Media +Materials +Foods +Networks +Shipping +Tools +Medical +Publishing +Enterpise +Audio +Health +Bank +Imports +Apparel +Petroleum +Studios + + +Corp + Inc. +Co +World +.Com + USA + Ltd. +Net + Tech + Labs + Mfg. + UK + Unlimited + One \ No newline at end of file diff --git a/glBbox.cpp b/glBbox.cpp new file mode 100644 index 0000000..d2af243 --- /dev/null +++ b/glBbox.cpp @@ -0,0 +1,70 @@ +/*----------------------------------------------------------------------------- + + glBbox.cpp + + 2006 Shamus Young + +------------------------------------------------------------------------------- + + This module has a few functions useful for manipulating the bounding-box + structs. + +-----------------------------------------------------------------------------*/ + +#define MAX_VALUE 999999999999999.9f + +#include + +#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; + +} + + diff --git a/glMatrix.cpp b/glMatrix.cpp new file mode 100644 index 0000000..31770ff --- /dev/null +++ b/glMatrix.cpp @@ -0,0 +1,324 @@ +/*----------------------------------------------------------------------------- + + glMatrix.cpp + + 2006 Shamus Young + +------------------------------------------------------------------------------- + + Functions useful for manipulating the Matrix struct + +-----------------------------------------------------------------------------*/ + + +#define M(e,x,y) (e.elements[x][y]) + +/*** Order type constants, constructors, extractors ***/ + + /* There are 24 possible conventions, designated by: */ + /* o EulAxI = axis used initially */ + /* o EulPar = parity of axis permutation */ + /* o EulRep = repetition of initial axis as last */ + /* o EulFrm = frame from which axes are taken */ + /* Axes I,J,K will be a permutation of X,Y,Z. */ + /* Axis H will be either I or K, depending on EulRep. */ + /* Frame S takes axes from initial static frame. */ + /* If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then */ + /* {a,b,c,ord} means Rz(c)Ry(b)Rx(a), where Rz(c)v */ + /* rotates v around Z by c radians. */ + +#define EulFrmS 0 +#define EulFrmR 1 +#define EulFrm(ord) ((unsigned)(ord)&1) +#define EulRepNo 0 +#define EulRepYes 1 +#define EulRep(ord) (((unsigned)(ord)>>1)&1) +#define EulParEven 0 +#define EulParOdd 1 +#define EulPar(ord) (((unsigned)(ord)>>2)&1) +#define EulSafe "\000\001\002\000" +#define EulNext "\001\002\000\001" +#define EulAxI(ord) ((int)(EulSafe[(((unsigned)(ord)>>3)&3)])) +#define EulAxJ(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)==EulParOdd)])) +#define EulAxK(ord) ((int)(EulNext[EulAxI(ord)+(EulPar(ord)!=EulParOdd)])) +#define EulAxH(ord) ((EulRep(ord)==EulRepNo)?EulAxK(ord):EulAxI(ord)) + /* EulGetOrd unpacks all useful information about order simultaneously. */ +#define EulGetOrd(ord,i,j,k,h,n,s,f) {unsigned o=ord;f=o&1;o>>=1;s=o&1;o>>=1;\ + n=o&1;o>>=1;i=EulSafe[o&3];j=EulNext[i+n];k=EulNext[i+1-n];h=s?k:i;} + /* EulOrd creates an order value between 0 and 23 from 4-tuple choices. */ +#define EulOrd(i,p,r,f) (((((((i)<<1)+(p))<<1)+(r))<<1)+(f)) + /* Static axes */ +#define EulOrdXYZs EulOrd(X,EulParEven,EulRepNo,EulFrmS) +#define EulOrdXYXs EulOrd(X,EulParEven,EulRepYes,EulFrmS) +#define EulOrdXZYs EulOrd(X,EulParOdd,EulRepNo,EulFrmS) +#define EulOrdXZXs EulOrd(X,EulParOdd,EulRepYes,EulFrmS) +#define EulOrdYZXs EulOrd(Y,EulParEven,EulRepNo,EulFrmS) +#define EulOrdYZYs EulOrd(Y,EulParEven,EulRepYes,EulFrmS) +#define EulOrdYXZs EulOrd(Y,EulParOdd,EulRepNo,EulFrmS) +#define EulOrdYXYs EulOrd(Y,EulParOdd,EulRepYes,EulFrmS) +#define EulOrdZXYs EulOrd(Z,EulParEven,EulRepNo,EulFrmS) +#define EulOrdZXZs EulOrd(Z,EulParEven,EulRepYes,EulFrmS) +#define EulOrdZYXs EulOrd(Z,EulParOdd,EulRepNo,EulFrmS) +#define EulOrdZYZs EulOrd(Z,EulParOdd,EulRepYes,EulFrmS) + /* Rotating axes */ +#define EulOrdZYXr EulOrd(X,EulParEven,EulRepNo,EulFrmR) +#define EulOrdXYXr EulOrd(X,EulParEven,EulRepYes,EulFrmR) +#define EulOrdYZXr EulOrd(X,EulParOdd,EulRepNo,EulFrmR) +#define EulOrdXZXr EulOrd(X,EulParOdd,EulRepYes,EulFrmR) +#define EulOrdXZYr EulOrd(Y,EulParEven,EulRepNo,EulFrmR) +#define EulOrdYZYr EulOrd(Y,EulParEven,EulRepYes,EulFrmR) +#define EulOrdZXYr EulOrd(Y,EulParOdd,EulRepNo,EulFrmR) +#define EulOrdYXYr EulOrd(Y,EulParOdd,EulRepYes,EulFrmR) +#define EulOrdYXZr EulOrd(Z,EulParEven,EulRepNo,EulFrmR) +#define EulOrdZXZr EulOrd(Z,EulParEven,EulRepYes,EulFrmR) +#define EulOrdXYZr EulOrd(Z,EulParOdd,EulRepNo,EulFrmR) +#define EulOrdZYZr EulOrd(Z,EulParOdd,EulRepYes,EulFrmR) + +//EulerAngles Eul_(float ai, float aj, float ah, int order); +//Quat Eul_ToQuat(EulerAngles ea); +//void Eul_ToHMatrix(EulerAngles ea, HMatrix M); +//EulerAngles Eul_FromHMatrix(HMatrix M, int order); +//EulerAngles Eul_FromQuat(Quat q, int order); + +#include +#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); +} diff --git a/glQuat.cpp b/glQuat.cpp new file mode 100644 index 0000000..fb7dd17 --- /dev/null +++ b/glQuat.cpp @@ -0,0 +1,78 @@ +/*----------------------------------------------------------------------------- + + 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)); +} diff --git a/glRgba.cpp b/glRgba.cpp new file mode 100644 index 0000000..38c7848 --- /dev/null +++ b/glRgba.cpp @@ -0,0 +1,401 @@ +/*----------------------------------------------------------------------------- + + 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); +} \ No newline at end of file diff --git a/glTypes.h b/glTypes.h new file mode 100644 index 0000000..0be898e --- /dev/null +++ b/glTypes.h @@ -0,0 +1,209 @@ +#ifndef glTYPES +#define glTYPES + +#define GL_CLAMP_TO_EDGE 0x812F + +#define OPERATORS(type) \ + type operator+ (const type& c); \ + type operator+ (const float& c);\ + void operator+= (const type& c);\ + void operator+= (const float& c);\ + type operator- (const type& c);\ + type operator- (const float& c);\ + void operator-= (const type& c);\ + void operator-= (const float& c);\ + type operator* (const type& c);\ + type operator* (const float& c);\ + void operator*= (const type& c);\ + void operator*= (const float& c);\ + type operator/ (const type& c);\ + type operator/ (const float& c);\ + void operator/= (const type& c);\ + void operator/= (const float& c);\ + bool operator== (const type& c); + + +#define JOINT_MAX_CHILDREN 8 + +struct GLquat +{ + float x; + float y; + float z; + float w; +}; + +struct GLvector +{ + float x; + float y; + float z; + OPERATORS(GLvector); +}; + +typedef GLvector GLvector3; + +struct GLvector2 +{ + float x; + float y; + OPERATORS(GLvector2); +}; + +struct GLrgba +{ + float red; + float green; + float blue; + float alpha; + OPERATORS(GLrgba); +}; + +struct GLmatrix +{ + float elements[4][4]; +}; + +struct GLbbox +{ + GLvector3 min; + GLvector3 max; +}; + +struct GLvertex +{ + GLvector3 position; + GLvector2 uv; + GLrgba color; + int bone; +}; + +struct GLrect +{ + float left; + float top; + float right; + float bottom; +}; + +struct GLtriangle +{ + int v1; + int v2; + int v3; + int normal1; + int normal2; + int normal3; +}; + +/* +class GLmodel +{ +public: + unsigned vertex_count; + unsigned triangle_count; + unsigned normal_count; + GLvertex* vertex; + GLvector* normal; + GLtriangle* triangle; + + void TriangleRender (unsigned n); + GLtriangle* TriangleAdd (unsigned v1, int unsigned, int unsigned); + GLtriangle* TriangleAdd (GLtriangle c); + void NormalAdd (GLvector n); + void VertexAdd (GLvertex v); + GLmodel (); + ~GLmodel (); + void Render (); + GLbbox BBox (); +private: + GLbbox m_bbox; + +}; + +struct GLkeyframe +{ + float time; + GLvector offset; + GLvector rotation; +}; + +struct GLsegment +{ + int index; + GLvector rotation; + GLvector offset; + GLkeyframe keyframes[255]; + int frame_count; +}; + +class GLanimate +{ +public: + GLanimate (); + void KeyframeAdd (int joint, float time, GLquat q); + void TimeSet (float time); + void PositionSet (float pos); + GLvector Rotation (int); + GLvector Offset (int); + +private: + GLsegment* m_segments; + int m_segment_count; + float m_length; +}; +*/ + +GLbbox glBboxClear (void); +GLbbox glBboxContainPoint (GLbbox box, GLvector point); +bool glBboxTestPoint (GLbbox box, GLvector point); + +GLrgba glRgba (char* string); +GLrgba glRgba (float red, float green, float blue); +GLrgba glRgba (float luminance); +GLrgba glRgba (float red, float green, float blue, float alpha); +GLrgba glRgba (long c); +GLrgba glRgba (int red, int green, int blue); +GLrgba glRgbaAdd (GLrgba c1, GLrgba c2); +GLrgba glRgbaSubtract (GLrgba c1, GLrgba c2); +GLrgba glRgbaInterpolate (GLrgba c1, GLrgba c2, float delta); +GLrgba glRgbaScale (GLrgba c, float scale); +GLrgba glRgbaMultiply (GLrgba c1, GLrgba c2); +GLrgba glRgbaUnique (int i); +GLrgba glRgbaFromHsl (float h, float s, float l); + +GLmatrix glMatrixIdentity (void); +void glMatrixElementsSet (GLmatrix* m, float* in); +GLmatrix glMatrixMultiply (GLmatrix a, GLmatrix b); +GLvector glMatrixTransformPoint (GLmatrix m, GLvector in); +GLmatrix glMatrixTranslate (GLmatrix m, GLvector in); +GLmatrix glMatrixRotate (GLmatrix m, float theta, float x, float y, float z); +GLvector glMatrixToEuler (GLmatrix mat, int order); + +GLquat glQuat (float x, float y, float z, float w); +GLvector glQuatToEuler (GLquat q, int order); + +GLvector glVector (float x, float y, float z); +GLvector glVectorCrossProduct (GLvector v1, GLvector v2); +float glVectorDotProduct (GLvector v1, GLvector v2); +void glVectorGl (GLvector v); +GLvector glVectorInterpolate (GLvector v1, GLvector v2, float scalar); +float glVectorLength (GLvector v); +GLvector glVectorNormalize (GLvector v); +GLvector glVectorReflect (GLvector3 ray, GLvector3 normal); + +GLvector2 glVector (float x, float y); +GLvector2 glVectorAdd (GLvector2 val1, GLvector2 val2); +GLvector2 glVectorSubtract (GLvector2 val1, GLvector2 val2); +GLvector2 glVectorNormalize (GLvector2 v); +GLvector2 glVectorInterpolate (GLvector2 v1, GLvector2 v2, float scalar); +GLvector2 glVectorSinCos (float angle); +float glVectorLength (GLvector2 v); + + +#endif + +#ifndef NULL +#define NULL 0 +#endif + diff --git a/glVector2.cpp b/glVector2.cpp new file mode 100644 index 0000000..e7d08dc --- /dev/null +++ b/glVector2.cpp @@ -0,0 +1,223 @@ +/*----------------------------------------------------------------------------- + + 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; +} \ No newline at end of file diff --git a/glVector3.cpp b/glVector3.cpp new file mode 100644 index 0000000..cffa549 --- /dev/null +++ b/glVector3.cpp @@ -0,0 +1,257 @@ +/*----------------------------------------------------------------------------- + + 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 glVectorSubtract (ray, glVectorScale (normal, 2.0f * dot)); + return ray - (normal * (2.0f * dot)); + +} + + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVector (float x, float y, float z) +{ + + GLvector3 result; + + result.x = x; + result.y = y; + result.z = z; + return result; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVectorInterpolate (GLvector3 v1, GLvector3 v2, float scalar) +{ + + GLvector3 result; + + result.x = MathInterpolate (v1.x, v2.x, scalar); + result.y = MathInterpolate (v1.y, v2.y, scalar); + result.z = MathInterpolate (v1.z, v2.z, scalar); + return result; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +float glVectorLength (GLvector3 v) +{ + + return (float)sqrt (v.x * v.x + v.y * v.y + v.z * v.z); + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +float glVectorDotProduct (GLvector3 v1, GLvector3 v2) +{ + + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVectorCrossProduct (GLvector3 v1, GLvector3 v2) +{ + + GLvector3 result; + + result.x = v1.y * v2.z - v2.y * v1.z; + result.y = v1.z * v2.x - v2.z * v1.x; + result.z = v1.x * v2.y - v2.x * v1.y; + return result; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVectorInvert (GLvector3 v) +{ + + v.x *= -v.x; + v.y *= -v.y; + v.z *= -v.z; + return v; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVectorScale (GLvector3 v, float scale) +{ + + v.x *= scale; + v.y *= scale; + v.z *= scale; + return v; + +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ + +GLvector3 glVectorNormalize (GLvector3 v) +{ + + float length; + + length = glVectorLength (v); + if (length < 0.000001f) + return v; + return glVectorScale (v, 1.0f / length); + +} + +/*----------------------------------------------------------------------------- ++ +-----------------------------------------------------------------------------*/ + +GLvector GLvector::operator+ (const GLvector& c) +{ + return glVector (x + c.x, y + c.y, z + c.z); +} + +GLvector GLvector::operator+ (const float& c) +{ + return glVector (x + c, y + c, z + c); +} + +void GLvector::operator+= (const GLvector& c) +{ + x += c.x; + y += c.y; + z += c.z; +} + +void GLvector::operator+= (const float& c) +{ + x += c; + y += c; + z += c; +} + +GLvector GLvector::operator- (const GLvector& c) +{ + return glVector (x - c.x, y - c.y, z - c.z); +} + +GLvector GLvector::operator- (const float& c) +{ + return glVector (x - c, y - c, z - c); +} + +void GLvector::operator-= (const GLvector& c) +{ + x -= c.x; + y -= c.y; + z -= c.z; +} + +void GLvector::operator-= (const float& c) +{ + x -= c; + y -= c; + z -= c; +} + +GLvector GLvector::operator* (const GLvector& c) +{ + return glVector (x * c.x, y * c.y, z * c.z); +} + +GLvector GLvector::operator* (const float& c) +{ + return glVector (x * c, y * c, z * c); +} + +void GLvector::operator*= (const GLvector& c) +{ + x *= c.x; + y *= c.y; + z *= c.z; +} + +void GLvector::operator*= (const float& c) +{ + x *= c; + y *= c; + z *= c; +} + +GLvector GLvector::operator/ (const GLvector& c) +{ + return glVector (x / c.x, y / c.y, z / c.z); +} + +GLvector GLvector::operator/ (const float& c) +{ + return glVector (x / c, y / c, z / c); +} + +void GLvector::operator/= (const GLvector& c) +{ + x /= c.x; + y /= c.y; + z /= c.z; +} + +void GLvector::operator/= (const float& c) +{ + x /= c; + y /= c; + z /= c; +} + +bool GLvector::operator== (const GLvector& c) +{ + if (x == c.x && y == c.y && z == c.z) + return true; + return false; +} \ No newline at end of file