From 64d86633e8d8d7593ba7cc49f8c8cd5bfc8e6623 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 28 Feb 2010 20:28:29 +0000 Subject: [PATCH] Make SlopeTrack work like a proper track segment --- include/BezierCurve.hpp | 6 --- include/ITrackSegment.hpp | 2 +- src/CrossoverTrack.cpp | 14 ++++- src/CurvedTrack.cpp | 18 ++++++- src/Editor.cpp | 2 +- src/Map.cpp | 25 +++++---- src/Points.cpp | 34 ++++++------ src/SlopeTrack.cpp | 107 ++++++++++++++++++++++++++++++++++---- src/StraightTrack.cpp | 13 ++++- src/TrackCommon.cpp | 28 +++++----- 10 files changed, 186 insertions(+), 63 deletions(-) diff --git a/include/BezierCurve.hpp b/include/BezierCurve.hpp index c35c5ed..004f48f 100644 --- a/include/BezierCurve.hpp +++ b/include/BezierCurve.hpp @@ -50,12 +50,6 @@ struct BezierCurve { } } - BezierCurve() - : length(0) - { - - } - Vector operator()(T t) const { return makeVector diff --git a/include/ITrackSegment.hpp b/include/ITrackSegment.hpp index 8dde980..73a9bb8 100644 --- a/include/ITrackSegment.hpp +++ b/include/ITrackSegment.hpp @@ -87,7 +87,7 @@ struct ITrackSegment : IXMLSerialisable { virtual void render() const = 0; // Set the absolute position of the track in the world - virtual void setOrigin(int x, int y) = 0; + virtual void setOrigin(int x, int y, float height) = 0; // Get the length of this track segment virtual double segmentLength(const track::TravelToken& aToken) const = 0; diff --git a/src/CrossoverTrack.cpp b/src/CrossoverTrack.cpp index 1e2cf9b..cfff014 100644 --- a/src/CrossoverTrack.cpp +++ b/src/CrossoverTrack.cpp @@ -35,10 +35,10 @@ using namespace boost; class CrossoverTrack : public ITrackSegment, public enable_shared_from_this { public: - CrossoverTrack() : myX(0), myY(0) {} + CrossoverTrack() : myX(0), myY(0), height(0.0f) {} ~CrossoverTrack() {} - void setOrigin(int x, int y) { myX = x; myY = y; } + void setOrigin(int x, int y, float h); void render() const; double segmentLength(const track::TravelToken& aToken) const; @@ -61,6 +61,7 @@ private: void transform(const track::TravelToken& aToken, double aDelta) const; int myX, myY; + float height; }; void CrossoverTrack::render() const @@ -68,6 +69,8 @@ void CrossoverTrack::render() const // Render the y-going rails and sleepers glPushMatrix(); + glTranslatef(0.0f, height, 0.0f); + renderStraightRail(); glRotated(90.0, 0.0, 1.0, 0.0); @@ -98,6 +101,13 @@ void CrossoverTrack::render() const glPopMatrix(); } +void CrossoverTrack::setOrigin(int x, int y, float h ) +{ + myX = x; + myY = y; + height = h; +} + double CrossoverTrack::segmentLength(const track::TravelToken& aToken) const { return 1.0; diff --git a/src/CurvedTrack.cpp b/src/CurvedTrack.cpp index 998a3eb..80e4c52 100644 --- a/src/CurvedTrack.cpp +++ b/src/CurvedTrack.cpp @@ -42,7 +42,7 @@ public: void render() const; - void setOrigin(int x, int y) { origin.x = x; origin.y = y; } + void setOrigin(int x, int y, float h); double segmentLength(const track::TravelToken& aToken) const; Connection nextPosition(const track::TravelToken& aToken) const; @@ -70,13 +70,15 @@ private: Point origin; int baseRadius; track::Angle startAngle, finishAngle; + float height; }; CurvedTrack::CurvedTrack(track::Angle aStartAngle, track::Angle aFinishAngle, int aRadius) : origin(makePoint(0, 0)), baseRadius(aRadius), - startAngle(aStartAngle), finishAngle(aFinishAngle) + startAngle(aStartAngle), finishAngle(aFinishAngle), + height(0.0f) { } @@ -86,6 +88,12 @@ CurvedTrack::~CurvedTrack() } +void CurvedTrack::setOrigin(int x, int y, float h) +{ + origin = makePoint(x, y); + height = h; +} + track::TravelToken CurvedTrack::getTravelToken(track::Position aPosition, track::Direction aDirection) const @@ -291,7 +299,13 @@ ITrackSegmentPtr CurvedTrack::mergeExit(Point where, track::Direction dir) void CurvedTrack::render() const { + glPushMatrix(); + + glTranslatef(0.0f, height, 0.0f); + renderCurvedTrack(baseRadius, startAngle, finishAngle); + + glPopMatrix(); } xml::element CurvedTrack::toXml() const diff --git a/src/Editor.cpp b/src/Editor.cpp index 36bb771..f976f21 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -469,7 +469,7 @@ void Editor::drawDraggedTrack() } ITrackSegmentPtr track = makeCurvedTrack(startAngle, endAngle, xlen); - track->setOrigin(where.x, where.y); + track->setOrigin(where.x, where.y, map->heightAt(where.x, where.y)); vector > exits; track->getEndpoints(exits); diff --git a/src/Map.cpp b/src/Map.cpp index 1152c08..5d3873c 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -284,16 +284,23 @@ bool Map::emptyTile(Point point) const return !(tile.track || tile.scenery); } -void Map::setTrackAt(const Point& aPoint, ITrackSegmentPtr aTrack) +void Map::setTrackAt(const Point& where, ITrackSegmentPtr track) { - aTrack->setOrigin(aPoint.x, aPoint.y); + int indexes[4]; + tileVertices(where.x, where.y, indexes); - TrackNodePtr node(new TrackNode(aTrack, aPoint.x, aPoint.y)); + float lowestHeight = 1.0e20f; + for (int i = 0; i < 4; i++) + lowestHeight = min(heightMap[indexes[i]].pos.y, lowestHeight); + + track->setOrigin(where.x, where.y, lowestHeight); + + TrackNodePtr node(new TrackNode(track, where.x, where.y)); // Attach the track node to every tile it covers vector > covers; - aTrack->getEndpoints(covers); - aTrack->getCovers(covers); + track->getEndpoints(covers); + track->getCovers(covers); for (vector >::iterator it = covers.begin(); it != covers.end(); ++it) { @@ -301,13 +308,13 @@ void Map::setTrackAt(const Point& aPoint, ITrackSegmentPtr aTrack) } } -bool Map::isValidTrack(const Point& aPoint) const +bool Map::isValidTrack(const Point& where) const { - if (aPoint.x < 0 || aPoint.y < 0 - || aPoint.x >= myWidth || aPoint.y >= myDepth) + if (where.x < 0 || where.y < 0 + || where.x >= myWidth || where.y >= myDepth) return false; - return tileAt(aPoint.x, aPoint.y).track; + return tileAt(where.x, where.y).track; } // Return a location where the train may start diff --git a/src/Points.cpp b/src/Points.cpp index 39b948e..8ed8a32 100644 --- a/src/Points.cpp +++ b/src/Points.cpp @@ -33,7 +33,7 @@ public: // ITrackSegment interface void render() const; - void setOrigin(int x, int y) { myX = x; myY = y; } + void setOrigin(int x, int y, float h) { myX = x; myY = y; height = h; } double segmentLength(const track::TravelToken& aToken) const; bool isValidDirection(const track::Direction& aDirection) const; track::Connection nextPosition(const track::TravelToken& aToken) const; @@ -63,6 +63,7 @@ private: track::Direction myAxis; bool reflected; State state; + float height; // Draw the arrow over the points if true mutable bool stateRenderHint; @@ -73,19 +74,20 @@ private: const BezierCurve Points::myCurve = makeBezierCurve (makeVector(0.0f, 0.0f, 0.0f), makeVector(1.0f, 0.0f, 0.0f), - makeVector(2.0f, 1.0f, 0.0f), - makeVector(3.0f, 1.0f, 0.0f)); + makeVector(2.0f, 0.0f, 1.0f), + makeVector(3.0f, 0.0f, 1.0f)); const BezierCurve Points::myReflectedCurve = makeBezierCurve (makeVector(0.0f, 0.0f, 0.0f), makeVector(1.0f, 0.0f, 0.0f), - makeVector(2.0f, -1.0f, 0.0f), - makeVector(3.0f, -1.0f, 0.0f)); + makeVector(2.0f, 0.0f, -1.0f), + makeVector(3.0f, 0.0f, -1.0f)); Points::Points(track::Direction aDirection, bool reflect) : myX(0), myY(0), myAxis(aDirection), reflected(reflect), state(NOT_TAKEN), + height(0.0f), stateRenderHint(false) { @@ -127,19 +129,19 @@ void Points::renderArrow() const // Arrow head glBegin(GL_TRIANGLES); { - glVertex3f(v1.x, 0.0f, v1.y - headWidth); - glVertex3f(v2.x, 0.0f, v2.y); - glVertex3f(v1.x, 0.0f, v1.y + headWidth); + glVertex3f(v1.x, 0.0f, v1.z - headWidth); + glVertex3f(v2.x, 0.0f, v2.z); + glVertex3f(v1.x, 0.0f, v1.z + headWidth); } glEnd(); } else { glBegin(GL_QUADS); { - glVertex3f(v1.x, 0.0f, v1.y - 0.1f); - glVertex3f(v1.x, 0.0f, v1.y + 0.1f); - glVertex3f(v2.x, 0.0f, v2.y + 0.1f); - glVertex3f(v2.x, 0.0f, v2.y - 0.1f); + glVertex3f(v1.x, 0.0f, v1.z - 0.1f); + glVertex3f(v1.x, 0.0f, v1.z + 0.1f); + glVertex3f(v2.x, 0.0f, v2.z + 0.1f); + glVertex3f(v2.x, 0.0f, v2.z - 0.1f); } glEnd(); } @@ -178,6 +180,8 @@ void Points::render() const glPushMatrix(); + glTranslatef(0.0f, height, 0.0f); + if (myAxis == -axis::X) glRotatef(180.0f, 0.0f, 1.0f, 0.0f); else if (myAxis == -axis::Y) @@ -198,17 +202,17 @@ void Points::render() const glPopMatrix(); // Draw the curved sleepers - for (float i = 0.2f; i < 1.0f; i += 0.08f) { + for (float i = 0.2f; i < 0.95f; i += 0.08f) { glPushMatrix(); Vector v = (reflected ? myReflectedCurve : myCurve)(i); - glTranslatef(v.x - 0.4f, 0.0f, v.y); + glTranslatef(v.x - 0.4f, 0.0f, v.z); const Vector deriv = (reflected ? myReflectedCurve : myCurve).deriv(i); const float angle = - radToDeg(atanf(deriv.y / deriv.x)); + radToDeg(atanf(deriv.z / deriv.x)); glRotatef(-angle, 0.0f, 1.0f, 0.0f); diff --git a/src/SlopeTrack.cpp b/src/SlopeTrack.cpp index 552be28..6246b7e 100644 --- a/src/SlopeTrack.cpp +++ b/src/SlopeTrack.cpp @@ -19,8 +19,15 @@ #include "IXMLSerialisable.hpp" #include "XMLBuilder.hpp" #include "BezierCurve.hpp" +#include "IMesh.hpp" +#include "TrackCommon.hpp" +#include "OpenGLHelper.hpp" +#include "ILogger.hpp" #include +#include + +#include // Like StraightTrack but with a change of height class SlopeTrack : public ITrackSegment { @@ -30,7 +37,7 @@ public: // ITrackSegment interface void render() const; - void setOrigin(int x, int y) { origin = makePoint(x, y); } + void setOrigin(int x, int y, float h); double segmentLength(const track::TravelToken& token) const; track::TravelToken getTravelToken(track::Position pos, track::Direction dir) const; @@ -49,12 +56,19 @@ public: xml::element toXml() const; private: + void ensureValidDirection(const track::Direction& dir) const; + void transform(const track::TravelToken& token, double delta) const; + Point origin; - BezierCurve curve; + float height; + IMeshPtr railMesh; + track::Direction axis; + float length; }; SlopeTrack::SlopeTrack(track::Direction axis, Vector slope, Vector slopeBefore, Vector slopeAfter) + : height(0.0f), axis(axis) { Vector p1, p2, p3, p4; @@ -70,42 +84,113 @@ SlopeTrack::SlopeTrack(track::Direction axis, Vector slope, p3 = makeVector(0.0f, slope.y, 0.9f); p4 = makeVector(0.0f, slope.y, 1.0f); } + + BezierCurve curve = makeBezierCurve(p1, p2, p3, p4); + length = curve.length; + + // TODO: we should cache these + railMesh = makeBezierRailMesh(curve); } void SlopeTrack::render() const { + glPushMatrix(); + + glTranslatef(0.0f, height, 0.0f); + + renderRailMesh(railMesh); + glPopMatrix(); +} + +void SlopeTrack::setOrigin(int x, int y, float h) +{ + origin = makePoint(x, y); + height = h; } double SlopeTrack::segmentLength(const track::TravelToken& token) const { - assert(false); - return 1.0; // TODO: use Pythagoras + return length; } bool SlopeTrack::isValidDirection(const track::Direction& dir) const { - assert(false); - return false; // TODO + if (axis == axis::X) + return dir == axis::X || -dir == axis::X; + else + return dir == axis::Y || -dir == axis::Y; +} + +void SlopeTrack::ensureValidDirection(const track::Direction& dir) const +{ + if (!isValidDirection(dir)) + throw runtime_error + ("Invalid direction on straight track: " + + boost::lexical_cast(dir) + + " (should be parallel to " + + boost::lexical_cast(axis) + ")"); } track::Connection SlopeTrack::nextPosition( const track::TravelToken& token) const { - // TODO - assert(false); + ensureValidDirection(token.direction); + + if (token.direction == axis::X) + return make_pair(makePoint(origin.x + 1, origin.y), axis::X); + else if (token.direction == -axis::X) + return make_pair(makePoint(origin.x - 1, origin.y), -axis::X); + else if (token.direction == axis::Y) + return make_pair(makePoint(origin.x, origin.y + 1), axis::Y); + else if (token.direction == -axis::Y) + return make_pair(makePoint(origin.x, origin.y - 1), -axis::Y); + else + assert(false); } track::TravelToken SlopeTrack::getTravelToken(track::Position pos, track::Direction dir) const { - // TODO - assert(false); + using namespace placeholders; + + ensureValidDirection(dir); + + track::TravelToken tok = { + dir, + pos, + bind(&SlopeTrack::transform, this, _1, _2), + 1 + }; + return tok; } -void SlopeTrack::getEndpoints(vector >& output) const +void SlopeTrack::transform(const track::TravelToken& token, double delta) const { + assert(delta < 1.0); + + if (token.direction == -axis) + delta = 1.0 - delta; + + const double xTrans = axis == axis::X ? delta : 0; + const double yTrans = axis == axis::Y ? delta : 0; + + glTranslated(static_cast(origin.x) + xTrans, + 0.0, + static_cast(origin.y) + yTrans); + + if (axis == axis::Y) + glRotated(-90.0, 0.0, 1.0, 0.0); + glTranslated(-0.5, 0.0, 0.0); + + if (token.direction == -axis) + glRotated(-180.0, 0.0, 1.0, 0.0); +} + +void SlopeTrack::getEndpoints(vector >& output) const +{ + output.push_back(origin); } ITrackSegmentPtr SlopeTrack::mergeExit(Point where, track::Direction dir) diff --git a/src/StraightTrack.cpp b/src/StraightTrack.cpp index 1afb64a..4081526 100644 --- a/src/StraightTrack.cpp +++ b/src/StraightTrack.cpp @@ -40,7 +40,7 @@ public: void render() const; - void setOrigin(int x, int y) { origin.x = x; origin.y = y; } + void setOrigin(int x, int y, float h); double segmentLength(const track::TravelToken& aToken) const { return 1.0; } Vector offsetForDelta(double aDelta) const; @@ -67,10 +67,11 @@ private: Point origin; // Absolute position Direction direction; + float height; }; StraightTrack::StraightTrack(const Direction& aDirection) - : direction(aDirection) + : direction(aDirection), height(0.0f) { } @@ -80,6 +81,12 @@ StraightTrack::~StraightTrack() } +void StraightTrack::setOrigin(int x, int y, float h) +{ + origin = makePoint(x, y); + height = h; +} + track::TravelToken StraightTrack::getTravelToken(track::Position aPosition, track::Direction aDirection) const @@ -206,6 +213,8 @@ void StraightTrack::render() const { glPushMatrix(); + glTranslatef(0.0f, height, 0.0f); + if (direction == axis::X) glRotated(90.0, 0.0, 1.0, 0.0); diff --git a/src/TrackCommon.cpp b/src/TrackCommon.cpp index ff698e5..0c6b15f 100644 --- a/src/TrackCommon.cpp +++ b/src/TrackCommon.cpp @@ -129,28 +129,28 @@ namespace { Vector v1 = aFunc(t); Vector v2 = aFunc(t + step); - v1.y -= RAIL_WIDTH / 2.0f; - v2.y -= RAIL_WIDTH / 2.0f; + v1.z -= RAIL_WIDTH / 2.0f; + v2.z -= RAIL_WIDTH / 2.0f; // Top of rail - buf->addQuad(makeVector(v1.x, track::RAIL_HEIGHT, v1.y), - makeVector(v1.x, track::RAIL_HEIGHT, v1.y + RAIL_WIDTH), - makeVector(v2.x, track::RAIL_HEIGHT, v2.y + RAIL_WIDTH), - makeVector(v2.x, track::RAIL_HEIGHT, v2.y), + buf->addQuad(makeVector(v1.x, v1.y + track::RAIL_HEIGHT, v1.z), + makeVector(v1.x, v1.y + track::RAIL_HEIGHT, v1.z + RAIL_WIDTH), + makeVector(v2.x, v2.y + track::RAIL_HEIGHT, v2.z + RAIL_WIDTH), + makeVector(v2.x, v2.y + track::RAIL_HEIGHT, v2.z), METAL); // Outer edge - buf->addQuad(makeVector(v2.x, track::RAIL_HEIGHT, v2.y), - makeVector(v2.x , 0.0f, v2.y), - makeVector(v1.x, 0.0f, v1.y), - makeVector(v1.x, track::RAIL_HEIGHT, v1.y), + buf->addQuad(makeVector(v2.x, v2.y + track::RAIL_HEIGHT, v2.z), + makeVector(v2.x , v2.y, v2.z), + makeVector(v1.x, v1.y, v1.z), + makeVector(v1.x, v1.y + track::RAIL_HEIGHT, v1.z), METAL); // Inner edge - buf->addQuad(makeVector(v1.x, track::RAIL_HEIGHT, v1.y + RAIL_WIDTH), - makeVector(v1.x, 0.0f, v1.y + RAIL_WIDTH), - makeVector(v2.x , 0.0f, v2.y + RAIL_WIDTH), - makeVector(v2.x, track::RAIL_HEIGHT, v2.y + RAIL_WIDTH), + buf->addQuad(makeVector(v1.x, v1.y + track::RAIL_HEIGHT, v1.z + RAIL_WIDTH), + makeVector(v1.x, v1.y, v1.z + RAIL_WIDTH), + makeVector(v2.x , v2.y, v2.z + RAIL_WIDTH), + makeVector(v2.x, v2.y + track::RAIL_HEIGHT, v2.z + RAIL_WIDTH), METAL); } -- 2.39.2