void TerraformPrepare () { int x, y; Region r; GLcoord from_center; GLcoord offset; //Set some defaults offset.x = RandomVal () % 1024; offset.y = RandomVal () % 1024; for (x = 0; x < WORLD_GRID; x++) { for (y = 0; y < WORLD_GRID; y++) { memset (&r, 0, sizeof (Region)); sprintf (r.title, "NOTHING"); r.geo_bias = r.geo_detail = 0; r.mountain_height = 0; r.grid_pos.x = x; r.grid_pos.y = y; r.tree_threshold = 0.15f; from_center.x = abs (x - WORLD_GRID_CENTER); from_center.y = abs (y - WORLD_GRID_CENTER); //Geo scale is a number from -1 to 1. -1 is lowest ocean. 0 is sea level. //+1 is highest elevation on the island. This is used to guide other derived numbers. r.geo_scale = glVectorLength (glVector ((float)from_center.x, (float)from_center.y)); r.geo_scale /= (WORLD_GRID_CENTER - OCEAN_BUFFER); //Create a steep drop around the edge of the world if (r.geo_scale > 1.0f) r.geo_scale = 1.0f + (r.geo_scale - 1.0f) * 4.0f; r.geo_scale = 1.0f - r.geo_scale; r.geo_scale += (Entropy ((x + offset.x), (y + offset.y)) - 0.5f); r.geo_scale += (Entropy ((x + offset.x) * FREQUENCY, (y + offset.y) * FREQUENCY) - 0.2f); r.geo_scale = clamp (r.geo_scale, -1.0f, 1.0f); if (r.geo_scale > 0.0f) r.geo_water = 1.0f + r.geo_scale * 16.0f; r.color_atmosphere = glRgba (0.0f, 0.0f, 0.0f); r.geo_bias = 0.0f; r.geo_detail = 0.0f; r.color_map = glRgba (0.0f); r.climate = CLIMATE_INVALID; WorldRegionSet (x, y, r); } } }
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); }
//Drop a point in the middle of the terrain and attempt to //place a river. void TerraformRivers (int count) { int rivers; int cycles; int x, y; int range; rivers = 0; cycles = 0; range = WORLD_GRID_CENTER / 3; while (rivers < count && cycles < 100) { x = WORLD_GRID_CENTER + (RandomVal () % range) - range / 2; y = WORLD_GRID_CENTER + (RandomVal () % range) - range / 2; if (try_river (x, y, rivers)) rivers++; cycles++; } }
//look around the map and find an unused area of the desired size static bool find_plot (int radius, GLcoord* result) { int cycles; GLcoord test; cycles = 0; while (cycles < 20) { cycles++; test.x = RandomVal () % WORLD_GRID; test.y = RandomVal () % WORLD_GRID; if (is_free (test.x, test.y, radius)) { *result = test; return true; } } //couldn't find a spot. Map is full, or just bad dice rolls. return false; }
void CBuilding::ConstructCube (int left, int right, int front, int back, int bottom, int top) { GLvertex p[10]; float x1, x2, z1, z2, y1, y2; int i; cube c; float u, v1, v2; float mapping; int base_index; int height; height = top - bottom; x1 = (float)left; x2 = (float)right; y1 = (float)bottom; y2 = (float)top; z1 = (float)front; z2 = (float)back; base_index = _mesh->VertexCount (); mapping = (float)SEGMENTS_PER_TEXTURE; u = (float)(RandomVal () % SEGMENTS_PER_TEXTURE) / (float)SEGMENTS_PER_TEXTURE; v1 = (float)bottom / (float)mapping; v2 = (float)top / (float)mapping; p[0].position = glVector (x1, y1, z1); p[0].uv = glVector (u, v1); p[1].position = glVector (x1, y2, z1); p[1].uv = glVector (u, v2); u += (float)_width / mapping; p[2].position = glVector (x2, y1, z1); p[2].uv = glVector (u, v1); p[3].position = glVector (x2, y2, z1); p[3].uv = glVector (u, v2); u += (float)_depth / mapping; p[4].position = glVector (x2, y1, z2); p[4].uv = glVector (u, v1); p[5].position = glVector (x2, y2, z2); p[5].uv = glVector (u, v2); u += (float)_width / mapping; p[6].position = glVector (x1, y1, z2); p[6].uv = glVector (u, v1); p[7].position = glVector (x1, y2, z2); p[7].uv = glVector (u, v2); u += (float)_width / mapping; p[8].position = glVector (x1, y1, z1); p[8].uv = glVector (u, v1); p[9].position = glVector (x1, y2, z1); p[9].uv = glVector (u, v2); for (i = 0; i < 10; i++) { p[i].uv.x = (p[i].position.x + p[i].position.z) / (float)SEGMENTS_PER_TEXTURE; _mesh->VertexAdd (p[i]); c.index_list.push_back(base_index + i); } _mesh->CubeAdd (c); }
static void window (int x, int y, int size, int id, GLrgba color) { int margin; int half; int i; margin = size / 3; half = size / 2; switch (id) { case TEXTURE_BUILDING1: //filled, 1-pixel frame drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); break; case TEXTURE_BUILDING2: //vertical drawrect (x + margin, y + 1, x + size - margin, y + size - 1, color); break; case TEXTURE_BUILDING3: //side-by-side pair drawrect (x + 1, y + 1, x + half - 1, y + size - margin, color); drawrect (x + half + 1, y + 1, x + size - 1, y + size - margin, color); break; case TEXTURE_BUILDING4: //windows with blinds drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); i = RandomVal (size - 2); drawrect (x + 1, y + 1, x + size - 1, y + i + 1, color * 0.3f); break; case TEXTURE_BUILDING5: //vert stripes drawrect (x + 1, y + 1, x + size - 1, y + size - 1, color); drawrect (x + margin, y + 1, x + margin, y + size - 1, color * 0.7f); drawrect (x + size - margin - 1, y + 1, x + size - margin - 1, y + size - 1, color * 0.3f); break; case TEXTURE_BUILDING6: //wide horz line drawrect (x + 1, y + 1, x + size - 1, y + size - margin, color); break; case TEXTURE_BUILDING7: //4-pane drawrect (x + 2, y + 1, x + size - 1, y + size - 1, color); drawrect (x + 2, y + half, x + size - 1, y + half, color * 0.2f); drawrect (x + half, y + 1, x + half, y + size - 1, color * 0.2f); break; case TEXTURE_BUILDING8: // Single narrow window drawrect (x + half - 1, y + 1, x + half + 1, y + size - margin, color); break; case TEXTURE_BUILDING9: //horizontal drawrect (x + 1, y + margin, x + size - 1, y + size - margin - 1, color); break; } }
CBuilding::CBuilding (int type, int x, int y, int height, int width, int depth, int seed, GLrgba color) { _x = x; _y = y; _width = width; _depth = depth; _height = height; _center = glVector ((float)(_x + width / 2), 0.0f, (float)(_y + depth / 2)); _seed = seed; _texture_type = RandomVal (); _color = color; _color.alpha = 0.1f; _have_lights = false; _have_logo = false; _have_trim = false; _roof_tiers = 0; //Pick a color for logos & roof lights _trim_color = WorldLightColor (seed); _mesh = new CMesh; //The main textured mesh for the building _mesh_flat = new CMesh; //Flat-color mesh for untextured detail items. switch (type) { case BUILDING_SIMPLE: CreateSimple (); break; case BUILDING_MODERN: CreateModern (); break; case BUILDING_TOWER: CreateTower (); break; case BUILDING_BLOCKY: CreateBlocky (); break; } }
void CTexture::DrawWindows() { int x, y; int run = 0; int run_length = 2; int lit_density = 2; GLrgba color; bool lit = false; //color = glRgbaUnique (_my_id); for (y = 0; y < SEGMENTS_PER_TEXTURE; y++) { //Every few floors we change the behavior if ((y % 8) == 0) { 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--; } } }
//Gives a 1 in 'odds' chance of adding flowers to the given region void add_flowers (Region* r, unsigned odds) { GLrgba c; int shape; r->has_flowers = RandomVal () % odds == 0; shape = RandomVal (); c = flower_palette[RandomVal () % FLOWER_PALETTE]; for (int i = 0; i < FLOWERS; i++) { r->color_flowers[i] = c; r->flower_shape[i] = shape; if ((RandomVal () % 15) == 0) { shape = RandomVal (); c = flower_palette[RandomVal () % FLOWER_PALETTE]; } } }
void CBuilding::CreateTower () { int left, right, front, back, bottom; int section_height, section_width, section_depth; int remaining_height; int ledge_height; int tier_fraction; int grouping; int foundation; int narrowing_interval; int tiers; float ledge; float uv_start; bool blank_corners; bool roof_spike; bool tower; //How much ledges protrude from the building ledge = (float)RandomVal (3) * 0.25f; //How tall the ledges are, in stories ledge_height = RandomVal (4) + 1; //How the windows are grouped grouping = RandomVal (3) + 2; //if the corners of the building have no windows blank_corners = RandomVal (4) > 0; //if the roof is pointed or has infrastructure on it roof_spike = RandomVal (3) == 0; //What fraction of the remaining height should be given to each tier tier_fraction = 2 + RandomVal (4); //How often (in tiers) does the building get narrorwer? narrowing_interval = 1 + RandomVal (10); //The height of the windowsless slab at the bottom foundation = 2 + RandomVal (3); //The odds that we'll have a big fancy spikey top tower = RandomVal (5) != 0 && _height > 40; //set our initial parameters left = _x; right = _x + _width; front = _y; back = _y + _depth; bottom = 0; tiers = 0; //build the foundations. ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)foundation); bottom += foundation; //now add tiers until we reach the top while (1) { remaining_height = _height - bottom; section_depth = back - front; section_width = right - left; section_height = MAX (remaining_height / tier_fraction, 2); if (remaining_height < 10) section_height = remaining_height; //Build the four walls uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE; uv_start = ConstructWall (left, bottom, back, SOUTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (left, bottom, front, EAST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (right, bottom, front, NORTH, section_depth, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (right, bottom, back, WEST, section_width, section_height, grouping, uv_start, blank_corners) - ONE_SEGMENT; bottom += section_height; //Build the slab / ledges to cap this section. if (bottom + ledge_height > _height) break; ConstructCube ((float)left - ledge, (float)right + ledge, (float)front - ledge, (float)back + ledge, (float)bottom, (float)(bottom + ledge_height)); bottom += ledge_height; if (bottom > _height) break; tiers++; if ((tiers % narrowing_interval) == 0) { if (section_width > 7) { left+=1; right-=1; } if (section_depth > 7) { front+=1; back-=1; } } } ConstructRoof ((float)left, (float)right, (float)front, (float)back, (float)bottom); _mesh->Compile (); _mesh_flat->Compile (); }
void CBuilding::CreateModern () { GLvertex p; GLvector center; GLvector pos; GLvector2 radius; GLvector2 start, end; int angle; int windows; int cap_height; int half_depth, half_width; float dist; float length; quad_strip qs; fan f; int points; int skip_interval; int skip_counter; int skip_delta; int i; bool logo_done; bool do_trim; CDeco* d; logo_done = false; //How tall the windowless section on top will be. cap_height = 1 + RandomVal (5); //How many 10-degree segments to build before the next skip. skip_interval = 1 + RandomVal (8); //When a skip happens, how many degrees should be skipped skip_delta = (1 + RandomVal (2)) * 30; //30 60 or 90 //See if this is eligible for fancy lighting trim on top if (_height > 48 && RandomVal (3) == 0) do_trim = true; else do_trim = false; //Get the center and radius of the circle half_depth = _depth / 2; half_width = _width / 2; center = glVector ((float)(_x + half_width), 0.0f, (float)(_y + half_depth)); radius = glVector ((float)half_width, (float)half_depth); dist = 0; windows = 0; p.uv.x = 0.0f; points = 0; skip_counter = 0; for (angle = 0; angle <= 360; angle += 10) { if (skip_counter >= skip_interval && (angle + skip_delta < 360)) { angle += skip_delta; skip_counter = 0; } pos.x = center.x - sinf ((float)angle * DEGREES_TO_RADIANS) * radius.x; pos.z = center.z + cosf ((float)angle * DEGREES_TO_RADIANS) * radius.y; if (angle > 0 && skip_counter == 0) { length = MathDistance (p.position.x, p.position.z, pos.x, pos.z); windows += (int)length; if (length > 10 && !logo_done) { logo_done = true; start = glVector (pos.x, pos.z); end = glVector (p.position.x, p.position.z); d = new CDeco; d->CreateLogo (start, end, (float)_height, WorldLogoIndex (), RANDOM_COLOR); } } else if (skip_counter != 1) windows++; p.position = pos; p.uv.x = (float)windows / (float)SEGMENTS_PER_TEXTURE; p.uv.y = 0.0f; p.position.y = 0.0f; _mesh->VertexAdd (p); p.position.y = (float)_height; p.uv.y = (float)_height / (float)SEGMENTS_PER_TEXTURE; _mesh->VertexAdd (p); _mesh_flat->VertexAdd (p); p.position.y += (float)cap_height; _mesh_flat->VertexAdd (p); vector_buffer[points / 2] = p.position; vector_buffer[points / 2].y = (float)_height + cap_height / 4; points += 2; skip_counter++; } //if this is a big building and it didn't get a logo, consider giving it a light strip if (!logo_done && do_trim) { d = new CDeco; d->CreateLightTrim (vector_buffer, (points / 2) - 2, (float)cap_height / 2, _seed, RANDOM_COLOR); } qs.index_list.reserve(points); //Add the outer walls for (i = 0; i < points; i++) qs.index_list.push_back(i); _mesh->QuadStripAdd (qs); _mesh_flat->QuadStripAdd (qs); //add the fan to cap the top of the buildings f.index_list.push_back(points); for (i = 0; i < points / 2; i++) f.index_list.push_back(points - (1 + i * 2)); p.position.x = _center.x; p.position.z = _center.z; _mesh_flat->VertexAdd (p); _mesh_flat->FanAdd (f); radius /= 2.0f; //ConstructRoof ((int)(_center.x - radius), (int)(_center.x + radius), (int)(_center.z - radius), (int)(_center.z + radius), _height + cap_height); _mesh->Compile (); _mesh_flat->Compile (); }
void CBuilding::CreateSimple () { GLvertex p; float x1, x2, z1, z2, y1, y2; quad_strip qs; float u, v1, v2; float cap_height; float ledge; for(int i=0; i<10; i++) qs.index_list.push_back(i); //How tall the flat-color roof is cap_height = (float)(1 + RandomVal (4)); //how much the ledge sticks out ledge = (float)RandomVal (10) / 30.0f; x1 = (float)_x; x2 = (float)(_x + _width); y1 = (float)0.0f; y2 = (float)_height; z2 = (float)_y; z1 = (float)(_y + _depth); u = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE; v1 = (float)(RandomVal (SEGMENTS_PER_TEXTURE)) / SEGMENTS_PER_TEXTURE; v2 = v1 + (float)_height * ONE_SEGMENT; p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1); _mesh->VertexAdd (p); p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2); _mesh->VertexAdd (p); u += (float)_depth / SEGMENTS_PER_TEXTURE; p.position = glVector (x1, y1, z2); p.uv = glVector (u, v1); _mesh->VertexAdd (p); p.position = glVector (x1, y2, z2); p.uv = glVector (u, v2); _mesh->VertexAdd (p); u += (float)_width / SEGMENTS_PER_TEXTURE; p.position = glVector (x2, y1, z2); p.uv = glVector (u, v1); _mesh->VertexAdd (p); p.position = glVector (x2, y2, z2); p.uv = glVector (u, v2); _mesh->VertexAdd (p); u += (float)_depth / SEGMENTS_PER_TEXTURE; p.position = glVector (x2, y1, z1); p.uv = glVector (u, v1); _mesh->VertexAdd (p); p.position = glVector (x2, y2, z1); p.uv = glVector (u, v2); _mesh->VertexAdd (p); u += (float)_depth / SEGMENTS_PER_TEXTURE; p.position = glVector (x1, y1, z1); p.uv = glVector (u, v1); _mesh->VertexAdd (p); p.position = glVector (x1, y2, z1); p.uv = glVector (u, v2); _mesh->VertexAdd (p); _mesh->QuadStripAdd (qs); ConstructCube (x1 - ledge, x2 + ledge, z2 - ledge, z1 + ledge, (float)_height, (float)_height + cap_height); _mesh->Compile (); }
//Create zones of different climates. void TerraformZones () { int x, y; vector<Climate> climates; Region r; int radius; Climate c; GLcoord walk; UINT spinner; walk.Clear (); spinner = 0; do { x = walk.x; y = walk.y;// + WorldNoisei (walk.x + walk.y * WORLD_GRID) % 4; radius = 2 + WorldNoisei (10 + walk.x + walk.y * WORLD_GRID) % 9; if (is_free (x, y, radius)) { r = WorldRegionGet (x, y); climates.clear (); //swamps only appear in wet areas that aren't cold. if (r.moisture > 0.8f && r.temperature > 0.5f) climates.push_back (CLIMATE_SWAMP); //mountains only appear in the middle if (abs (x - WORLD_GRID_CENTER) < 10 && radius > 1) climates.push_back (CLIMATE_MOUNTAIN); //Deserts are HOT and DRY. Duh. if (r.temperature > TEMP_HOT && r.moisture < 0.05f && radius > 1) climates.push_back (CLIMATE_DESERT); //fields should be not too hot or cold. if (r.temperature > TEMP_TEMPERATE && r.temperature < TEMP_HOT && r.moisture > 0.5f && radius == 1) climates.push_back (CLIMATE_FIELD); if (r.temperature > TEMP_TEMPERATE && r.temperature < TEMP_HOT && r.moisture > 0.25f && radius > 1) climates.push_back (CLIMATE_PLAINS); //Rocky wastelands favor cold areas if (r.temperature < TEMP_TEMPERATE) climates.push_back (CLIMATE_ROCKY); if (radius > 1 && !(WorldNoisei (spinner++) % 10)) climates.push_back (CLIMATE_CANYON); if (r.temperature > TEMP_TEMPERATE && r.temperature < TEMP_HOT && r.moisture > 0.5f) climates.push_back (CLIMATE_FOREST); if (climates.empty ()) { walk.Walk (WORLD_GRID); continue; } c = climates[RandomVal () % climates.size ()]; switch (c) { case CLIMATE_ROCKY: do_rocky (x, y, radius); break; case CLIMATE_MOUNTAIN: do_mountain (x, y, radius); break; case CLIMATE_CANYON: do_canyon (x, y, radius); break; case CLIMATE_SWAMP: do_swamp (x, y, radius); break; case CLIMATE_FIELD: do_field (x, y, radius); break; case CLIMATE_DESERT: do_desert (x, y, radius); break; case CLIMATE_PLAINS: do_plains (x, y, radius); break; case CLIMATE_FOREST: do_forest (x, y, radius); break; } } } while (!walk.Walk (WORLD_GRID)); }
void CBuilding::CreateBlocky () { int min_height; int left, right, front, back; int max_left, max_right, max_front, max_back; int height; int mid_x, mid_z; int half_depth, half_width; int tiers; int max_tiers; int grouping; float lid_height; float uv_start; bool skip; bool blank_corners; //Choose if the corners of the building are to be windowless. blank_corners = COIN_FLIP; //Choose a random column on our texture; uv_start = (float)RandomVal (SEGMENTS_PER_TEXTURE) / SEGMENTS_PER_TEXTURE; //Choose how the windows are grouped grouping = 2 + RandomVal (4); //Choose how tall the lid should be on top of each section lid_height = (float)(RandomVal (3) + 1); //find the center of the building. mid_x = _x + _width / 2; mid_z = _y + _depth / 2; max_left = max_right = max_front = max_back = 1; height = _height; min_height = _height / 2; min_height = 3; half_depth = _depth / 2; half_width = _width / 2; tiers = 0; if (_height > 40) max_tiers = 15; else if (_height > 30) max_tiers = 10; else if (_height > 20) max_tiers = 5; else if (_height > 10) max_tiers = 2; else max_tiers = 1; //We begin at the top of the building, and work our way down. //Viewed from above, the sections of the building are randomly sized //rectangles that ALWAYS include the center of the building somewhere within //their area. while (1) { if (height < min_height) break; if (tiers >= max_tiers) break; //pick new locationsfor our four outer walls left = (RandomVal () % half_width) + 1; right = (RandomVal () % half_width) + 1; front = (RandomVal () % half_depth) + 1; back = (RandomVal () % half_depth) + 1; skip = false; //At least ONE of the walls must reach out beyond a previous maximum. //Otherwise, this tier would be completely hidden within a previous one. if (left <= max_left && right <= max_right && front <= max_front && back <= max_back) skip = true; //If any of the four walls is in the same position as the previous max,then //skip this tier, or else the two walls will end up z-fightng. if (left == max_left || right == max_right || front == max_front || back == max_back) skip = true; if (!skip) { //if this is the top, then put some lights up here max_left = MAX (left, max_left); max_right = MAX (right, max_right); max_front = MAX (front, max_front); max_back = MAX (back, max_back); //Now build the four walls of this part uv_start = ConstructWall (mid_x - left, 0, mid_z + back, SOUTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (mid_x - left, 0, mid_z - front, EAST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (mid_x + right, 0, mid_z - front, NORTH, front + back, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; uv_start = ConstructWall (mid_x + right, 0, mid_z + back, WEST, right + left, height, grouping, uv_start, blank_corners) - ONE_SEGMENT; if (!tiers) ConstructRoof ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height); else //add a flat-color lid onto this section ConstructCube ((float)(mid_x - left), (float)(mid_x + right), (float)(mid_z - front), (float)(mid_z + back), (float)height, (float)height + lid_height); height -= (RandomVal () % 10) + 1; tiers++; } height--; } ConstructCube (mid_x - half_width, mid_x + half_width, mid_z - half_depth, mid_z + half_depth, 0, 2); _mesh->Compile (); _mesh_flat->Compile (); }
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 = ADDON_NONE; 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); } }
//This will fill in all previously un-assigned regions. void TerraformFill () { int x, y; Region r; unsigned rand; for (x = 0; x < WORLD_GRID; x++) { for (y = 0; y < WORLD_GRID; y++) { r = WorldRegionGet (x, y); //See if this is already ocean if (r.climate != CLIMATE_INVALID) continue; sprintf (r.title, "???"); r.geo_water = r.geo_scale * 10.0f; r.geo_detail = 20.0f; //Have them trend more hilly in dry areas rand = RandomVal () % 8; if (r.moisture > 0.3f && r.temperature > 0.5f) { GLrgba c; int shape; r.has_flowers = RandomVal () % 4 == 0; shape = RandomVal (); c = flower_palette[RandomVal () % FLOWER_PALETTE]; for (int i = 0; i < FLOWERS; i++) { r.color_flowers[i] = c; r.flower_shape[i] = shape; if ((RandomVal () % 15) == 0) { shape = RandomVal (); c = flower_palette[RandomVal () % FLOWER_PALETTE]; } } } if (rand == 0) { r.flags_shape |= REGION_FLAG_MESAS; sprintf (r.title, "Mesas"); } else if (rand == 1) { sprintf (r.title, "Craters"); r.flags_shape |= REGION_FLAG_CRATER; } else if (rand == 2) { sprintf (r.title, "TEST"); r.flags_shape |= REGION_FLAG_TEST; } else if (rand == 3) { sprintf (r.title, "Sinkhole"); r.flags_shape |= REGION_FLAG_SINKHOLE; } else if (rand == 4) { sprintf (r.title, "Crack"); r.flags_shape |= REGION_FLAG_CRACK; } else if (rand == 5) { sprintf (r.title, "Tiered"); r.flags_shape |= REGION_FLAG_TIERED; } else if (rand == 6) { sprintf (r.title, "Wasteland"); } else { sprintf (r.title, "Grasslands"); //r.geo_detail /= 3; //r.geo_large /= 3; } WorldRegionSet (x, y, r); } } }
void CTexture::Rebuild() { int i, j; int x, y; int name_num, prefix_num, suffix_num; int max_size; float radius; GLvector2 pos; bool use_framebuffer; unsigned char* bits; unsigned start; int lapsed; start = GetTickCount(); //Since we make textures by drawing into the viewport, we can't make them bigger //than the current view. _size = _desired_size; max_size = RenderMaxTextureSize(); while (_size > max_size) _size /= 2; glBindTexture(GL_TEXTURE_2D, _glid); //Set up the texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _size, _size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (_clamp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } //Set up our viewport so that drawing into our texture will be as easy //as possible. We make the viewport and projection simply match the given //texture size. glViewport(0, 0, _size, _size); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, _size, _size, 0, 0.1f, 2048); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glDisable(GL_CULL_FACE); glDisable(GL_FOG); glBindTexture(GL_TEXTURE_2D, 0); glTranslatef(0, 0, -10.0f); glClearColor(0, 0, 0, _masked ? 0.0f : 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); use_framebuffer = true; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); switch (_my_id) { case TEXTURE_LATTICE: glLineWidth(2.0f); glColor3f(0, 0, 0); glBegin(GL_LINES); glVertex2i(0, 0); glVertex2i(_size, _size); //diagonal glVertex2i(0, 0); glVertex2i(0, _size); //vertical glVertex2i(0, 0); glVertex2i(_size, 0); //vertical glEnd(); glBegin(GL_LINE_STRIP); glVertex2i(0, 0); for (i = 0; i < _size; i += 9) { if (i % 2) glVertex2i(0, i); else glVertex2i(i, i); } for (i = 0; i < _size; i += 9) { if (i % 2) glVertex2i(i, 0); else glVertex2i(i, i); } glEnd(); break; case TEXTURE_SOFT_CIRCLE: //Make a simple circle of light, bright in the center and fading out glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); radius = ((float)_half) - 3; glBegin(GL_TRIANGLE_FAN); glColor4f(1, 1, 1, 1); glVertex2i(_half, _half); glColor4f(0, 0, 0, 0); for (i = 0; i <= 360; i++) { pos.x = sinf((float)i * DEGREES_TO_RADIANS) * radius; pos.y = cosf((float)i * DEGREES_TO_RADIANS) * radius; glVertex2i(_half + (int)pos.x, _half + (int)pos.y); } glEnd(); break; case TEXTURE_LIGHT: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); radius = ((float)_half) - 3; for (j = 0; j < 2; j++) { glBegin(GL_TRIANGLE_FAN); glColor4f(1, 1, 1, 1); glVertex2i(_half, _half); if (!j) radius = ((float)_half / 2); else radius = 8; glColor4f(1, 1, 1, 0); for (i = 0; i <= 360; i++) { pos.x = sinf((float)i * DEGREES_TO_RADIANS) * radius; pos.y = cosf((float)i * DEGREES_TO_RADIANS) * radius; glVertex2i(_half + (int)pos.x, _half + (int)pos.y); } glEnd(); } break; case TEXTURE_HEADLIGHT: DrawHeadlight(); break; case TEXTURE_LOGOS: i = 0; glDepthMask(false); glDisable(GL_BLEND); name_num = RandomVal(NAME_COUNT); prefix_num = RandomVal(PREFIX_COUNT); suffix_num = RandomVal(SUFFIX_COUNT); glColor3f(1, 1, 1); while (i < _size) { //randomly use a prefix OR suffix, but not both. Too verbose. if (COIN_FLIP) RenderPrint(2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba(1.0f), "%s%s", prefix[prefix_num], name[name_num]); else RenderPrint(2, _size - i - LOGO_PIXELS / 4, RandomVal(), glRgba(1.0f), "%s%s", name[name_num], suffix[suffix_num]); name_num = (name_num + 1) % NAME_COUNT; prefix_num = (prefix_num + 1) % PREFIX_COUNT; suffix_num = (suffix_num + 1) % SUFFIX_COUNT; i += LOGO_PIXELS; } break; case TEXTURE_TRIM: int margin; y = 0; margin = MAX(TRIM_PIXELS / 4, 1); for (x = 0; x < _size; x += TRIM_PIXELS) drawrect_simple(x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba(1.0f), glRgba(0.5f)); y += TRIM_PIXELS; for (x = 0; x < _size; x += TRIM_PIXELS * 2) drawrect_simple(x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba(1.0f), glRgba(0.5f)); y += TRIM_PIXELS; for (x = 0; x < _size; x += TRIM_PIXELS * 3) drawrect_simple(x + margin, y + margin, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba(1.0f), glRgba(0.5f)); y += TRIM_PIXELS; for (x = 0; x < _size; x += TRIM_PIXELS) drawrect_simple(x + margin, y + margin * 2, x + TRIM_PIXELS - margin, y + TRIM_PIXELS - margin, glRgba(1.0f), glRgba(0.5f)); break; case TEXTURE_SKY: DrawSky(); break; default: //building textures DrawWindows(); break; } glPopMatrix(); //Now blit the finished image into our texture if (use_framebuffer) { glBindTexture(GL_TEXTURE_2D, _glid); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, _size, _size, 0); } if (_mipmap) { bits = (unsigned char*)malloc(_size * _size * 4); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, _size, _size, GL_RGBA, GL_UNSIGNED_BYTE, bits); free(bits); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //cleanup and restore the viewport RenderResize(); _ready = true; lapsed = GetTickCount() - start; build_time += lapsed; }
void CTexture::DrawSky() { GLrgba color; float grey; float scale, inv_scale; int i, x, y; int width, height; int offset; int width_adjust; int height_adjust; color = WorldBloomColor(); grey = (color.red + color.green + color.blue) / 3.0f; //desaturate, slightly dim color = (color + glRgba(grey) * 2.0f) / 15.0f; glDisable(GL_BLEND); glBegin(GL_QUAD_STRIP); glColor3f(0, 0, 0); glVertex2i(0, _half); glVertex2i(_size, _half); glColor3fv(&color.red); glVertex2i(0, _size - 2); glVertex2i(_size, _size - 2); glEnd(); //Draw a bunch of little faux-buildings on the horizon. for (i = 0; i < _size; i += 5) drawrect(i, _size - RandomVal(8) - RandomVal(8) - RandomVal(8), i + RandomVal(9), _size, glRgba(0.0f)); //Draw the clouds for (i = _size - 30; i > 5; i -= 2) { x = RandomVal(_size); y = i; scale = 1.0f - ((float)y / (float)_size); width = RandomVal(_half / 2) + (int)((float)_half * scale) / 2; scale = 1.0f - (float)y / (float)_size; height = (int)((float)(width) * scale); height = MAX(height, 4); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, TextureId(TEXTURE_SOFT_CIRCLE)); glDepthMask(false); glBegin(GL_QUADS); for (offset = -_size; offset <= _size; offset += _size) { for (scale = 1.0f; scale > 0.0f; scale -= 0.25f) { inv_scale = 1.0f - (scale); if (scale < 0.4f) color = WorldBloomColor() * 0.1f; else color = glRgba(0.0f); color.alpha = 0.2f; glColor4fv(&color.red); width_adjust = (int)((float)width / 2.0f + (int)(inv_scale * ((float)width / 2.0f))); height_adjust = height + (int)(scale * (float)height * 0.99f); glTexCoord2f(0, 0); glVertex2i(offset + x - width_adjust, y + height - height_adjust); glTexCoord2f(0, 1); glVertex2i(offset + x - width_adjust, y + height); glTexCoord2f(1, 1); glVertex2i(offset + x + width_adjust, y + height); glTexCoord2f(1, 0); glVertex2i(offset + x + width_adjust, y + height - height_adjust); } } } glEnd(); }
void 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(); } } } }
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]++; }