]> git.treefish.org Git - seamulator.git/commitdiff
Changed directory structure
authorAlexander Schmidt <alex@treefish.org>
Wed, 20 Jul 2016 20:29:48 +0000 (22:29 +0200)
committerAlexander Schmidt <alex@treefish.org>
Wed, 20 Jul 2016 20:29:48 +0000 (22:29 +0200)
24 files changed:
CMakeLists.txt
include/sea.h [new file with mode: 0644]
include/seafwd.h [new file with mode: 0644]
include/seaview.h [new file with mode: 0644]
include/surfacepoint.h [new file with mode: 0644]
include/watersurface.h [new file with mode: 0644]
include/watersurfacefwd.h [new file with mode: 0644]
sea.cpp [deleted file]
sea.h [deleted file]
seafwd.h [deleted file]
seamulator.cpp [deleted file]
seaview.cpp [deleted file]
seaview.h [deleted file]
src/CMakeLists.txt [new file with mode: 0644]
src/sea.cpp [new file with mode: 0644]
src/seamulator.cpp [new file with mode: 0644]
src/seaview.cpp [new file with mode: 0644]
src/surfacepoint.cpp [new file with mode: 0644]
src/watersurface.cpp [new file with mode: 0644]
surfacepoint.cpp [deleted file]
surfacepoint.h [deleted file]
watersurface.cpp [deleted file]
watersurface.h [deleted file]
watersurfacefwd.h [deleted file]

index b6b7e6b7a6918cbf3a6c79184db89ccc19401c87..5fff49e42ec3b0617a09a83f620c79570092effb 100644 (file)
@@ -2,20 +2,4 @@ cmake_minimum_required(VERSION 2.8)
 
 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)
diff --git a/include/sea.h b/include/sea.h
new file mode 100644 (file)
index 0000000..798b92d
--- /dev/null
@@ -0,0 +1,42 @@
+#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;
+};
diff --git a/include/seafwd.h b/include/seafwd.h
new file mode 100644 (file)
index 0000000..22977d7
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <memory>
+
+class Sea;
+using SeaPtr = std::shared_ptr<Sea>;
diff --git a/include/seaview.h b/include/seaview.h
new file mode 100644 (file)
index 0000000..213bce0
--- /dev/null
@@ -0,0 +1,20 @@
+#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;
+};
diff --git a/include/surfacepoint.h b/include/surfacepoint.h
new file mode 100644 (file)
index 0000000..9a577f9
--- /dev/null
@@ -0,0 +1,11 @@
+#pragma once
+
+class SurfacePoint
+{
+ public:
+  double getHeight() const;
+  void setHeight(double height);
+
+ private:
+  double m_height = 0;
+};
diff --git a/include/watersurface.h b/include/watersurface.h
new file mode 100644 (file)
index 0000000..22d3c48
--- /dev/null
@@ -0,0 +1,24 @@
+#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;
+};
diff --git a/include/watersurfacefwd.h b/include/watersurfacefwd.h
new file mode 100644 (file)
index 0000000..efb7fe3
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <memory>
+
+class WaterSurface;
+using WaterSurfacePtr = std::shared_ptr<WaterSurface>;
diff --git a/sea.cpp b/sea.cpp
deleted file mode 100644 (file)
index 85191d4..0000000
--- a/sea.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#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};
-}
diff --git a/sea.h b/sea.h
deleted file mode 100644 (file)
index 798b92d..0000000
--- a/sea.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#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;
-};
diff --git a/seafwd.h b/seafwd.h
deleted file mode 100644 (file)
index 22977d7..0000000
--- a/seafwd.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include <memory>
-
-class Sea;
-using SeaPtr = std::shared_ptr<Sea>;
diff --git a/seamulator.cpp b/seamulator.cpp
deleted file mode 100644 (file)
index c5f7936..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#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);
-}
diff --git a/seaview.cpp b/seaview.cpp
deleted file mode 100644 (file)
index 035f557..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#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);
-}
diff --git a/seaview.h b/seaview.h
deleted file mode 100644 (file)
index 213bce0..0000000
--- a/seaview.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#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;
-};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..24c9ef6
--- /dev/null
@@ -0,0 +1,18 @@
+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})
diff --git a/src/sea.cpp b/src/sea.cpp
new file mode 100644 (file)
index 0000000..85191d4
--- /dev/null
@@ -0,0 +1,135 @@
+#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};
+}
diff --git a/src/seamulator.cpp b/src/seamulator.cpp
new file mode 100644 (file)
index 0000000..c5f7936
--- /dev/null
@@ -0,0 +1,85 @@
+#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);
+}
diff --git a/src/seaview.cpp b/src/seaview.cpp
new file mode 100644 (file)
index 0000000..035f557
--- /dev/null
@@ -0,0 +1,62 @@
+#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);
+}
diff --git a/src/surfacepoint.cpp b/src/surfacepoint.cpp
new file mode 100644 (file)
index 0000000..4e39d07
--- /dev/null
@@ -0,0 +1,11 @@
+#include "surfacepoint.h"
+
+double SurfacePoint::getHeight() const
+{
+  return m_height;
+}
+
+void SurfacePoint::setHeight(double height)
+{
+  m_height = height;
+}
diff --git a/src/watersurface.cpp b/src/watersurface.cpp
new file mode 100644 (file)
index 0000000..a38ad57
--- /dev/null
@@ -0,0 +1,59 @@
+#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();
+}
diff --git a/surfacepoint.cpp b/surfacepoint.cpp
deleted file mode 100644 (file)
index 4e39d07..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "surfacepoint.h"
-
-double SurfacePoint::getHeight() const
-{
-  return m_height;
-}
-
-void SurfacePoint::setHeight(double height)
-{
-  m_height = height;
-}
diff --git a/surfacepoint.h b/surfacepoint.h
deleted file mode 100644 (file)
index 9a577f9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-class SurfacePoint
-{
- public:
-  double getHeight() const;
-  void setHeight(double height);
-
- private:
-  double m_height = 0;
-};
diff --git a/watersurface.cpp b/watersurface.cpp
deleted file mode 100644 (file)
index a38ad57..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#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();
-}
diff --git a/watersurface.h b/watersurface.h
deleted file mode 100644 (file)
index 22d3c48..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#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;
-};
diff --git a/watersurfacefwd.h b/watersurfacefwd.h
deleted file mode 100644 (file)
index efb7fe3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include <memory>
-
-class WaterSurface;
-using WaterSurfacePtr = std::shared_ptr<WaterSurface>;