project(seamulator)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}")
-
-find_package(OpenGL REQUIRED)
-find_package(GLUT REQUIRED)
-find_package(fftw3 REQUIRED)
-
-include_directories(${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS}
- ${FFTW_INCLUDES})
-
-add_executable(seamulator seamulator.cpp
- sea.cpp watersurface.cpp surfacepoint.cpp
- seaview.cpp)
-
-target_link_libraries(seamulator ${OPENGL_LIBRARIES} ${GLUT_LIBRARY}
- ${FFTW_LIBRARIES})
+add_subdirectory(src)
--- /dev/null
+#pragma once
+
+#include <chrono>
+#include <complex>
+#include <random>
+
+#include <fftw3.h>
+
+#include "seafwd.h"
+
+#include "watersurfacefwd.h"
+
+class Sea
+{
+ public:
+ Sea(WaterSurfacePtr surface);
+ ~Sea();
+ Sea(const Sea&) = delete;
+ Sea& operator=(const Sea&) = delete;
+ void update();
+
+ private:
+ static const double PHILLIPS_CONSTANT;
+ static const double GRAVITATIONAL_CONSTANT;
+
+ WaterSurfacePtr m_surface;
+ double m_windDirection[2];
+ double m_windSpeed;
+ std::random_device m_randomDevice;
+ std::mt19937 m_randomGenerator;
+ std::normal_distribution<> m_normalDistribution;
+ std::vector<std::complex<double>> m_fourierAmplitudes;
+ fftw_complex *m_fftwIn, *m_fftwOut;
+ fftw_plan m_fftwPlan;
+ std::chrono::time_point<std::chrono::system_clock> m_startTime;
+
+ double phillipsSpectrum(double k_x, double k_y) const;
+ std::complex<double>& fourierAmplitudeAt(int n, int m);
+ void generateFourierAmplitudes();
+ double spatialFrequencyForIndex(int n) const;
+ double getRuntime() const;
+};
--- /dev/null
+#pragma once
+
+#include <memory>
+
+class Sea;
+using SeaPtr = std::shared_ptr<Sea>;
--- /dev/null
+#pragma once
+
+class SeaView
+{
+ public:
+ SeaView(double distance, double azimuth, double altitude);
+ void onMouseEvent(int button, int state, int x, int y);
+ void onMouseMove(int x, int y);
+ void setupView() const;
+
+ private:
+ static constexpr double DISTANCE_MULTIPLIER = 0.1f;
+
+ double m_distance;
+ double m_azimuth;
+ double m_altitude;
+ int m_mouseDownPos[2];
+ double m_mouseDownAltitude;
+ double m_mouseDownAzimuth;
+};
--- /dev/null
+#pragma once
+
+class SurfacePoint
+{
+ public:
+ double getHeight() const;
+ void setHeight(double height);
+
+ private:
+ double m_height = 0;
+};
--- /dev/null
+#pragma once
+
+#include "watersurfacefwd.h"
+
+#include <vector>
+
+#include "surfacepoint.h"
+
+class WaterSurface
+{
+ public:
+ WaterSurface(int size, double unitLength);
+ SurfacePoint& at(int x, int y);
+ const SurfacePoint& at(int x, int y) const;
+ int size() const;
+ double extend() const;
+ void draw() const;
+ void drawSingleTile(int x, int y) const;
+
+ private:
+ std::vector<SurfacePoint> m_points;
+ int m_size;
+ double m_extend;
+};
--- /dev/null
+#pragma once
+
+#include <memory>
+
+class WaterSurface;
+using WaterSurfacePtr = std::shared_ptr<WaterSurface>;
+++ /dev/null
-#include "sea.h"
-
-#include <cmath>
-#include <cstdlib>
-#include <iostream>
-
-#include "watersurface.h"
-
-const double Sea::PHILLIPS_CONSTANT{0.0000001};
-const double Sea::GRAVITATIONAL_CONSTANT{9.8};
-
-Sea::Sea(WaterSurfacePtr surface) :
- m_surface{surface},
- m_windDirection{1, 0},
- m_windSpeed{10},
- m_randomGenerator{m_randomDevice()},
- m_normalDistribution{0.0, 1.0}
-{
- m_fourierAmplitudes.resize(pow(m_surface->size() + 1, 2));
- generateFourierAmplitudes();
-
- m_fftwIn = (fftw_complex*)
- fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
- m_fftwOut = (fftw_complex*)
- fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
- m_fftwPlan = fftw_plan_dft_2d
- (m_surface->size(), m_surface->size(), m_fftwIn, m_fftwOut,
- FFTW_BACKWARD, FFTW_MEASURE);
-
- m_startTime = std::chrono::system_clock::now();
-}
-
-Sea::~Sea()
-{
- fftw_destroy_plan(m_fftwPlan);
- fftw_free(m_fftwIn); fftw_free(m_fftwOut);
-}
-
-double Sea::getRuntime() const
-{
- auto timeNow = std::chrono::system_clock::now();
- auto durationMs =
- std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startTime);
-
- return durationMs.count() / 1000.0;
-}
-
-void Sea::update()
-{
- using namespace std::complex_literals;
-
- const double runtime = getRuntime();
-
- for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
- const int positiveM = (m + m_surface->size()) % m_surface->size();
-
- for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
- const double k = sqrt(pow(spatialFrequencyForIndex(n), 2) +
- pow(spatialFrequencyForIndex(m), 2));
- const double omega = sqrt(GRAVITATIONAL_CONSTANT * k);
-
- std::complex<double> amplitude =
- fourierAmplitudeAt(n, m) * exp(1i * omega * runtime) +
- std::conj(fourierAmplitudeAt(-n, -m)) * exp(-1i * omega * runtime);
-
- const int positiveN = (n + m_surface->size()) % m_surface->size();
- int fftwIndex = positiveM + positiveN * m_surface->size();
-
- m_fftwIn[fftwIndex][0] = std::real(amplitude);
- m_fftwIn[fftwIndex][1] = std::imag(amplitude);
- }
- }
-
- fftw_execute(m_fftwPlan);
-
- for (int y = 0; y < m_surface->size(); ++y) {
- for (int x = 0; x < m_surface->size(); ++x) {
- m_surface->at(x, y)
- .setHeight(m_fftwOut[y + x * m_surface->size()][0]);
- }
- }
-}
-
-double Sea::phillipsSpectrum(double k_x, double k_y) const
-{
- const double k = sqrt(pow(k_x, 2) + pow(k_y, 2));
- const double L = pow(m_windSpeed, 2) / GRAVITATIONAL_CONSTANT;
-
- const double cosineFactor = pow((k_x / k) * m_windDirection[0] +
- (k_y / k) * m_windDirection[1], 2);
-
- return PHILLIPS_CONSTANT * exp(-1 / pow(k * L, 2)) / pow(k, 4) *
- cosineFactor;
-}
-
-std::complex<double>& Sea::fourierAmplitudeAt(int n, int m)
-{
- return m_fourierAmplitudes.at
- (n + m_surface->size()/2 +
- (m + m_surface->size()/2) * m_surface->size());
-}
-
-double Sea::spatialFrequencyForIndex(int n) const
-{
- return 2 * M_PI * n / m_surface->size();
-}
-
-void Sea::generateFourierAmplitudes()
-{
- for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
- const double k_y = spatialFrequencyForIndex(m);
-
- for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
- const double k_x = spatialFrequencyForIndex(n);
-
- std::complex<double> cDist(m_normalDistribution(m_randomGenerator),
- m_normalDistribution(m_randomGenerator));
-
- fourierAmplitudeAt(n, m) =
- cDist * sqrt(phillipsSpectrum(k_x, k_y)) / sqrt(2);
- }
- }
-
- for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
- fourierAmplitudeAt(n, m_surface->size()/2) =
- fourierAmplitudeAt(n, -m_surface->size()/2);
- }
-
- for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
- fourierAmplitudeAt(m_surface->size()/2, m) =
- fourierAmplitudeAt(-m_surface->size()/2, m);
- }
-
- fourierAmplitudeAt(0, 0) = {0, 0};
-}
+++ /dev/null
-#pragma once
-
-#include <chrono>
-#include <complex>
-#include <random>
-
-#include <fftw3.h>
-
-#include "seafwd.h"
-
-#include "watersurfacefwd.h"
-
-class Sea
-{
- public:
- Sea(WaterSurfacePtr surface);
- ~Sea();
- Sea(const Sea&) = delete;
- Sea& operator=(const Sea&) = delete;
- void update();
-
- private:
- static const double PHILLIPS_CONSTANT;
- static const double GRAVITATIONAL_CONSTANT;
-
- WaterSurfacePtr m_surface;
- double m_windDirection[2];
- double m_windSpeed;
- std::random_device m_randomDevice;
- std::mt19937 m_randomGenerator;
- std::normal_distribution<> m_normalDistribution;
- std::vector<std::complex<double>> m_fourierAmplitudes;
- fftw_complex *m_fftwIn, *m_fftwOut;
- fftw_plan m_fftwPlan;
- std::chrono::time_point<std::chrono::system_clock> m_startTime;
-
- double phillipsSpectrum(double k_x, double k_y) const;
- std::complex<double>& fourierAmplitudeAt(int n, int m);
- void generateFourierAmplitudes();
- double spatialFrequencyForIndex(int n) const;
- double getRuntime() const;
-};
+++ /dev/null
-#pragma once
-
-#include <memory>
-
-class Sea;
-using SeaPtr = std::shared_ptr<Sea>;
+++ /dev/null
-#include <ctime>
-#include <cmath>
-#include <memory>
-
-#include <GL/glut.h>
-
-#include "sea.h"
-#include "seaview.h"
-#include "watersurface.h"
-
-const int LATTICE_SIZE{128};
-const double LATTICE_EXTEND{10};
-const int INIT_WINDOW_POS_X{50};
-const int INIT_WINDOW_POS_Y{50};
-const int INIT_WINDOW_WIDTH{800};
-const int INIT_WINDOW_HEIGHT{600};
-const double INIT_VIEW_DISTANCE{LATTICE_EXTEND * 1.5};
-const double INIT_VIEW_AZIMUTH{0};
-const double INIT_VIEW_ALTITUDE{M_PI / 4};
-const char WINDOW_TITLE[]{"seamulator"};
-
-SeaPtr sea;
-WaterSurfacePtr surface;
-std::unique_ptr<SeaView> seaView;
-
-void glDisplayFunc();
-void glReshapeFunc(int width, int height);
-void glMouseFunc(int button, int state, int x, int y);
-void glMotionFunc(int x, int y);
-
-int main(int argc, char** argv)
-{
- std::srand(std::time(0));
-
- surface = std::make_shared<WaterSurface>(LATTICE_SIZE, LATTICE_EXTEND);
- sea = std::make_shared<Sea>(surface);
- seaView = std::make_unique<SeaView>(INIT_VIEW_DISTANCE, INIT_VIEW_AZIMUTH,
- INIT_VIEW_ALTITUDE);
-
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE);
- glutInitWindowSize(INIT_WINDOW_WIDTH, INIT_WINDOW_HEIGHT);
- glutInitWindowPosition(INIT_WINDOW_POS_X, INIT_WINDOW_POS_Y);
- glutCreateWindow(WINDOW_TITLE);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- glutDisplayFunc(glDisplayFunc);
- glutReshapeFunc(glReshapeFunc);
- glutMouseFunc(glMouseFunc);
- glutMotionFunc(glMotionFunc);
-
- glutMainLoop();
-
- return 0;
-}
-
-void glDisplayFunc()
-{
- glClear(GL_COLOR_BUFFER_BIT);
-
- seaView->setupView();
- sea->update();
- surface->draw();
-
- glutSwapBuffers();
- glutPostRedisplay();
-}
-
-void glReshapeFunc(int width, int height)
-{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(50.0, ((float)width/(float)height), 0, 1000.0);
- glViewport(0, 0, width, height);
-}
-
-void glMouseFunc(int button, int state, int x, int y)
-{
- seaView->onMouseEvent(button, state, x, y);
-}
-
-void glMotionFunc(int x, int y)
-{
- seaView->onMouseMove(x, y);
-}
+++ /dev/null
-#include "seaview.h"
-
-#include <cmath>
-
-#include <GL/glut.h>
-
-SeaView::SeaView(double distance, double azimuth, double altitude) :
- m_distance{distance},
- m_azimuth{azimuth},
- m_altitude{altitude}
-{
-}
-
-void SeaView::onMouseEvent(int button, int state, int x, int y)
-{
- if (button == 3 && state == 0) {
- m_distance += m_distance*DISTANCE_MULTIPLIER;
- glutPostRedisplay();
- }
- else if (button == 4 && state == 0) {
- m_distance -= m_distance*DISTANCE_MULTIPLIER;
- glutPostRedisplay();
- }
- else if (button == 0 && state == 0) {
- m_mouseDownPos[0] = x;
- m_mouseDownPos[1] = y;
- m_mouseDownAzimuth = m_azimuth;
- m_mouseDownAltitude = m_altitude;
- }
-}
-
-void SeaView::onMouseMove(int x, int y)
-{
- m_altitude =
- fmod(m_mouseDownAltitude +
- (double)((y - m_mouseDownPos[1]) *
- 2*M_PI / glutGet(GLUT_WINDOW_HEIGHT)),
- (double)(2*M_PI));
-
- m_azimuth =
- fmod(m_mouseDownAzimuth +
- (double)((x - m_mouseDownPos[0]) *
- 2*M_PI / glutGet(GLUT_WINDOW_WIDTH)),
- (double)(2*M_PI));
-
- glutPostRedisplay();
-}
-
-void SeaView::setupView() const
-{
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- const double eyePos[3] =
- {m_distance * cos(m_altitude) * sin(m_azimuth),
- m_distance * cos(m_altitude) * cos(m_azimuth),
- m_distance * sin(m_altitude)};
-
- gluLookAt(eyePos[0], eyePos[1], eyePos[2],
- 0, 0, 0,
- 0, 0, 1);
-}
+++ /dev/null
-#pragma once
-
-class SeaView
-{
- public:
- SeaView(double distance, double azimuth, double altitude);
- void onMouseEvent(int button, int state, int x, int y);
- void onMouseMove(int x, int y);
- void setupView() const;
-
- private:
- static constexpr double DISTANCE_MULTIPLIER = 0.1f;
-
- double m_distance;
- double m_azimuth;
- double m_altitude;
- int m_mouseDownPos[2];
- double m_mouseDownAltitude;
- double m_mouseDownAzimuth;
-};
--- /dev/null
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}")
+
+find_package(OpenGL REQUIRED)
+find_package(GLUT REQUIRED)
+find_package(fftw3 REQUIRED)
+
+include_directories(${seamulator_SOURCE_DIR}/include
+ ${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS}
+ ${FFTW_INCLUDES})
+
+add_executable(seamulator seamulator.cpp
+ sea.cpp watersurface.cpp surfacepoint.cpp
+ seaview.cpp)
+
+target_link_libraries(seamulator ${OPENGL_LIBRARIES} ${GLUT_LIBRARY}
+ ${FFTW_LIBRARIES})
--- /dev/null
+#include "sea.h"
+
+#include <cmath>
+#include <cstdlib>
+#include <iostream>
+
+#include "watersurface.h"
+
+const double Sea::PHILLIPS_CONSTANT{0.0000001};
+const double Sea::GRAVITATIONAL_CONSTANT{9.8};
+
+Sea::Sea(WaterSurfacePtr surface) :
+ m_surface{surface},
+ m_windDirection{1, 0},
+ m_windSpeed{10},
+ m_randomGenerator{m_randomDevice()},
+ m_normalDistribution{0.0, 1.0}
+{
+ m_fourierAmplitudes.resize(pow(m_surface->size() + 1, 2));
+ generateFourierAmplitudes();
+
+ m_fftwIn = (fftw_complex*)
+ fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
+ m_fftwOut = (fftw_complex*)
+ fftw_malloc(sizeof(fftw_complex) * pow(m_surface->size(), 2));
+ m_fftwPlan = fftw_plan_dft_2d
+ (m_surface->size(), m_surface->size(), m_fftwIn, m_fftwOut,
+ FFTW_BACKWARD, FFTW_MEASURE);
+
+ m_startTime = std::chrono::system_clock::now();
+}
+
+Sea::~Sea()
+{
+ fftw_destroy_plan(m_fftwPlan);
+ fftw_free(m_fftwIn); fftw_free(m_fftwOut);
+}
+
+double Sea::getRuntime() const
+{
+ auto timeNow = std::chrono::system_clock::now();
+ auto durationMs =
+ std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startTime);
+
+ return durationMs.count() / 1000.0;
+}
+
+void Sea::update()
+{
+ using namespace std::complex_literals;
+
+ const double runtime = getRuntime();
+
+ for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
+ const int positiveM = (m + m_surface->size()) % m_surface->size();
+
+ for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
+ const double k = sqrt(pow(spatialFrequencyForIndex(n), 2) +
+ pow(spatialFrequencyForIndex(m), 2));
+ const double omega = sqrt(GRAVITATIONAL_CONSTANT * k);
+
+ std::complex<double> amplitude =
+ fourierAmplitudeAt(n, m) * exp(1i * omega * runtime) +
+ std::conj(fourierAmplitudeAt(-n, -m)) * exp(-1i * omega * runtime);
+
+ const int positiveN = (n + m_surface->size()) % m_surface->size();
+ int fftwIndex = positiveM + positiveN * m_surface->size();
+
+ m_fftwIn[fftwIndex][0] = std::real(amplitude);
+ m_fftwIn[fftwIndex][1] = std::imag(amplitude);
+ }
+ }
+
+ fftw_execute(m_fftwPlan);
+
+ for (int y = 0; y < m_surface->size(); ++y) {
+ for (int x = 0; x < m_surface->size(); ++x) {
+ m_surface->at(x, y)
+ .setHeight(m_fftwOut[y + x * m_surface->size()][0]);
+ }
+ }
+}
+
+double Sea::phillipsSpectrum(double k_x, double k_y) const
+{
+ const double k = sqrt(pow(k_x, 2) + pow(k_y, 2));
+ const double L = pow(m_windSpeed, 2) / GRAVITATIONAL_CONSTANT;
+
+ const double cosineFactor = pow((k_x / k) * m_windDirection[0] +
+ (k_y / k) * m_windDirection[1], 2);
+
+ return PHILLIPS_CONSTANT * exp(-1 / pow(k * L, 2)) / pow(k, 4) *
+ cosineFactor;
+}
+
+std::complex<double>& Sea::fourierAmplitudeAt(int n, int m)
+{
+ return m_fourierAmplitudes.at
+ (n + m_surface->size()/2 +
+ (m + m_surface->size()/2) * m_surface->size());
+}
+
+double Sea::spatialFrequencyForIndex(int n) const
+{
+ return 2 * M_PI * n / m_surface->size();
+}
+
+void Sea::generateFourierAmplitudes()
+{
+ for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
+ const double k_y = spatialFrequencyForIndex(m);
+
+ for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
+ const double k_x = spatialFrequencyForIndex(n);
+
+ std::complex<double> cDist(m_normalDistribution(m_randomGenerator),
+ m_normalDistribution(m_randomGenerator));
+
+ fourierAmplitudeAt(n, m) =
+ cDist * sqrt(phillipsSpectrum(k_x, k_y)) / sqrt(2);
+ }
+ }
+
+ for (int n = -m_surface->size()/2; n < m_surface->size()/2; ++n) {
+ fourierAmplitudeAt(n, m_surface->size()/2) =
+ fourierAmplitudeAt(n, -m_surface->size()/2);
+ }
+
+ for (int m = -m_surface->size()/2; m < m_surface->size()/2; ++m) {
+ fourierAmplitudeAt(m_surface->size()/2, m) =
+ fourierAmplitudeAt(-m_surface->size()/2, m);
+ }
+
+ fourierAmplitudeAt(0, 0) = {0, 0};
+}
--- /dev/null
+#include <ctime>
+#include <cmath>
+#include <memory>
+
+#include <GL/glut.h>
+
+#include "sea.h"
+#include "seaview.h"
+#include "watersurface.h"
+
+const int LATTICE_SIZE{128};
+const double LATTICE_EXTEND{10};
+const int INIT_WINDOW_POS_X{50};
+const int INIT_WINDOW_POS_Y{50};
+const int INIT_WINDOW_WIDTH{800};
+const int INIT_WINDOW_HEIGHT{600};
+const double INIT_VIEW_DISTANCE{LATTICE_EXTEND * 1.5};
+const double INIT_VIEW_AZIMUTH{0};
+const double INIT_VIEW_ALTITUDE{M_PI / 4};
+const char WINDOW_TITLE[]{"seamulator"};
+
+SeaPtr sea;
+WaterSurfacePtr surface;
+std::unique_ptr<SeaView> seaView;
+
+void glDisplayFunc();
+void glReshapeFunc(int width, int height);
+void glMouseFunc(int button, int state, int x, int y);
+void glMotionFunc(int x, int y);
+
+int main(int argc, char** argv)
+{
+ std::srand(std::time(0));
+
+ surface = std::make_shared<WaterSurface>(LATTICE_SIZE, LATTICE_EXTEND);
+ sea = std::make_shared<Sea>(surface);
+ seaView = std::make_unique<SeaView>(INIT_VIEW_DISTANCE, INIT_VIEW_AZIMUTH,
+ INIT_VIEW_ALTITUDE);
+
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_DOUBLE);
+ glutInitWindowSize(INIT_WINDOW_WIDTH, INIT_WINDOW_HEIGHT);
+ glutInitWindowPosition(INIT_WINDOW_POS_X, INIT_WINDOW_POS_Y);
+ glutCreateWindow(WINDOW_TITLE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glutDisplayFunc(glDisplayFunc);
+ glutReshapeFunc(glReshapeFunc);
+ glutMouseFunc(glMouseFunc);
+ glutMotionFunc(glMotionFunc);
+
+ glutMainLoop();
+
+ return 0;
+}
+
+void glDisplayFunc()
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ seaView->setupView();
+ sea->update();
+ surface->draw();
+
+ glutSwapBuffers();
+ glutPostRedisplay();
+}
+
+void glReshapeFunc(int width, int height)
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(50.0, ((float)width/(float)height), 0, 1000.0);
+ glViewport(0, 0, width, height);
+}
+
+void glMouseFunc(int button, int state, int x, int y)
+{
+ seaView->onMouseEvent(button, state, x, y);
+}
+
+void glMotionFunc(int x, int y)
+{
+ seaView->onMouseMove(x, y);
+}
--- /dev/null
+#include "seaview.h"
+
+#include <cmath>
+
+#include <GL/glut.h>
+
+SeaView::SeaView(double distance, double azimuth, double altitude) :
+ m_distance{distance},
+ m_azimuth{azimuth},
+ m_altitude{altitude}
+{
+}
+
+void SeaView::onMouseEvent(int button, int state, int x, int y)
+{
+ if (button == 3 && state == 0) {
+ m_distance += m_distance*DISTANCE_MULTIPLIER;
+ glutPostRedisplay();
+ }
+ else if (button == 4 && state == 0) {
+ m_distance -= m_distance*DISTANCE_MULTIPLIER;
+ glutPostRedisplay();
+ }
+ else if (button == 0 && state == 0) {
+ m_mouseDownPos[0] = x;
+ m_mouseDownPos[1] = y;
+ m_mouseDownAzimuth = m_azimuth;
+ m_mouseDownAltitude = m_altitude;
+ }
+}
+
+void SeaView::onMouseMove(int x, int y)
+{
+ m_altitude =
+ fmod(m_mouseDownAltitude +
+ (double)((y - m_mouseDownPos[1]) *
+ 2*M_PI / glutGet(GLUT_WINDOW_HEIGHT)),
+ (double)(2*M_PI));
+
+ m_azimuth =
+ fmod(m_mouseDownAzimuth +
+ (double)((x - m_mouseDownPos[0]) *
+ 2*M_PI / glutGet(GLUT_WINDOW_WIDTH)),
+ (double)(2*M_PI));
+
+ glutPostRedisplay();
+}
+
+void SeaView::setupView() const
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ const double eyePos[3] =
+ {m_distance * cos(m_altitude) * sin(m_azimuth),
+ m_distance * cos(m_altitude) * cos(m_azimuth),
+ m_distance * sin(m_altitude)};
+
+ gluLookAt(eyePos[0], eyePos[1], eyePos[2],
+ 0, 0, 0,
+ 0, 0, 1);
+}
--- /dev/null
+#include "surfacepoint.h"
+
+double SurfacePoint::getHeight() const
+{
+ return m_height;
+}
+
+void SurfacePoint::setHeight(double height)
+{
+ m_height = height;
+}
--- /dev/null
+#include "watersurface.h"
+
+#include <GL/glut.h>
+
+WaterSurface::WaterSurface(int size, double extend) :
+ m_size{size},
+ m_extend{extend}
+{
+ m_points.resize(size*size);
+}
+
+SurfacePoint& WaterSurface::at(int x, int y)
+{
+ return m_points.at(x + m_size*y);
+}
+
+const SurfacePoint& WaterSurface::at(int x, int y) const
+{
+ return m_points.at(x + m_size*y);
+}
+
+int WaterSurface::size() const
+{
+ return m_size;
+}
+
+double WaterSurface::extend() const
+{
+ return m_extend;
+}
+
+void WaterSurface::draw() const
+{
+ const double scaleFactor{m_extend / m_size};
+
+ glScalef(scaleFactor, scaleFactor, 1.0f);
+ glTranslatef(-(float)(m_size - 1) / 2, -(float)(m_size - 1) / 2, 0);
+
+ for (int y = 0; y < m_size - 1; ++y) {
+ for (int x = 0; x < m_size - 1; ++x) {
+ drawSingleTile(x, y);
+ }
+ }
+}
+
+void WaterSurface::drawSingleTile(int x, int y) const
+{
+ glBegin(GL_TRIANGLES);
+
+ glVertex3f(x, y, at(x, y).getHeight());
+ glVertex3f(x+1, y, at(x+1, y).getHeight());
+ glVertex3f(x+1, y+1, at(x+1, y+1).getHeight());
+
+ glVertex3f(x, y, at(x, y).getHeight());
+ glVertex3f(x, y+1, at(x, y+1).getHeight());
+ glVertex3f(x+1, y+1, at(x+1, y+1).getHeight());
+
+ glEnd();
+}
+++ /dev/null
-#include "surfacepoint.h"
-
-double SurfacePoint::getHeight() const
-{
- return m_height;
-}
-
-void SurfacePoint::setHeight(double height)
-{
- m_height = height;
-}
+++ /dev/null
-#pragma once
-
-class SurfacePoint
-{
- public:
- double getHeight() const;
- void setHeight(double height);
-
- private:
- double m_height = 0;
-};
+++ /dev/null
-#include "watersurface.h"
-
-#include <GL/glut.h>
-
-WaterSurface::WaterSurface(int size, double extend) :
- m_size{size},
- m_extend{extend}
-{
- m_points.resize(size*size);
-}
-
-SurfacePoint& WaterSurface::at(int x, int y)
-{
- return m_points.at(x + m_size*y);
-}
-
-const SurfacePoint& WaterSurface::at(int x, int y) const
-{
- return m_points.at(x + m_size*y);
-}
-
-int WaterSurface::size() const
-{
- return m_size;
-}
-
-double WaterSurface::extend() const
-{
- return m_extend;
-}
-
-void WaterSurface::draw() const
-{
- const double scaleFactor{m_extend / m_size};
-
- glScalef(scaleFactor, scaleFactor, 1.0f);
- glTranslatef(-(float)(m_size - 1) / 2, -(float)(m_size - 1) / 2, 0);
-
- for (int y = 0; y < m_size - 1; ++y) {
- for (int x = 0; x < m_size - 1; ++x) {
- drawSingleTile(x, y);
- }
- }
-}
-
-void WaterSurface::drawSingleTile(int x, int y) const
-{
- glBegin(GL_TRIANGLES);
-
- glVertex3f(x, y, at(x, y).getHeight());
- glVertex3f(x+1, y, at(x+1, y).getHeight());
- glVertex3f(x+1, y+1, at(x+1, y+1).getHeight());
-
- glVertex3f(x, y, at(x, y).getHeight());
- glVertex3f(x, y+1, at(x, y+1).getHeight());
- glVertex3f(x+1, y+1, at(x+1, y+1).getHeight());
-
- glEnd();
-}
+++ /dev/null
-#pragma once
-
-#include "watersurfacefwd.h"
-
-#include <vector>
-
-#include "surfacepoint.h"
-
-class WaterSurface
-{
- public:
- WaterSurface(int size, double unitLength);
- SurfacePoint& at(int x, int y);
- const SurfacePoint& at(int x, int y) const;
- int size() const;
- double extend() const;
- void draw() const;
- void drawSingleTile(int x, int y) const;
-
- private:
- std::vector<SurfacePoint> m_points;
- int m_size;
- double m_extend;
-};
+++ /dev/null
-#pragma once
-
-#include <memory>
-
-class WaterSurface;
-using WaterSurfacePtr = std::shared_ptr<WaterSurface>;