From b71280a62add7b719fd4817154a4e7263fb720bc Mon Sep 17 00:00:00 2001 From: Nick Gasson <nick@nickg.me.uk> Date: Sun, 17 May 2009 13:55:20 +0100 Subject: [PATCH] Add a few more stats meters --- include/IController.hpp | 1 + include/gui/IControl.hpp | 6 ++ src/Engine.cpp | 13 +++- src/Game.cpp | 25 ++++++++ src/gui/FuelMeter.cpp | 129 ++++++++++++++++++++++++++++++++++++++ src/gui/ThrottleMeter.cpp | 19 ++++-- 6 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 src/gui/FuelMeter.cpp diff --git a/include/IController.hpp b/include/IController.hpp index 9bb0a57..d275cf0 100644 --- a/include/IController.hpp +++ b/include/IController.hpp @@ -37,6 +37,7 @@ struct IController { // Get current values for the display virtual int throttle() const = 0; virtual bool brakeOn() const = 0; + virtual double pressure() const = 0; }; typedef std::tr1::shared_ptr<IController> IControllerPtr; diff --git a/include/gui/IControl.hpp b/include/gui/IControl.hpp index 890acbc..dc0501d 100644 --- a/include/gui/IControl.hpp +++ b/include/gui/IControl.hpp @@ -21,12 +21,15 @@ #include "IFont.hpp" #include <tr1/memory> +#include <tr1/tuple> #include <string> #include <boost/cast.hpp> namespace gui { + typedef std::tr1::tuple<float, float, float> Colour; + // Interface to any UI control struct IControl { virtual ~IControl() {} @@ -61,6 +64,7 @@ namespace gui { virtual ~IMeterControl() {} virtual void setValue(int aValue) = 0; + virtual void setRange(int aLowValue, int aHighValue) = 0; }; typedef std::tr1::shared_ptr<IMeterControl> IMeterControlPtr; @@ -69,6 +73,8 @@ namespace gui { IControlPtr makeButton(const std::string& aGlyphFile); ITextControlPtr makeLabel(IFontPtr aFont, const std::string& aString=""); IMeterControlPtr makeThrottleMeter(IFontPtr aFont); + IMeterControlPtr makeFuelMeter(IFontPtr aFont, const std::string& aCaption, + const Colour& aColour); } #endif diff --git a/src/Engine.cpp b/src/Engine.cpp index 767e74f..8293003 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -48,6 +48,9 @@ using namespace std::tr1; // Run models.gnuplot to see an example of these curves. The functions // in that file should match the code here!! // +// Currently pressure varies between 0 and 1. <0.1 and >1.0 are bad, but +// currently don't correspond to real values +// // Concrete implementation of a steam engine class Engine : public IRollingStock, @@ -68,6 +71,7 @@ public: void actOn(Action anAction); int throttle() const { return myThrottle; } bool brakeOn() const { return isBrakeOn; } + double pressure() const { return myPressure; } private: double tractiveEffort() const; double resistance() const; @@ -79,20 +83,25 @@ private: double myFuelOnFire; double myStatTractiveEffort; bool isBrakeOn; - int myThrottle; // Ratio measured in tenths + int myThrottle; // Ratio measured in tenths + double myPressure; // Boiler pressure static const double MODEL_SCALE; static const double TRACTIVE_EFFORT_KNEE; + + static const double INIT_PRESSURE; }; const double Engine::MODEL_SCALE(0.4); const double Engine::TRACTIVE_EFFORT_KNEE(10.0); +const double Engine::INIT_PRESSURE(0.2); Engine::Engine() : mySpeed(0.0), myMass(29.0), myBoilerPressure(1.0), myFireTemp(0.0), myFuelOnFire(0.0), myStatTractiveEffort(34.7), - isBrakeOn(true), myThrottle(0) + isBrakeOn(true), myThrottle(0), + myPressure(INIT_PRESSURE) { myModel = loadModel("pclass.obj", MODEL_SCALE); } diff --git a/src/Game.cpp b/src/Game.cpp index afd4da9..8d21ab4 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -27,6 +27,7 @@ #include <GL/gl.h> using namespace std; +using namespace std::tr1; using namespace gui; // Implementation of the main play screen @@ -57,6 +58,8 @@ private: IContainerPtr myStatsPanel; ITextControlPtr mySpeedLabel, myBrakeLabel; IMeterControlPtr myThrottleMeter; + IMeterControlPtr myCoalMeter, myWaterMeter; + IMeterControlPtr myTempMeter, myPressureMeter; }; Game::Game(IMapPtr aMap) @@ -77,6 +80,23 @@ Game::Game(IMapPtr aMap) myThrottleMeter = makeThrottleMeter(stdFont); myStatsPanel->addChild(myThrottleMeter); + myCoalMeter = makeFuelMeter(stdFont, "Coal", + make_tuple(0.1f, 0.1f, 0.1f)); + myStatsPanel->addChild(myCoalMeter); + + myWaterMeter = makeFuelMeter(stdFont, "Water", + make_tuple(0.1f, 0.1f, 0.8f)); + myStatsPanel->addChild(myWaterMeter); + + myTempMeter = makeFuelMeter(stdFont, "Temp", + make_tuple(0.8f, 0.1f, 0.1f)); + myStatsPanel->addChild(myTempMeter); + + myPressureMeter = makeFuelMeter(stdFont, "Pressure", + make_tuple(0.1f, 0.3f, 0.5f)); + myPressureMeter->setRange(0, 60); + myStatsPanel->addChild(myPressureMeter); + myBrakeLabel = makeLabel(stdFont, "Brake on"); myBrakeLabel->setColour(1.0f, 0.0f, 0.0f); myStatsPanel->addChild(myBrakeLabel); @@ -121,6 +141,11 @@ void Game::update(IPickBufferPtr aPickBuffer, int aDelta) mySpeedLabel->setText("Speed: %.1lfmph\n", myTrain->speed() * msToMPH); myThrottleMeter->setValue(myTrain->controller()->throttle()); myBrakeLabel->setVisible(myTrain->controller()->brakeOn()); + + const double pressure = myTrain->controller()->pressure(); + myPressureMeter->setValue(static_cast<int>(pressure * 100.0)); + + myWaterMeter->setValue(8); } void Game::onKeyDown(SDLKey aKey) diff --git a/src/gui/FuelMeter.cpp b/src/gui/FuelMeter.cpp new file mode 100644 index 0000000..d2badab --- /dev/null +++ b/src/gui/FuelMeter.cpp @@ -0,0 +1,129 @@ +// +// Copyright (C) 2009 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "gui/IControl.hpp" + +#include <stdexcept> + +#include <GL/gl.h> +#include <boost/lexical_cast.hpp> + +using namespace gui; +using namespace std; +using namespace std::tr1; +using namespace boost; + +class FuelMeter : public IMeterControl { +public: + FuelMeter(IFontPtr aFont, const string& aCaption, + const Colour& aColour); + ~FuelMeter() {} + + // IControl interface + void render(int x, int y) const; + int width() const; + int height() const; + void setVisible(bool visible) { amVisible = visible; } + + // IMeterControl interface + void setValue(int aValue); + void setRange(int aLowValue, int aHighValue); +private: + int myValue; + IFontPtr myFont; + const string myCaption; + const Colour myColour; + const int myTextWidth; + bool amVisible; + int myMin, myMax; + + static const int METER_HEIGHT, METER_WIDTH; +}; + +const int FuelMeter::METER_HEIGHT(16); +const int FuelMeter::METER_WIDTH(100); + +FuelMeter::FuelMeter(IFontPtr aFont, const string& aCaption, + const Colour& aColour) + : myValue(0), myFont(aFont), myCaption(aCaption + ": "), + myColour(aColour), + myTextWidth(myFont->stringWidth(myCaption.c_str())), + amVisible(true), myMin(0), myMax(10) +{ + +} + +int FuelMeter::height() const +{ + return max(myFont->maxHeight(), METER_HEIGHT); +} + +int FuelMeter::width() const +{ + return myTextWidth + METER_WIDTH; +} + +void FuelMeter::setValue(int aValue) +{ + if (aValue < myMin) + throw runtime_error("Fuel meter underflow: " + + lexical_cast<string>(aValue)); + else if (aValue > myMax) + throw runtime_error("Fuel meter overflow: " + + lexical_cast<string>(aValue)); + + myValue = aValue; +} + +void FuelMeter::setRange(int aLowValue, int aHighValue) +{ + myMin = aLowValue; + myMax = aHighValue; +} + +void FuelMeter::render(int x, int y) const +{ + if (!amVisible) + return; + + myFont->print(x, y, myCaption.c_str()); + + glPushMatrix(); + + const int off = height() - METER_HEIGHT + 1; + + glTranslatef(static_cast<float>(myTextWidth), + static_cast<float>(y + off), 0.0f); + + const int unit = METER_WIDTH / (myMax + 1); + + glColor3f(get<0>(myColour), get<1>(myColour), get<2>(myColour)); + glBegin(GL_QUADS); + glVertex2i(0, 0); + glVertex2i(0, METER_HEIGHT); + glVertex2i(unit * myValue, METER_HEIGHT); + glVertex2i(unit * myValue, 0); + glEnd(); + + glPopMatrix(); +} + +IMeterControlPtr gui::makeFuelMeter(IFontPtr aFont, const string& aCaption, + const Colour& aColour) +{ + return IMeterControlPtr(new FuelMeter(aFont, aCaption, aColour)); +} diff --git a/src/gui/ThrottleMeter.cpp b/src/gui/ThrottleMeter.cpp index 09d0a56..e7a8511 100644 --- a/src/gui/ThrottleMeter.cpp +++ b/src/gui/ThrottleMeter.cpp @@ -37,11 +37,13 @@ public: // IMeterControl interface void setValue(int aValue); + void setRange(int aLowValue, int aHighValue); private: int myValue; IFontPtr myFont; const int myTextWidth; bool amVisible; + int myMin, myMax; static const int THROTTLE_MAX = 10; static const int THROTTLE_MIN = 0; @@ -55,7 +57,8 @@ const int ThrottleMeter::METER_WIDTH(100); ThrottleMeter::ThrottleMeter(IFontPtr aFont) : myValue(0), myFont(aFont), myTextWidth(myFont->stringWidth("Throttle: ")), - amVisible(true) + amVisible(true), + myMin(THROTTLE_MIN), myMax(THROTTLE_MAX) { } @@ -75,6 +78,12 @@ void ThrottleMeter::setValue(int aValue) myValue = aValue; } +void ThrottleMeter::setRange(int aLowValue, int aHighValue) +{ + myMin = aLowValue; + myMax = aHighValue; +} + void ThrottleMeter::render(int x, int y) const { if (!amVisible) @@ -89,7 +98,7 @@ void ThrottleMeter::render(int x, int y) const glTranslatef(static_cast<float>(myTextWidth), static_cast<float>(y + off), 0.0f); - const int unit = METER_WIDTH / (THROTTLE_MAX + 1); + const int unit = METER_WIDTH / (myMax + 1); // Neutral bit glColor3f(1.0f, 1.0f, 0.0f); @@ -100,8 +109,8 @@ void ThrottleMeter::render(int x, int y) const glVertex2i(unit, 0); glEnd(); - int squareLen = myValue >= THROTTLE_MAX - ? (THROTTLE_MAX - 1) * unit + int squareLen = myValue >= myMax + ? (myMax - 1) * unit : (myValue > 0 ? unit * (myValue - 1) : 0); glTranslatef(static_cast<float>(unit), 0.0f, 0.0f); @@ -117,7 +126,7 @@ void ThrottleMeter::render(int x, int y) const glEnd(); } - const bool wantTriangle = myValue < THROTTLE_MAX && myValue > 0; + const bool wantTriangle = myValue < myMax && myValue > 0; if (wantTriangle) { // Triangle bit glBegin(GL_TRIANGLES); -- 2.39.5