Add temperature scales option

Make the PROP tool default to the current temperature scale
Make the PROP tool's temp suffixes work in the console(This is currently blocked by AnyType doing resource management wrong)

Signed-off-by: xphere07 <xphere07@outlook.com>
This commit is contained in:
xphere07 2022-12-27 22:07:52 +09:00
parent 6b133aced6
commit fe67ec8550
No known key found for this signature in database
GPG Key ID: AE1AD11DF516617D
15 changed files with 172 additions and 47 deletions

View File

@ -178,3 +178,57 @@ ByteString format::URLDecode(ByteString source)
} }
return result; return result;
} }
void format::RenderTemperature(StringBuilder &sb, float temp, int scale)
{
switch (scale)
{
case 1:
sb << (temp - 273.15f) << " °C";
break;
case 2:
sb << (temp - 273.15f) * 1.8f + 32.0f << " °F";
break;
default:
sb << temp << " K";
break;
}
}
float format::StringToTemperature(String str, int defaultScale)
{
auto scale = defaultScale;
if (str.size())
{
if (str.EndsWith("K"))
{
scale = 0;
str = str.SubstrFromEnd(1);
}
else if (str.EndsWith("C"))
{
scale = 1;
str = str.SubstrFromEnd(1);
}
else if (str.EndsWith("F"))
{
scale = 2;
str = str.SubstrFromEnd(1);
}
}
if (!str.size())
{
throw std::out_of_range("empty string");
}
auto out = str.ToNumber<float>();
switch (scale)
{
case 1:
out = out + 273.15;
break;
case 2:
out = (out - 32.0f) / 1.8f + 273.15f;
break;
}
return out;
}

View File

@ -14,4 +14,6 @@ namespace format
ByteString UnixtimeToDateMini(time_t unixtime); ByteString UnixtimeToDateMini(time_t unixtime);
String CleanString(String dirtyString, bool ascii, bool color, bool newlines, bool numeric = false); String CleanString(String dirtyString, bool ascii, bool color, bool newlines, bool numeric = false);
std::vector<char> VideoBufferToPPM(const VideoBuffer & vidBuf); std::vector<char> VideoBufferToPPM(const VideoBuffer & vidBuf);
void RenderTemperature(StringBuilder &sb, float temp, int scale);
float StringToTemperature(String str, int defaultScale);
} }

View File

