Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
Wavefield.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2025 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Wavefield.h"
23
24#include "Actor.h"
25#include "AppContext.h"
26#include "CameraManager.h"
27#include "GfxScene.h"
28#include "PlatformUtils.h" // PathCombine
29#include "Terrain.h"
30
31#include <Ogre.h>
32
33using namespace RoR;
34
36 m_map_size(terrn_size)
37{
38 if (m_map_size.x < 1500 && m_map_size.z < 1500)
40
41 char line[1024] = {};
42 std::string filepath = PathCombine(RoR::App::sys_config_dir->getStr(), "wavefield.cfg");
43 FILE* fd = fopen(filepath.c_str(), "r");
44 if (fd)
45 {
46 while (!feof(fd))
47 {
48 int res = fscanf(fd, " %[^\n\r]", line);
49 if (line[0] == ';')
50 continue;
51 float wl, amp, mx, dir;
52 res = sscanf(line, "%f, %f, %f, %f", &wl, &amp, &mx, &dir);
53 if (res < 4)
54 continue;
55
56 WaveTrain wavetrain;
57 wavetrain.wavelength = wl;
58 wavetrain.amplitude = amp;
59 wavetrain.maxheight = mx;
60 wavetrain.direction = dir / 57.0;
61 wavetrain.dir_sin = sin(wavetrain.direction);
62 wavetrain.dir_cos = cos(wavetrain.direction);
63
64 m_wavetrain_defs.push_back(wavetrain);
65 }
66 fclose(fd);
67 }
68 for (size_t i = 0; i < m_wavetrain_defs.size(); i++)
69 {
70 m_wavetrain_defs[i].wavespeed = 1.25 * sqrt(m_wavetrain_defs[i].wavelength);
71 m_max_ampl += m_wavetrain_defs[i].maxheight;
72 }
73}
74
79
81{
82 m_water_height = value;
83}
84
86{
87 m_waves_height = value;
88}
89
90float Wavefield::CalcWavesHeight(Vec3 pos, float timeshift_sec)
91{
92 // no waves?
93 if (!RoR::App::gfx_water_waves->getBool() || RoR::App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
94 {
95 // constant height, sea is flat as pancake
96 return m_water_height;
97 }
98
99 // uh, some upper limit?!
100 if (pos.y > m_water_height + m_max_ampl)
101 return m_water_height;
102
103 const float time_sec = m_sim_time_counter + timeshift_sec;
104
105 float waveheight = GetWaveHeight(pos);
106 // we will store the result in this variable, init it with the default height
107 float result = m_water_height;
108 // now walk through all the wave trains. One 'train' is one sin/cos set that will generate once wave. All the trains together will sum up, so that they generate a 'rough' sea
109 for (size_t i = 0; i < m_wavetrain_defs.size(); i++)
110 {
111 // calculate the amplitude that this wave will have. wavetrains[i].amplitude is read from the config
112 // upper limit: prevent too big waves by setting an upper limit
113 float amp = std::min(m_wavetrain_defs[i].amplitude * waveheight, m_wavetrain_defs[i].maxheight);
114 // now the main thing:
115 // calculate the sinus with the values of the config file and add it to the result
116 result += amp * sin(Ogre::Math::TWO_PI * ((time_sec * m_wavetrain_defs[i].wavespeed + m_wavetrain_defs[i].dir_sin * pos.x + m_wavetrain_defs[i].dir_cos * pos.z) / m_wavetrain_defs[i].wavelength));
117 }
118 // return the summed up waves
119 return result;
120}
121
123{
124 float waterheight = m_water_height;
125
126 if (RoR::App::gfx_water_waves->getBool() && RoR::App::mp_state->getEnum<MpState>() == RoR::MpState::DISABLED)
127 {
128 float waveheight = GetWaveHeight(pos);
129
130 if (pos.y > m_water_height + m_max_ampl * waveheight || pos.y > m_water_height + m_max_ampl)
131 return false;
132
133 waterheight = CalcWavesHeight(pos);
134 }
135
136 return pos.y < waterheight;
137}
138
139Vec3 Wavefield::CalcWavesVelocity(Vec3 pos, float timeshift_sec)
140{
141 if (!RoR::App::gfx_water_waves->getBool() || RoR::App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
142 return Vec3();
143
144 float waveheight = GetWaveHeight(pos);
145
146 if (pos.y > m_water_height + m_max_ampl)
147 return Vec3();
148
149 Vec3 result;
150
151 const float time_sec = m_sim_time_counter + timeshift_sec;
152
153 for (size_t i = 0; i < m_wavetrain_defs.size(); i++)
154 {
155 float amp = std::min(m_wavetrain_defs[i].amplitude * waveheight, m_wavetrain_defs[i].maxheight);
156 float speed = Ogre::Math::TWO_PI * amp / (m_wavetrain_defs[i].wavelength / m_wavetrain_defs[i].wavespeed);
157 float coeff = Ogre::Math::TWO_PI * (time_sec * m_wavetrain_defs[i].wavespeed + m_wavetrain_defs[i].dir_sin * pos.x + m_wavetrain_defs[i].dir_cos * pos.z) / m_wavetrain_defs[i].wavelength;
158 result.y += speed * cos(coeff);
159 result += Vec3(m_wavetrain_defs[i].dir_sin, 0, m_wavetrain_defs[i].dir_cos) * speed * sin(coeff);
160 }
161
162 return result;
163}
164
166{
167 m_sim_time_counter += dt;
168}
169
171{
172 // calculate how high the waves should be at this point
173 // (mapsize.x * m_waterplane_mesh_scale) / 2 = terrain width / 2
174 // (mapsize.z * m_waterplane_mesh_scale) / 2 = terrain height / 2
175 // calculate distance to the center of the terrain and divide by 3.000.000
176 float waveheight = (pos - Vec3((m_map_size.x * m_waterplane_mesh_scale) * 0.5, m_water_height, (m_map_size.z * m_waterplane_mesh_scale) * 0.5)).squaredLength() / 3000000.0;
177 waveheight += m_waves_height;
178
179 return waveheight;
180}
181
182
System integration layer; inspired by OgreBites::ApplicationContext.
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
Vec3 CalcWavesVelocity(Vec3 pos, float timeshift_sec=0.f)
bool IsUnderWater(Vec3 pos)
float CalcWavesHeight(Vec3 pos, float timeshift_sec=0.f)
Definition Wavefield.cpp:90
void SetStaticWaterHeight(float value)
Definition Wavefield.cpp:80
void SetWavesHeight(float)
Definition Wavefield.cpp:85
float m_waves_height
Definition Wavefield.h:62
float m_water_height
Definition Wavefield.h:61
void FrameStepWaveField(float dt)
float m_waterplane_mesh_scale
Definition Wavefield.h:60
Wavefield(Vec3 terrn_size)
Definition Wavefield.cpp:35
std::vector< WaveTrain > m_wavetrain_defs
Definition Wavefield.h:58
float m_max_ampl
Definition Wavefield.h:64
float m_sim_time_counter
Elapsed simulation time in seconds.
Definition Wavefield.h:65
float GetStaticWaterHeight()
Returns static water level configured in 'terrn2'.
Definition Wavefield.cpp:75
float GetWaveHeight(Vec3 pos)
std::string PathCombine(std::string a, std::string b)
@ DISABLED
Not connected for whatever reason.
CVar * sys_config_dir
CVar * gfx_water_waves
CVar * mp_state
Designed to work smoothly with optimizations disabled.
Definition Vec3.h:29
float x
Definition Vec3.h:30
float z
Definition Vec3.h:30
float y
Definition Vec3.h:30