From 0fac0228bbe9f885da378f7e5f30ac59ca0bb3f7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 7 Jun 2009 12:22:09 +0100 Subject: [PATCH] Placing of stations --- include/IMap.hpp | 9 +++- include/IStation.hpp | 14 +++++++ include/Maths.hpp | 5 +++ src/Editor.cpp | 8 ++-- src/Map.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++-- src/SmokeTrail.cpp | 14 +++---- src/Station.cpp | 26 +++++++++++- 7 files changed, 156 insertions(+), 17 deletions(-) diff --git a/include/IMap.hpp b/include/IMap.hpp index bc86621..53ca232 100644 --- a/include/IMap.hpp +++ b/include/IMap.hpp @@ -20,6 +20,7 @@ #include "IGraphics.hpp" #include "ITrackSegment.hpp" +#include "IStation.hpp" #include #include @@ -57,8 +58,10 @@ public: virtual void render(IGraphicsPtr aContext) const = 0; // Draw a white border around the given tile + typedef tuple HighlightColour; virtual void highlightTile(IGraphicsPtr aContext, - const Point& aPoint) const = 0; + const Point& aPoint, + HighlightColour aColour) const = 0; // Given a pick name return the (x, y) co-ordinate virtual Point pickPosition(unsigned aName) const = 0; @@ -90,6 +93,10 @@ public: // Make all tiles in the area the same height virtual void levelArea(Point aStartPos, Point aFinishPos) = 0; + + // Create a new station covering this area or extend an existing station + virtual IStationPtr extendStation(Point aStartPos, + Point aFinishPos) = 0; }; diff --git a/include/IStation.hpp b/include/IStation.hpp index 0721a4b..e4fe0b9 100644 --- a/include/IStation.hpp +++ b/include/IStation.hpp @@ -19,6 +19,9 @@ #define INC_ISTATION_HPP #include "Platform.hpp" +#include "Maths.hpp" + +#include // The different types of cargo that may be carried enum Cargo { @@ -31,6 +34,17 @@ enum Cargo { // are stored in the map struct IStation { virtual ~IStation() {} + + // Return or set the name of the station + // This is only used for the user's benefit and does not identify + // the station in any way + virtual const string& name() const = 0; + virtual void setName(const string& aName) = 0; + + // A station has a random colour that is used to identify it when + // the highlight is drawn + typedef tuple HighlightColour; + virtual HighlightColour highlightColour() const = 0; }; typedef std::tr1::shared_ptr IStationPtr; diff --git a/include/Maths.hpp b/include/Maths.hpp index 5cc297c..3637e1d 100644 --- a/include/Maths.hpp +++ b/include/Maths.hpp @@ -156,6 +156,11 @@ struct Point { { return aPoint.x == x && aPoint.y == y; } + + Point operator+(const Point& rhs) const + { + return Point(x + rhs.x, y + rhs.y); + } T x, y; }; diff --git a/src/Editor.cpp b/src/Editor.cpp index cbe6c5b..543306a 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -27,8 +27,6 @@ #include -using namespace std; -using namespace std::tr1; using namespace gui; // Concrete editor class @@ -165,7 +163,8 @@ void Editor::display(IGraphicsPtr aContext) const for (int x = xmin; x <= xmax; x++) { for (int y = ymin; y <= ymax; y++) - myMap->highlightTile(aContext, makePoint(x, y)); + myMap->highlightTile(aContext, makePoint(x, y), + make_tuple(1.0f, 1.0f, 1.0f)); } } } @@ -545,6 +544,9 @@ void Editor::onMouseRelease(IPickBufferPtr aPickBuffer, int x, int y, case START_TOOL: myMap->setStart(myDragBegin.x, myDragBegin.y); break; + case STATION_TOOL: + myMap->extendStation(myDragBegin, myDragEnd); + break; } amDragging = false; diff --git a/src/Map.cpp b/src/Map.cpp index f684218..57f3972 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -84,7 +84,8 @@ public: void setTrackAt(const Point& aPoint, ITrackSegmentPtr aTrack); bool isValidTrack(const Point& aPoint) const; void render(IGraphicsPtr aContext) const; - void highlightTile(IGraphicsPtr aContext, const Point& aPoint) const; + void highlightTile(IGraphicsPtr aContext, const Point& aPoint, + HighlightColour aColour) const; void resetMap(int aWidth, int aDepth); void eraseTile(int x, int y); @@ -95,6 +96,9 @@ public: void levelArea(Point aStartPos, Point aFinishPos); void save(const string& aFileName); + + IStationPtr extendStation(Point aStartPos, + Point aFinishPos); // ISectorRenderable interface void renderSector(IGraphicsPtr aContext, int id, @@ -385,17 +389,20 @@ void Map::render(IGraphicsPtr aContext) const } // Draw a thick border around a single tile -void Map::highlightTile(IGraphicsPtr aContext, const Point& aPoint) const +void Map::highlightTile(IGraphicsPtr aContext, const Point& aPoint, + HighlightColour aColour) const { // User should be able to click on the highlight as well glPushName(tileName(aPoint.x, aPoint.y)); - + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDisable(GL_LIGHTING); glPushMatrix(); - glColor4f(1.0f, 1.0f, 1.0f, 0.5f); + glColor4f(get<0>(aColour), get<1>(aColour), get<2>(aColour), 0.5f); glBegin(GL_POLYGON); int indexes[4]; @@ -410,6 +417,8 @@ void Map::highlightTile(IGraphicsPtr aContext, const Point& aPoint) const glEnd(); glPopMatrix(); + glPopAttrib(); + glPopName(); } @@ -691,6 +700,11 @@ void Map::renderSector(IGraphicsPtr aContext, int id, tile.track->setMark(); } + // Draw the station, if any + if (tile.station) + highlightTile(aContext, makePoint(x, y), + tile.station->highlightColour()); + // Draw the start location if it's on this tile if (myStartLocation.x == x && myStartLocation.y == y && shouldDrawGridLines) @@ -907,6 +921,81 @@ void Map::lowerArea(const Point& aStartPos, changeAreaHeight(aStartPos, aFinishPos, -0.1f); } +// Either extend an existing station which borders this area +// or build a new station +IStationPtr Map::extendStation(Point aStartPos, Point aFinishPos) +{ + const int xmin = min(aStartPos.x, aFinishPos.x); + const int xmax = max(aStartPos.x, aFinishPos.x); + + const int ymin = min(aStartPos.y, aFinishPos.y); + const int ymax = max(aStartPos.y, aFinishPos.y); + + // Find all the tiles containing track in this region + typedef list > PointList; + PointList trackInArea; + for (int x = xmin; x <= xmax; x++) { + for (int y = ymin; y <= ymax; y++) { + if (tileAt(x, y).track) + trackInArea.push_back(makePoint(x, y)); + } + } + + if (trackInArea.empty()) { + warn() << "Stations must be placed on track"; + return IStationPtr(); + } + + IStationPtr station; + + // See if any of these track segments are adjacent to a station + for (PointList::const_iterator it = trackInArea.begin(); + it != trackInArea.end(); ++it) { + + const Point near[] = { + makePoint(0, 0), + makePoint(1, 0), + makePoint(0, 1), + makePoint(-1, 0), + makePoint(0, -1) + }; + + for (int i = 0; i < 5; i++) { + Point neighbour = *it + near[i]; + if (neighbour.x >= 0 && neighbour.x < myWidth + && neighbour.y >= 0 && neighbour.y < myDepth + && tileAt(neighbour.x, neighbour.y).station) { + + IStationPtr candidate = tileAt(neighbour.x, neighbour.y).station; + + // Maybe extend this station + if (station && station != candidate) { + warn() << "Cannot merge stations"; + return IStationPtr(); + } + else + station = candidate; + } + } + } + + if (station) { + // Found a station to extend + debug() << "Found station to extend"; + } + else { + debug() << "Creating new station"; + + station = makeStation(); + } + + for (PointList::iterator it = trackInArea.begin(); + it != trackInArea.end(); ++it) + tileAt((*it).x, (*it).y).station = station; + + return station; +} + // Write the terrain height map into a binary file // Binary file format is very simple: // Bytes 0-3 Width of map diff --git a/src/SmokeTrail.cpp b/src/SmokeTrail.cpp index 8214a59..bf1d83e 100644 --- a/src/SmokeTrail.cpp +++ b/src/SmokeTrail.cpp @@ -133,19 +133,19 @@ void SmokeTrail::newParticle() using namespace boost; // Random number generator for colour variance - static variate_generator > + static variate_generator > colourRand(mt19937(static_cast(time(NULL))), - normal_distribution<>(0.0f, 0.06f)); + normal_distribution(0.0f, 0.06f)); // Random number generator for position variance - static variate_generator > + static variate_generator > posRand(mt19937(static_cast(time(NULL))), - normal_distribution<>(0.0f, 0.07f)); + normal_distribution(0.0f, 0.07f)); - const float col = 0.7f + static_cast(colourRand()); + const float col = 0.7f + colourRand(); - const float dx = static_cast(posRand()); - const float dz = static_cast(posRand()); + const float dx = posRand(); + const float dz = posRand(); Particle p = { myX + dx, myY, myZ + dz, // Position diff --git a/src/Station.cpp b/src/Station.cpp index d304903..9c28bb3 100644 --- a/src/Station.cpp +++ b/src/Station.cpp @@ -17,19 +17,41 @@ #include "IStation.hpp" +#include + +#include +#include + // Concrete implementation of stations class Station : public IStation { public: Station(); ~Station() {} - -private: + // IStation interface + const string& name() const { return myName; } + void setName(const string& aName) { myName = aName; } + HighlightColour highlightColour() const { return myColour; } +private: + string myName; + HighlightColour myColour; }; Station::Station() { + using namespace boost; + + // Generate a unique station name; + static int nameCounter = 1; + myName = "Station" + lexical_cast(nameCounter++); + // Generate a random colour + static variate_generator > + colourRand(mt19937(static_cast(time(NULL))), + uniform_real(0.2f, 1.0f)); + myColour = make_tuple(colourRand(), + colourRand(), + colourRand()); } IStationPtr makeStation() -- 2.39.2