@ -1035,6 +1035,16 @@ bool GameController::GetDebugHUD()
return gameView->GetDebugHUD(); return gameView->GetDebugHUD();
} }
void GameController::SetTemperatureScale(int temperatureScale)
{
gameModel->SetTemperatureScale(temperatureScale);
}
int GameController::GetTemperatureScale()
{
return gameModel->GetTemperatureScale();
}
void GameController::SetActiveColourPreset(int preset) void GameController::SetActiveColourPreset(int preset)
{ {
gameModel->SetActiveColourPreset(preset); gameModel->SetActiveColourPreset(preset);

View File

@ -119,6 +119,8 @@ public:
bool GetBrushEnable(); bool GetBrushEnable();
void SetDebugHUD(bool hudState); void SetDebugHUD(bool hudState);
bool GetDebugHUD(); bool GetDebugHUD();
void SetTemperatureScale(int temperatureScale);
int GetTemperatureScale();
void SetDebugFlags(unsigned int flags) { debugFlags = flags; } void SetDebugFlags(unsigned int flags) { debugFlags = flags; }
void SetActiveMenu(int menuID); void SetActiveMenu(int menuID);
std::vector<Menu*> GetMenuList(); std::vector<Menu*> GetMenuList();

View File

@ -154,6 +154,7 @@ GameModel::GameModel():
mouseClickRequired = Client::Ref().GetPrefBool("MouseClickRequired", false); mouseClickRequired = Client::Ref().GetPrefBool("MouseClickRequired", false);
includePressure = Client::Ref().GetPrefBool("Simulation.IncludePressure", true); includePressure = Client::Ref().GetPrefBool("Simulation.IncludePressure", true);
temperatureScale = Client::Ref().GetPrefInteger("Renderer.TemperatureScale", 1);
ClearSimulation(); ClearSimulation();
} }
@ -534,6 +535,11 @@ int GameModel::GetEdgeMode()
return this->edgeMode; return this->edgeMode;
} }
void GameModel::SetTemperatureScale(int temperatureScale)
{
this->temperatureScale = temperatureScale;
}
void GameModel::SetAmbientAirTemperature(float ambientAirTemp) void GameModel::SetAmbientAirTemperature(float ambientAirTemp)
{ {
this->ambientAirTemp = ambientAirTemp; this->ambientAirTemp = ambientAirTemp;

View File

@ -81,6 +81,7 @@ private:
bool mouseClickRequired; bool mouseClickRequired;
bool includePressure; bool includePressure;
bool perfectCircle = true; bool perfectCircle = true;
int temperatureScale;
size_t activeColourPreset; size_t activeColourPreset;
std::vector<ui::Colour> colourPresets; std::vector<ui::Colour> colourPresets;
@ -123,6 +124,11 @@ public:
void SetEdgeMode(int edgeMode); void SetEdgeMode(int edgeMode);
int GetEdgeMode(); int GetEdgeMode();
void SetTemperatureScale(int temperatureScale);
inline int GetTemperatureScale() const
{
return temperatureScale;
}
void SetAmbientAirTemperature(float ambientAirTemp); void SetAmbientAirTemperature(float ambientAirTemp);
float GetAmbientAirTemperature(); float GetAmbientAirTemperature();
void SetDecoSpace(int decoSpace); void SetDecoSpace(int decoSpace);

View File

@ -2285,7 +2285,8 @@ void GameView::OnDraw()
else if (ctype) else if (ctype)
sampleInfo << " (" << ctype << ")"; sampleInfo << " (" << ctype << ")";
} }
sampleInfo << ", Temp: " << (sample.particle.temp - 273.15f) << " C"; sampleInfo << ", Temp: ";
format::RenderTemperature(sampleInfo, sample.particle.temp, c->GetTemperatureScale());
sampleInfo << ", Life: " << sample.particle.life; sampleInfo << ", Life: " << sample.particle.life;
if (sample.particle.type != PT_RFRG && sample.particle.type != PT_RFGL && sample.particle.type != PT_LIFE) if (sample.particle.type != PT_RFRG && sample.particle.type != PT_RFGL && sample.particle.type != PT_LIFE)
{ {
@ -2315,7 +2316,8 @@ void GameView::OnDraw()
else else
{ {
sampleInfo << c->BasicParticleInfo(sample.particle); sampleInfo << c->BasicParticleInfo(sample.particle);
sampleInfo << ", Temp: " << sample.particle.temp - 273.15f << " C"; sampleInfo << ", Temp: ";
format::RenderTemperature(sampleInfo, sample.particle.temp, c->GetTemperatureScale());
sampleInfo << ", Pressure: " << sample.AirPressure; sampleInfo << ", Pressure: " << sample.AirPressure;
} }
} }
@ -2386,7 +2388,10 @@ void GameView::OnDraw()
sampleInfo << ", GX: " << sample.GravityVelocityX << " GY: " << sample.GravityVelocityY; sampleInfo << ", GX: " << sample.GravityVelocityX << " GY: " << sample.GravityVelocityY;
if (c->GetAHeatEnable()) if (c->GetAHeatEnable())
sampleInfo << ", AHeat: " << sample.AirTemperature - 273.15f << " C"; {
sampleInfo << ", AHeat: ";
format::RenderTemperature(sampleInfo, sample.AirTemperature, c->GetTemperatureScale());
}
textWidth = Graphics::textwidth(sampleInfo.Build()); textWidth = Graphics::textwidth(sampleInfo.Build());
g->fillrect(XRES-20-textWidth, 27, textWidth+8, 14, 0, 0, 0, int(alpha*0.5f)); g->fillrect(XRES-20-textWidth, 27, textWidth+8, 14, 0, 0, 0, int(alpha*0.5f));

View File

@ -2,6 +2,7 @@
#include "client/Client.h" #include "client/Client.h"
#include "Menu.h" #include "Menu.h"
#include "Format.h"
#include "gui/game/GameModel.h" #include "gui/game/GameModel.h"
#include "gui/Style.h" #include "gui/Style.h"
@ -23,31 +24,6 @@
#include <iostream> #include <iostream>
void ParseFloatProperty(String value, float &out)
{
if (!value.size())
{
throw std::out_of_range("empty string");
}
if (value.EndsWith("C"))
{
float v = value.SubstrFromEnd(1).ToNumber<float>();
out = v + 273.15;
}
else if(value.EndsWith("F"))
{
float v = value.SubstrFromEnd(1).ToNumber<float>();
out = (v-32.0f)*5/9+273.15f;
}
else
{
out = value.ToNumber<float>();
}
#ifdef DEBUG
std::cout << "Got float value " << out << std::endl;
#endif
}
class PropertyWindow: public ui::Window class PropertyWindow: public ui::Window
{ {
public: public:
@ -219,7 +195,7 @@ void PropertyWindow::SetProperty(bool warn)
} }
case StructProperty::Float: case StructProperty::Float:
{ {
ParseFloatProperty(value, tool->propValue.Float); tool->propValue.Float = format::StringToTemperature(value, tool->gameModel->GetTemperatureScale());
} }
break; break;
default: default:

View File

@ -67,6 +67,11 @@ void OptionsController::SetEdgeMode(int edgeMode)
model->SetEdgeMode(edgeMode); model->SetEdgeMode(edgeMode);
} }
void OptionsController::SetTemperatureScale(int temperatureScale)
{
model->SetTemperatureScale(temperatureScale);
}
void OptionsController::SetFullscreen(bool fullscreen) void OptionsController::SetFullscreen(bool fullscreen)
{ {
model->SetFullscreen(fullscreen); model->SetFullscreen(fullscreen);

View File

@ -26,6 +26,7 @@ public:
void SetAirMode(int airMode); void SetAirMode(int airMode);
void SetAmbientAirTemperature(float ambientAirTemp); void SetAmbientAirTemperature(float ambientAirTemp);
void SetEdgeMode(int edgeMode); void SetEdgeMode(int edgeMode);
void SetTemperatureScale(int temperatureScale);
void SetFullscreen(bool fullscreen); void SetFullscreen(bool fullscreen);
void SetAltFullscreen(bool altFullscreen); void SetAltFullscreen(bool altFullscreen);
void SetForceIntegerScaling(bool forceIntegerScaling); void SetForceIntegerScaling(bool forceIntegerScaling);

View File

@ -90,6 +90,17 @@ void OptionsModel::SetEdgeMode(int edgeMode)
notifySettingsChanged(); notifySettingsChanged();
} }
int OptionsModel::GetTemperatureScale()
{
return gModel->GetTemperatureScale();
}
void OptionsModel::SetTemperatureScale(int temperatureScale)
{
Client::Ref().SetPref("Renderer.TemperatureScale", temperatureScale);
gModel->SetTemperatureScale(temperatureScale);
notifySettingsChanged();
}
float OptionsModel::GetAmbientAirTemperature() float OptionsModel::GetAmbientAirTemperature()
{ {
return gModel->GetSimulation()->air->ambientAirTemp; return gModel->GetSimulation()->air->ambientAirTemp;

View File

@ -32,6 +32,8 @@ public:
void SetAmbientAirTemperature(float ambientAirTemp); void SetAmbientAirTemperature(float ambientAirTemp);
int GetEdgeMode(); int GetEdgeMode();
void SetEdgeMode(int edgeMode); void SetEdgeMode(int edgeMode);
int GetTemperatureScale();
void SetTemperatureScale(int temperatureScale);
int GetGravityMode(); int GetGravityMode();
void SetGravityMode(int gravityMode); void SetGravityMode(int gravityMode);
float GetCustomGravityX(); float GetCustomGravityX();

View File

@ -4,6 +4,7 @@
#include <cstring> #include <cstring>
#include <cmath> #include <cmath>
#include "SDLCompat.h" #include "SDLCompat.h"
#include "Format.h"
#include "OptionsController.h" #include "OptionsController.h"
#include "OptionsModel.h" #include "OptionsModel.h"
@ -235,6 +236,19 @@ OptionsView::OptionsView():
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel); scrollPanel->AddChild(tempLabel);
currentY+=20;
temperatureScale = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
scrollPanel->AddChild(temperatureScale);
temperatureScale->AddOption(std::pair<String, int>("Kelvin", 0));
temperatureScale->AddOption(std::pair<String, int>("Celsius", 1));
temperatureScale->AddOption(std::pair<String, int>("Fahrenheit", 2));
temperatureScale->SetActionCallback({ [this] { c->SetTemperatureScale(temperatureScale->GetOption().second); } });
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Temperature Scale");
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=20; currentY+=20;
tmpSeparator = new Separator(ui::Point(0, currentY), ui::Point(Size.X, 1)); tmpSeparator = new Separator(ui::Point(0, currentY), ui::Point(Size.X, 1));
scrollPanel->AddChild(tmpSeparator); scrollPanel->AddChild(tmpSeparator);
@ -437,6 +451,25 @@ void OptionsView::UpdateAmbientAirTempPreview(float airTemp, bool isValid)
ambientAirTempPreview->Appearance.BackgroundHover = ambientAirTempPreview->Appearance.BackgroundInactive; ambientAirTempPreview->Appearance.BackgroundHover = ambientAirTempPreview->Appearance.BackgroundInactive;
} }
void OptionsView::AmbientAirTempToTextBox(float airTemp)
{
StringBuilder sb;
sb << Format::Precision(2);
switch (temperatureScale->GetOption().second)
{
case 1:
sb << (airTemp - 273.15f) << "C";
break;
case 2:
sb << (airTemp - 273.15f) * 1.8f + 32.0f << "F";
break;
default:
sb << airTemp;
break;
}
ambientAirTemp->SetText(sb.Build());
}
void OptionsView::UpdateAirTemp(String temp, bool isDefocus) void OptionsView::UpdateAirTemp(String temp, bool isDefocus)
{ {
// Parse air temp and determine validity // Parse air temp and determine validity
@ -444,8 +477,7 @@ void OptionsView::UpdateAirTemp(String temp, bool isDefocus)
bool isValid; bool isValid;
try try
{ {
void ParseFloatProperty(String value, float &out); airTemp = format::StringToTemperature(temp, temperatureScale->GetOption().second);
ParseFloatProperty(temp, airTemp);
isValid = true; isValid = true;
} }
catch (const std::exception &ex) catch (const std::exception &ex)
@ -470,10 +502,7 @@ void OptionsView::UpdateAirTemp(String temp, bool isDefocus)
else else
return; return;
// Update textbox with the new value AmbientAirTempToTextBox(airTemp);
StringBuilder sb;
sb << Format::Precision(2) << airTemp;
ambientAirTemp->SetText(sb.Build());
} }
// Out of range temperatures are invalid, preview should go away // Out of range temperatures are invalid, preview should go away
else if (isValid && (airTemp < MIN_TEMP || airTemp > MAX_TEMP)) else if (isValid && (airTemp < MIN_TEMP || airTemp > MAX_TEMP))
@ -488,20 +517,18 @@ void OptionsView::UpdateAirTemp(String temp, bool isDefocus)
void OptionsView::NotifySettingsChanged(OptionsModel * sender) void OptionsView::NotifySettingsChanged(OptionsModel * sender)
{ {
temperatureScale->SetOption(sender->GetTemperatureScale()); // has to happen before AmbientAirTempToTextBox is called
heatSimulation->SetChecked(sender->GetHeatSimulation()); heatSimulation->SetChecked(sender->GetHeatSimulation());
ambientHeatSimulation->SetChecked(sender->GetAmbientHeatSimulation()); ambientHeatSimulation->SetChecked(sender->GetAmbientHeatSimulation());
newtonianGravity->SetChecked(sender->GetNewtonianGravity()); newtonianGravity->SetChecked(sender->GetNewtonianGravity());
waterEqualisation->SetChecked(sender->GetWaterEqualisation()); waterEqualisation->SetChecked(sender->GetWaterEqualisation());
airMode->SetOption(sender->GetAirMode()); airMode->SetOption(sender->GetAirMode());
// Initialize air temp and preview only when the options menu is opened, and not when user is actively editing the textbox // Initialize air temp and preview only when the options menu is opened, and not when user is actively editing the textbox
if (!initializedAirTempPreview) if (!ambientAirTemp->IsFocused())
{ {
initializedAirTempPreview = true;
float airTemp = sender->GetAmbientAirTemperature(); float airTemp = sender->GetAmbientAirTemperature();
UpdateAmbientAirTempPreview(airTemp, true); UpdateAmbientAirTempPreview(airTemp, true);
StringBuilder sb; AmbientAirTempToTextBox(airTemp);
sb << Format::Precision(2) << airTemp;
ambientAirTemp->SetText(sb.Build());
} }
gravityMode->SetOption(sender->GetGravityMode()); gravityMode->SetOption(sender->GetGravityMode());
customGravityX = sender->GetCustomGravityX(); customGravityX = sender->GetCustomGravityX();

View File

@ -27,6 +27,7 @@ class OptionsView: public ui::Window
ui::Button * ambientAirTempPreview; ui::Button * ambientAirTempPreview;
ui::DropDown * gravityMode; ui::DropDown * gravityMode;
ui::DropDown * edgeMode; ui::DropDown * edgeMode;
ui::DropDown * temperatureScale;
ui::DropDown * scale; ui::DropDown * scale;
ui::Checkbox * resizable; ui::Checkbox * resizable;
ui::Checkbox * fullscreen; ui::Checkbox * fullscreen;
@ -41,8 +42,8 @@ class OptionsView: public ui::Window
ui::Checkbox * perfectCirclePressure; ui::Checkbox * perfectCirclePressure;
ui::ScrollPanel * scrollPanel; ui::ScrollPanel * scrollPanel;
float customGravityX, customGravityY; float customGravityX, customGravityY;
bool initializedAirTempPreview = false;
void UpdateAmbientAirTempPreview(float airTemp, bool isValid); void UpdateAmbientAirTempPreview(float airTemp, bool isValid);
void AmbientAirTempToTextBox(float airTemp);
void UpdateAirTemp(String temp, bool isDefocus); void UpdateAirTemp(String temp, bool isDefocus);
public: public:
OptionsView(); OptionsView();

View File

@ -8,6 +8,7 @@
#include <cmath> #include <cmath>
#include "Config.h" #include "Config.h"
#include "Format.h"
#include "simulation/Simulation.h" #include "simulation/Simulation.h"
#include "simulation/Air.h" #include "simulation/Air.h"
@ -271,6 +272,21 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
//Selector //Selector
int newValue = 0; int newValue = 0;
float newValuef = 0.0f; float newValuef = 0.0f;
if (property.Value() == "temp")
{
// convert non-string temperature values to strings to format::StringToTemperature can take care of them
switch (value.GetType())
{
case TypeNumber:
value = StringType(String::Build(((NumberType)value).Value()));
break;
case TypeFloat:
value = StringType(String::Build(((FloatType)value).Value()));
break;
default:
break;
}
}
if (value.GetType() == TypeNumber) if (value.GetType() == TypeNumber)
{ {
newValuef = float(newValue = ((NumberType)value).Value()); newValuef = float(newValue = ((NumberType)value).Value());
@ -283,13 +299,14 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
{ {
if (property.Value() == "temp") if (property.Value() == "temp")
{ {
String newString = ((StringType)value).Value(); try
if (newString.at(newString.length()-1) == 'C') {
newValuef = atof(newString.SubstrFromEnd(1).ToUtf8().c_str())+273.15; newValuef = format::StringToTemperature(((StringType)value).Value(), c->GetTemperatureScale());
else if (newString.at(newString.length()-1) == 'F') }
newValuef = (atof(newString.SubstrFromEnd(1).ToUtf8().c_str())-32.0f)*5/9+273.15f; catch (const std::exception &ex)
else {
throw GeneralException("Invalid value for assignment"); throw GeneralException("Invalid value for assignment");
}
} }
else else
{ {