diff --git a/README.md b/README.md index 74115a9..5806eed 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ struct GerstnerWave { }; ``` + +Tuto strukturu si můžete libovolně upravit a předat funkci například jako pole strutkur. + ## Dokumentace V dokumentaci **podrobně popište** postup optimalizace. Pro lepší přehlednost můžete využít: @@ -61,7 +64,7 @@ Na poslední cvičení bude obhajoba projektu, cílem je ukázat, že projektu r ### Windows + VS Code -Projekt spusťte ve **VS Code** z **2. cvičení**, které obsahuje všechny potřebné knihovny. +Projekt spusťte ve **VS Code** z **2. cvičení**, které obsahuje všechny potřebné knihovny. Jelikož šablona pro windows obsahuje relativní cesty k root složce archívu, musíte nakopírovat sloužku "windows" projektu do root složky ze cvičení. ### Linux diff --git a/linux/.vscode/settings.json b/linux/.vscode/settings.json index e06af31..31b2ac6 100644 --- a/linux/.vscode/settings.json +++ b/linux/.vscode/settings.json @@ -58,6 +58,11 @@ "streambuf": "cpp", "thread": "cpp", "cinttypes": "cpp", - "typeinfo": "cpp" + "typeinfo": "cpp", + "forward_list": "cpp", + "list": "cpp", + "unordered_set": "cpp", + "optional": "cpp", + "typeindex": "cpp" } } \ No newline at end of file diff --git a/linux/Makefile b/linux/Makefile index fe1349c..f03d59d 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -47,6 +47,7 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.s # Clean target clean: rm $(BUILD_DIR)/* + rm $(EXECUTABLE_PATH) # Debug build target debug: CXXFLAGS += -DDEBUG -g diff --git a/linux/include/Ocean.h b/linux/include/Ocean.h index dfd8b36..469d0ab 100644 --- a/linux/include/Ocean.h +++ b/linux/include/Ocean.h @@ -79,8 +79,8 @@ private: void generateGrid(); void createBuffers(); // Create and populate VBOs and IBO void updateBuffers(const std::vector& updatedVertices, const std::vector& updatedNormals); // Update VBO data - void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time); // Update vertex Y positions based on wave function - + //void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time); // Update vertex Y positions based on wave function + void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time); #if ASM_TYPE==CLEAR_ASM #else void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time); // Modified signature for C++ as well (for consistency or if you want to use float arrays in C++ SIMD too) diff --git a/linux/include/utils.h b/linux/include/utils.h index 10b490f..c5dfb7f 100644 --- a/linux/include/utils.h +++ b/linux/include/utils.h @@ -5,11 +5,12 @@ #include #include #include - +#include // Helper function to check for OpenGL errors and print a message void checkGLError(const char* operation); float perlinNoise(float x, float y); // Placeholder declaration - +void convert_vec3_to_float_array(const std::vector& src, float * dst); +void convert_float_array_to_vec3(float * src, std::vector& dst); uint64_t rdtsc(); #endif // UTILS_H \ No newline at end of file diff --git a/linux/src/Ocean.cpp b/linux/src/Ocean.cpp index d42ce27..dd4c0d0 100644 --- a/linux/src/Ocean.cpp +++ b/linux/src/Ocean.cpp @@ -17,12 +17,12 @@ #if ASM_TYPE==CLEAR_ASM // Assembly version declaration (signature changed to float arrays) - extern "C" void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time); + extern "C" void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time); #else // C++ implementation of SIMD version (now also taking float arrays for consistency) - void Ocean::updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time) + void Ocean::updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) { // Placeholder C++ implementation using float arrays //for (size_t i = 0; i < numVertices; ++i) { @@ -46,10 +46,7 @@ Ocean::Ocean(int gridSize) : time(0.0f),gridSize(gridSize), gridSpacing(1.0f), //gerstnerWaves.push_back({0.5f, 1.2f, 2.0f, glm::normalize(glm::vec2(0.9f, 0.8f)), 0.0f}); } -Ocean::~Ocean() -{ - cleanup(); // Call cleanup to release OpenGL resources -} + bool Ocean::init() { @@ -59,29 +56,6 @@ bool Ocean::init() return true; } -void Ocean::cleanup() -{ - // No dynamic memory allocation in this simple version - // Release OpenGL resources (VBOs, IBO, VAO) - glDeleteBuffers(1, &vertexBufferID); - glDeleteBuffers(1, &normalBufferID); - glDeleteBuffers(1, &texCoordBufferID); - glDeleteBuffers(1, &indexBufferID); - glDeleteVertexArrays(1, &vaoID); - vertexBufferID = 0; - normalBufferID = 0; - texCoordBufferID = 0; - indexBufferID = 0; - vaoID = 0; -} - -void add_sse(float* a, float* b, float* result) { - __m128 vec1 = _mm_loadu_ps(a); // Load 4 floats from a - __m128 vec2 = _mm_loadu_ps(b); // Load 4 floats from b - __m128 sum = _mm_add_ps(vec1, vec2); // Perform vector addition - _mm_storeu_ps(result, sum); // Store result -} - void Ocean::update(float deltaTime) { @@ -97,49 +71,40 @@ void Ocean::update(float deltaTime) size_t numVertices = vertices.size(); size_t floatArraySize = numVertices * 3; - float* updatedVertices_array = new float[floatArraySize]; - float* updatedNormals_array = new float[floatArraySize]; - float* updatedVertices_simd_array = new float[floatArraySize]; // Array for SIMD function - float* updatedNormals_simd_array = new float[floatArraySize]; // Array for SIMD function - - // Convert vector of vec3 to float array (for both normal and simd versions) - for (size_t i = 0; i < numVertices; ++i) { - updatedVertices_array[i * 3 + 0] = updatedVertices_vec[i].x; - updatedVertices_array[i * 3 + 1] = updatedVertices_vec[i].y; - updatedVertices_array[i * 3 + 2] = updatedVertices_vec[i].z; - - updatedNormals_array[i * 3 + 0] = updatedNormals_vec[i].x; // Normals init - adjust as needed - updatedNormals_array[i * 3 + 1] = updatedNormals_vec[i].y; - updatedNormals_array[i * 3 + 2] = updatedNormals_vec[i].z; - - updatedVertices_simd_array[i * 3 + 0] = updatedVertices_simd_vec[i].x; // SIMD version init - updatedVertices_simd_array[i * 3 + 1] = updatedVertices_simd_vec[i].y; - updatedVertices_simd_array[i * 3 + 2] = updatedVertices_simd_vec[i].z; - - updatedNormals_simd_array[i * 3 + 0] = updatedNormals_simd_vec[i].x; // SIMD normals init - updatedNormals_simd_array[i * 3 + 1] = updatedNormals_simd_vec[i].y; - updatedNormals_simd_array[i * 3 + 2] = updatedNormals_simd_vec[i].z; - - } + //Reference C++ part auto start_time = std::chrono::high_resolution_clock::now(); uint64_t start = rdtsc(); // --- Call C++ version for comparison (using vector) --- - updateVertices(&updatedVertices_vec, &updatedNormals_vec, time); - + //updateVertices(&updatedVertices_vec, &updatedNormals_vec, time); + updateVertices(&updatedVertices_vec, &updatedNormals_vec, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + updateBuffers(updatedVertices_vec, updatedNormals_vec); // Use vectors for updateBuffers uint64_t end = rdtsc(); - auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end_time - start_time); std::cout << "Ocean::update took " << duration.count() << "ns " << "CPU cycles: " << (end - start) << std::endl; + //End Reference C++ part + + float* updatedVertices_simd_array = new float[floatArraySize]; // Array for SIMD function + float* updatedNormals_simd_array = new float[floatArraySize]; // Array for SIMD function + + //Start SIMD part + // Convert vector of vec3 to float array (for both normal and simd versions) + + convert_vec3_to_float_array(updatedVertices_simd_vec, updatedVertices_simd_array); // Convert base vertices + convert_vec3_to_float_array(updatedNormals_simd_vec, updatedNormals_simd_array); // Convert base vertices start_time = std::chrono::high_resolution_clock::now(); start = rdtsc(); - // --- Call SIMD version (now taking float arrays) --- - updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, time); + // READ + // Extend function parameters by passing a reference to a structure with + // Gerstner wave properties, allowing customization through your own implementation. + updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + + end = rdtsc(); end_time = std::chrono::high_resolution_clock::now(); @@ -152,22 +117,23 @@ void Ocean::update(float deltaTime) std::vector updatedVertices_vec_from_array(numVertices); std::vector updatedNormals_vec_from_array(numVertices); - for (size_t i = 0; i < numVertices; ++i) { - updatedVertices_vec_from_array[i].x = updatedVertices_simd_array[i * 3 + 0]; - updatedVertices_vec_from_array[i].y = updatedVertices_simd_array[i * 3 + 1]; - updatedVertices_vec_from_array[i].z = updatedVertices_simd_array[i * 3 + 2]; - - updatedNormals_vec_from_array[i].x = updatedNormals_simd_array[i * 3 + 0]; - updatedNormals_vec_from_array[i].y = updatedNormals_simd_array[i * 3 + 1]; - updatedNormals_vec_from_array[i].z = updatedNormals_simd_array[i * 3 + 2]; - } + convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array); + convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array); - updateBuffers(updatedVertices_vec_from_array, updatedNormals_vec_from_array); // Use vectors for updateBuffers + // READ + + // THIS FUNCTION UPDATES THE VERTICES AND NORMALS. If updateVertices_simd doesn't work, + // the surface will remain flat. Uncomment this after implementing the update logic. + + //updateBuffers(updatedVertices_vec_from_array, updatedNormals_vec_from_array); // Use vectors for updateBuffers + + //End SIMD part // --- Deallocate float arrays --- - + delete[] updatedVertices_simd_array; + delete[] updatedNormals_simd_array; } @@ -193,6 +159,135 @@ void Ocean::generateGrid() } } + + +void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) +{ + + for (int x = 0; x < _grid_size; ++x) + { + for (int z = 0; z < _grid_size; ++z) + { + + glm::vec3 &vertex = (*updatedVertices)[x * _grid_size + z]; // Use reference to modify directly + float originalX = originalWorldX_[x * _grid_size + z]; + float originalZ = originalWorldZ_[x * _grid_size + z]; + vertex.y = getWaveHeight(vertex.x, vertex.z, time); + + (*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords + } + } +} + + + +float Ocean::getWaveHeight(float x, float z, float time) const { + float totalHeight = 0.0f; + for (const auto& wave : gerstnerWaves) { + totalHeight += getGerstnerWaveHeight(wave, x, z, time); + } + return totalHeight; +} + +float Ocean::getGerstnerWaveHeight(const GerstnerWave& wave, float x, float z, float time) const { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + float waveHeightValue = periodicAmplitude * sin(k * dotProduct - w * time + wave.phase); + + if (fabs(x) < 0.5f && fabs(z) < 0.5f) { + //std::cout << " getGerstnerWaveHeight - time: " << time << ", periodicAmplitude: " << periodicAmplitude << ", waveHeightValue: " << waveHeightValue << std::endl; + } + + return waveHeightValue; +} + +glm::vec3 Ocean::getGerstnerWaveDisplacement(const GerstnerWave& wave, float x, float z, float time) const { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float cosTerm = cos(k * dotProduct - w * time + wave.phase); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + return glm::vec3(wave.direction.x * periodicAmplitude * cosTerm, + 0.0f, + wave.direction.y * periodicAmplitude * cosTerm); +} + +glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { + glm::vec3 tangentX = glm::vec3(1.0f, 0.0f, 0.0f); + glm::vec3 tangentZ = glm::vec3(0.0f, 0.0f, 1.0f); + + for (const auto& wave : gerstnerWaves) { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float sinTerm = sin(k * dotProduct - w * time + wave.phase); + float cosTerm = cos(k * dotProduct - w * time + wave.phase); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + float modulatedAmplitude = periodicAmplitude; + + // Calculate tangent vectors for EACH wave component and ACCUMULATE them directly + tangentX += glm::vec3( + -modulatedAmplitude * wave.direction.x * wave.direction.x * k * sinTerm, // dx_dx + modulatedAmplitude * wave.direction.x * k * cosTerm, // dy_dx + -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm // dz_dx + ); + + tangentZ += glm::vec3( + -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm, // dx_dz + modulatedAmplitude * wave.direction.y * k * cosTerm, // dy_dz + -modulatedAmplitude * wave.direction.y * wave.direction.y * k * sinTerm // dz_dz + ); + } + + return glm::normalize(glm::cross(tangentZ, tangentX)); +} + + +void Ocean::updateBuffers(const std::vector &updatedVertices, const std::vector &updatedNormals) +{ + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); + glBufferSubData(GL_ARRAY_BUFFER, 0, updatedVertices.size() * sizeof(glm::vec3), updatedVertices.data()); // Update vertex positions + + glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); + glBufferSubData(GL_ARRAY_BUFFER, 0, updatedNormals.size() * sizeof(glm::vec3), updatedNormals.data()); // Update normals +} + +glm::vec3 Ocean::getVertex(int x, int z) const +{ + return vertices[x * gridSize + z]; +} + + +void Ocean::setGridSize(int newGridSize) +{ + gridSize = newGridSize; + generateGrid(); // Re-generate the grid with the new size + + std::vector updatedVertices = vertices; // Create a copy to update + std::vector updatedNormals(vertices.size()); // Vector to store updated normals + + updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + + updateBuffers(updatedVertices, updatedNormals); + //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) +} + +GLuint Ocean::getVAO() const +{ + return vaoID; +} + +GLuint Ocean::getIndexCount() const +{ + return indexCount; +} + +int Ocean::getGridIndex(int x, int z) const { + return x * gridSize + z; +} + void Ocean::createBuffers() { glGenVertexArrays(1, &vaoID); @@ -278,126 +373,23 @@ void Ocean::createBuffers() indexCount = indices.size(); // Store index count for rendering } -void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time) +Ocean::~Ocean() { - - for (int x = 0; x < gridSize; ++x) - { - for (int z = 0; z < gridSize; ++z) - { - - glm::vec3 &vertex = vertices[x * gridSize + z]; - float originalX = originalWorldX[x * gridSize + z]; - float originalZ = originalWorldZ[x * gridSize + z]; - vertex.y = getWaveHeight(vertex.x, vertex.z, time); - - (*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords - } - } - //vertices = updatedVertices; // Assign the updated vertices back - //updateBuffers(updatedVertices, updatedNormals); + cleanup(); // Call cleanup to release OpenGL resources } -void Ocean::updateBuffers(const std::vector &updatedVertices, const std::vector &updatedNormals) +void Ocean::cleanup() { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - glBufferSubData(GL_ARRAY_BUFFER, 0, updatedVertices.size() * sizeof(glm::vec3), updatedVertices.data()); // Update vertex positions - - glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); - glBufferSubData(GL_ARRAY_BUFFER, 0, updatedNormals.size() * sizeof(glm::vec3), updatedNormals.data()); // Update normals -} - -glm::vec3 Ocean::getVertex(int x, int z) const -{ - return vertices[x * gridSize + z]; -} - -float Ocean::getWaveHeight(float x, float z, float time) const { - float totalHeight = 0.0f; - for (const auto& wave : gerstnerWaves) { - totalHeight += getGerstnerWaveHeight(wave, x, z, time); - } - return totalHeight; -} - -float Ocean::getGerstnerWaveHeight(const GerstnerWave& wave, float x, float z, float time) const { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - float waveHeightValue = periodicAmplitude * sin(k * dotProduct - w * time + wave.phase); - - if (fabs(x) < 0.5f && fabs(z) < 0.5f) { - //std::cout << " getGerstnerWaveHeight - time: " << time << ", periodicAmplitude: " << periodicAmplitude << ", waveHeightValue: " << waveHeightValue << std::endl; - } - - return waveHeightValue; -} - -glm::vec3 Ocean::getGerstnerWaveDisplacement(const GerstnerWave& wave, float x, float z, float time) const { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float cosTerm = cos(k * dotProduct - w * time + wave.phase); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - return glm::vec3(wave.direction.x * periodicAmplitude * cosTerm, - 0.0f, - wave.direction.y * periodicAmplitude * cosTerm); -} - -glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { - glm::vec3 tangentX = glm::vec3(1.0f, 0.0f, 0.0f); - glm::vec3 tangentZ = glm::vec3(0.0f, 0.0f, 1.0f); - - for (const auto& wave : gerstnerWaves) { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float sinTerm = sin(k * dotProduct - w * time + wave.phase); - float cosTerm = cos(k * dotProduct - w * time + wave.phase); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - float modulatedAmplitude = periodicAmplitude; - - // Calculate tangent vectors for EACH wave component and ACCUMULATE them directly - tangentX += glm::vec3( - -modulatedAmplitude * wave.direction.x * wave.direction.x * k * sinTerm, // dx_dx - modulatedAmplitude * wave.direction.x * k * cosTerm, // dy_dx - -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm // dz_dx - ); - - tangentZ += glm::vec3( - -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm, // dx_dz - modulatedAmplitude * wave.direction.y * k * cosTerm, // dy_dz - -modulatedAmplitude * wave.direction.y * wave.direction.y * k * sinTerm // dz_dz - ); - } - - return glm::normalize(glm::cross(tangentZ, tangentX)); -} -void Ocean::setGridSize(int newGridSize) -{ - gridSize = newGridSize; - generateGrid(); // Re-generate the grid with the new size - - std::vector updatedVertices = vertices; // Create a copy to update - std::vector updatedNormals(vertices.size()); // Vector to store updated normals - - updateVertices(&updatedVertices, &updatedNormals, time); - - updateBuffers(updatedVertices, updatedNormals); - //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) -} - -GLuint Ocean::getVAO() const -{ - return vaoID; -} - -GLuint Ocean::getIndexCount() const -{ - return indexCount; -} - -int Ocean::getGridIndex(int x, int z) const { - return x * gridSize + z; -} + // No dynamic memory allocation in this simple version + // Release OpenGL resources (VBOs, IBO, VAO) + glDeleteBuffers(1, &vertexBufferID); + glDeleteBuffers(1, &normalBufferID); + glDeleteBuffers(1, &texCoordBufferID); + glDeleteBuffers(1, &indexBufferID); + glDeleteVertexArrays(1, &vaoID); + vertexBufferID = 0; + normalBufferID = 0; + texCoordBufferID = 0; + indexBufferID = 0; + vaoID = 0; +} \ No newline at end of file diff --git a/linux/src/utils.cpp b/linux/src/utils.cpp index 461f980..03a6b66 100644 --- a/linux/src/utils.cpp +++ b/linux/src/utils.cpp @@ -69,4 +69,25 @@ float perlinNoise(float x, float y) { frequency *= 2.0f; // Increase frequency for each octave } return value / maxAmplitude; // Normalize to [0, 1] range -} \ No newline at end of file +} + +void convert_vec3_to_float_array(const std::vector& src, float * dst) { + // Ensure dst is the correct size (numVertices * 3) - should be handled by resize in constructor + size_t numVertices = src.size(); + + for (size_t i = 0; i < numVertices; ++i) { + dst[i * 3 + 0] = src[i].x; + dst[i * 3 + 1] = src[i].y; + dst[i * 3 + 2] = src[i].z; + } +} + +void convert_float_array_to_vec3(float * src, std::vector& dst) { +size_t numVertices = dst.size(); // Assume dst has correct size already + + for (size_t i = 0; i < numVertices; ++i) { + dst[i].x = src[i * 3 + 0]; + dst[i].y = src[i * 3 + 1]; + dst[i].z = src[i * 3 + 2]; + } +} diff --git a/windows/include/Ocean.h b/windows/include/Ocean.h index dfd8b36..469d0ab 100644 --- a/windows/include/Ocean.h +++ b/windows/include/Ocean.h @@ -79,8 +79,8 @@ private: void generateGrid(); void createBuffers(); // Create and populate VBOs and IBO void updateBuffers(const std::vector& updatedVertices, const std::vector& updatedNormals); // Update VBO data - void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time); // Update vertex Y positions based on wave function - + //void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time); // Update vertex Y positions based on wave function + void updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time); #if ASM_TYPE==CLEAR_ASM #else void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time); // Modified signature for C++ as well (for consistency or if you want to use float arrays in C++ SIMD too) diff --git a/windows/include/utils.h b/windows/include/utils.h index 10b490f..c5dfb7f 100644 --- a/windows/include/utils.h +++ b/windows/include/utils.h @@ -5,11 +5,12 @@ #include #include #include - +#include // Helper function to check for OpenGL errors and print a message void checkGLError(const char* operation); float perlinNoise(float x, float y); // Placeholder declaration - +void convert_vec3_to_float_array(const std::vector& src, float * dst); +void convert_float_array_to_vec3(float * src, std::vector& dst); uint64_t rdtsc(); #endif // UTILS_H \ No newline at end of file diff --git a/windows/src/Ocean.cpp b/windows/src/Ocean.cpp index d42ce27..dd4c0d0 100644 --- a/windows/src/Ocean.cpp +++ b/windows/src/Ocean.cpp @@ -17,12 +17,12 @@ #if ASM_TYPE==CLEAR_ASM // Assembly version declaration (signature changed to float arrays) - extern "C" void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time); + extern "C" void updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time); #else // C++ implementation of SIMD version (now also taking float arrays for consistency) - void Ocean::updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float time) + void Ocean::updateVertices_simd(float* updatedVertices_array, float* updatedNormals_array, size_t numVertices, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) { // Placeholder C++ implementation using float arrays //for (size_t i = 0; i < numVertices; ++i) { @@ -46,10 +46,7 @@ Ocean::Ocean(int gridSize) : time(0.0f),gridSize(gridSize), gridSpacing(1.0f), //gerstnerWaves.push_back({0.5f, 1.2f, 2.0f, glm::normalize(glm::vec2(0.9f, 0.8f)), 0.0f}); } -Ocean::~Ocean() -{ - cleanup(); // Call cleanup to release OpenGL resources -} + bool Ocean::init() { @@ -59,29 +56,6 @@ bool Ocean::init() return true; } -void Ocean::cleanup() -{ - // No dynamic memory allocation in this simple version - // Release OpenGL resources (VBOs, IBO, VAO) - glDeleteBuffers(1, &vertexBufferID); - glDeleteBuffers(1, &normalBufferID); - glDeleteBuffers(1, &texCoordBufferID); - glDeleteBuffers(1, &indexBufferID); - glDeleteVertexArrays(1, &vaoID); - vertexBufferID = 0; - normalBufferID = 0; - texCoordBufferID = 0; - indexBufferID = 0; - vaoID = 0; -} - -void add_sse(float* a, float* b, float* result) { - __m128 vec1 = _mm_loadu_ps(a); // Load 4 floats from a - __m128 vec2 = _mm_loadu_ps(b); // Load 4 floats from b - __m128 sum = _mm_add_ps(vec1, vec2); // Perform vector addition - _mm_storeu_ps(result, sum); // Store result -} - void Ocean::update(float deltaTime) { @@ -97,49 +71,40 @@ void Ocean::update(float deltaTime) size_t numVertices = vertices.size(); size_t floatArraySize = numVertices * 3; - float* updatedVertices_array = new float[floatArraySize]; - float* updatedNormals_array = new float[floatArraySize]; - float* updatedVertices_simd_array = new float[floatArraySize]; // Array for SIMD function - float* updatedNormals_simd_array = new float[floatArraySize]; // Array for SIMD function - - // Convert vector of vec3 to float array (for both normal and simd versions) - for (size_t i = 0; i < numVertices; ++i) { - updatedVertices_array[i * 3 + 0] = updatedVertices_vec[i].x; - updatedVertices_array[i * 3 + 1] = updatedVertices_vec[i].y; - updatedVertices_array[i * 3 + 2] = updatedVertices_vec[i].z; - - updatedNormals_array[i * 3 + 0] = updatedNormals_vec[i].x; // Normals init - adjust as needed - updatedNormals_array[i * 3 + 1] = updatedNormals_vec[i].y; - updatedNormals_array[i * 3 + 2] = updatedNormals_vec[i].z; - - updatedVertices_simd_array[i * 3 + 0] = updatedVertices_simd_vec[i].x; // SIMD version init - updatedVertices_simd_array[i * 3 + 1] = updatedVertices_simd_vec[i].y; - updatedVertices_simd_array[i * 3 + 2] = updatedVertices_simd_vec[i].z; - - updatedNormals_simd_array[i * 3 + 0] = updatedNormals_simd_vec[i].x; // SIMD normals init - updatedNormals_simd_array[i * 3 + 1] = updatedNormals_simd_vec[i].y; - updatedNormals_simd_array[i * 3 + 2] = updatedNormals_simd_vec[i].z; - - } + //Reference C++ part auto start_time = std::chrono::high_resolution_clock::now(); uint64_t start = rdtsc(); // --- Call C++ version for comparison (using vector) --- - updateVertices(&updatedVertices_vec, &updatedNormals_vec, time); - + //updateVertices(&updatedVertices_vec, &updatedNormals_vec, time); + updateVertices(&updatedVertices_vec, &updatedNormals_vec, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + updateBuffers(updatedVertices_vec, updatedNormals_vec); // Use vectors for updateBuffers uint64_t end = rdtsc(); - auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end_time - start_time); std::cout << "Ocean::update took " << duration.count() << "ns " << "CPU cycles: " << (end - start) << std::endl; + //End Reference C++ part + + float* updatedVertices_simd_array = new float[floatArraySize]; // Array for SIMD function + float* updatedNormals_simd_array = new float[floatArraySize]; // Array for SIMD function + + //Start SIMD part + // Convert vector of vec3 to float array (for both normal and simd versions) + + convert_vec3_to_float_array(updatedVertices_simd_vec, updatedVertices_simd_array); // Convert base vertices + convert_vec3_to_float_array(updatedNormals_simd_vec, updatedNormals_simd_array); // Convert base vertices start_time = std::chrono::high_resolution_clock::now(); start = rdtsc(); - // --- Call SIMD version (now taking float arrays) --- - updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, time); + // READ + // Extend function parameters by passing a reference to a structure with + // Gerstner wave properties, allowing customization through your own implementation. + updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + + end = rdtsc(); end_time = std::chrono::high_resolution_clock::now(); @@ -152,22 +117,23 @@ void Ocean::update(float deltaTime) std::vector updatedVertices_vec_from_array(numVertices); std::vector updatedNormals_vec_from_array(numVertices); - for (size_t i = 0; i < numVertices; ++i) { - updatedVertices_vec_from_array[i].x = updatedVertices_simd_array[i * 3 + 0]; - updatedVertices_vec_from_array[i].y = updatedVertices_simd_array[i * 3 + 1]; - updatedVertices_vec_from_array[i].z = updatedVertices_simd_array[i * 3 + 2]; - - updatedNormals_vec_from_array[i].x = updatedNormals_simd_array[i * 3 + 0]; - updatedNormals_vec_from_array[i].y = updatedNormals_simd_array[i * 3 + 1]; - updatedNormals_vec_from_array[i].z = updatedNormals_simd_array[i * 3 + 2]; - } + convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array); + convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array); - updateBuffers(updatedVertices_vec_from_array, updatedNormals_vec_from_array); // Use vectors for updateBuffers + // READ + + // THIS FUNCTION UPDATES THE VERTICES AND NORMALS. If updateVertices_simd doesn't work, + // the surface will remain flat. Uncomment this after implementing the update logic. + + //updateBuffers(updatedVertices_vec_from_array, updatedNormals_vec_from_array); // Use vectors for updateBuffers + + //End SIMD part // --- Deallocate float arrays --- - + delete[] updatedVertices_simd_array; + delete[] updatedNormals_simd_array; } @@ -193,6 +159,135 @@ void Ocean::generateGrid() } } + + +void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) +{ + + for (int x = 0; x < _grid_size; ++x) + { + for (int z = 0; z < _grid_size; ++z) + { + + glm::vec3 &vertex = (*updatedVertices)[x * _grid_size + z]; // Use reference to modify directly + float originalX = originalWorldX_[x * _grid_size + z]; + float originalZ = originalWorldZ_[x * _grid_size + z]; + vertex.y = getWaveHeight(vertex.x, vertex.z, time); + + (*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords + } + } +} + + + +float Ocean::getWaveHeight(float x, float z, float time) const { + float totalHeight = 0.0f; + for (const auto& wave : gerstnerWaves) { + totalHeight += getGerstnerWaveHeight(wave, x, z, time); + } + return totalHeight; +} + +float Ocean::getGerstnerWaveHeight(const GerstnerWave& wave, float x, float z, float time) const { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + float waveHeightValue = periodicAmplitude * sin(k * dotProduct - w * time + wave.phase); + + if (fabs(x) < 0.5f && fabs(z) < 0.5f) { + //std::cout << " getGerstnerWaveHeight - time: " << time << ", periodicAmplitude: " << periodicAmplitude << ", waveHeightValue: " << waveHeightValue << std::endl; + } + + return waveHeightValue; +} + +glm::vec3 Ocean::getGerstnerWaveDisplacement(const GerstnerWave& wave, float x, float z, float time) const { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float cosTerm = cos(k * dotProduct - w * time + wave.phase); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + return glm::vec3(wave.direction.x * periodicAmplitude * cosTerm, + 0.0f, + wave.direction.y * periodicAmplitude * cosTerm); +} + +glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { + glm::vec3 tangentX = glm::vec3(1.0f, 0.0f, 0.0f); + glm::vec3 tangentZ = glm::vec3(0.0f, 0.0f, 1.0f); + + for (const auto& wave : gerstnerWaves) { + float k = 2.0f * glm::pi() / wave.wavelength; + float w = wave.speed * k; + float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); + float sinTerm = sin(k * dotProduct - w * time + wave.phase); + float cosTerm = cos(k * dotProduct - w * time + wave.phase); + float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); + float modulatedAmplitude = periodicAmplitude; + + // Calculate tangent vectors for EACH wave component and ACCUMULATE them directly + tangentX += glm::vec3( + -modulatedAmplitude * wave.direction.x * wave.direction.x * k * sinTerm, // dx_dx + modulatedAmplitude * wave.direction.x * k * cosTerm, // dy_dx + -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm // dz_dx + ); + + tangentZ += glm::vec3( + -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm, // dx_dz + modulatedAmplitude * wave.direction.y * k * cosTerm, // dy_dz + -modulatedAmplitude * wave.direction.y * wave.direction.y * k * sinTerm // dz_dz + ); + } + + return glm::normalize(glm::cross(tangentZ, tangentX)); +} + + +void Ocean::updateBuffers(const std::vector &updatedVertices, const std::vector &updatedNormals) +{ + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); + glBufferSubData(GL_ARRAY_BUFFER, 0, updatedVertices.size() * sizeof(glm::vec3), updatedVertices.data()); // Update vertex positions + + glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); + glBufferSubData(GL_ARRAY_BUFFER, 0, updatedNormals.size() * sizeof(glm::vec3), updatedNormals.data()); // Update normals +} + +glm::vec3 Ocean::getVertex(int x, int z) const +{ + return vertices[x * gridSize + z]; +} + + +void Ocean::setGridSize(int newGridSize) +{ + gridSize = newGridSize; + generateGrid(); // Re-generate the grid with the new size + + std::vector updatedVertices = vertices; // Create a copy to update + std::vector updatedNormals(vertices.size()); // Vector to store updated normals + + updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time); + + updateBuffers(updatedVertices, updatedNormals); + //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) +} + +GLuint Ocean::getVAO() const +{ + return vaoID; +} + +GLuint Ocean::getIndexCount() const +{ + return indexCount; +} + +int Ocean::getGridIndex(int x, int z) const { + return x * gridSize + z; +} + void Ocean::createBuffers() { glGenVertexArrays(1, &vaoID); @@ -278,126 +373,23 @@ void Ocean::createBuffers() indexCount = indices.size(); // Store index count for rendering } -void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time) +Ocean::~Ocean() { - - for (int x = 0; x < gridSize; ++x) - { - for (int z = 0; z < gridSize; ++z) - { - - glm::vec3 &vertex = vertices[x * gridSize + z]; - float originalX = originalWorldX[x * gridSize + z]; - float originalZ = originalWorldZ[x * gridSize + z]; - vertex.y = getWaveHeight(vertex.x, vertex.z, time); - - (*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords - } - } - //vertices = updatedVertices; // Assign the updated vertices back - //updateBuffers(updatedVertices, updatedNormals); + cleanup(); // Call cleanup to release OpenGL resources } -void Ocean::updateBuffers(const std::vector &updatedVertices, const std::vector &updatedNormals) +void Ocean::cleanup() { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - glBufferSubData(GL_ARRAY_BUFFER, 0, updatedVertices.size() * sizeof(glm::vec3), updatedVertices.data()); // Update vertex positions - - glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); - glBufferSubData(GL_ARRAY_BUFFER, 0, updatedNormals.size() * sizeof(glm::vec3), updatedNormals.data()); // Update normals -} - -glm::vec3 Ocean::getVertex(int x, int z) const -{ - return vertices[x * gridSize + z]; -} - -float Ocean::getWaveHeight(float x, float z, float time) const { - float totalHeight = 0.0f; - for (const auto& wave : gerstnerWaves) { - totalHeight += getGerstnerWaveHeight(wave, x, z, time); - } - return totalHeight; -} - -float Ocean::getGerstnerWaveHeight(const GerstnerWave& wave, float x, float z, float time) const { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - float waveHeightValue = periodicAmplitude * sin(k * dotProduct - w * time + wave.phase); - - if (fabs(x) < 0.5f && fabs(z) < 0.5f) { - //std::cout << " getGerstnerWaveHeight - time: " << time << ", periodicAmplitude: " << periodicAmplitude << ", waveHeightValue: " << waveHeightValue << std::endl; - } - - return waveHeightValue; -} - -glm::vec3 Ocean::getGerstnerWaveDisplacement(const GerstnerWave& wave, float x, float z, float time) const { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float cosTerm = cos(k * dotProduct - w * time + wave.phase); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - return glm::vec3(wave.direction.x * periodicAmplitude * cosTerm, - 0.0f, - wave.direction.y * periodicAmplitude * cosTerm); -} - -glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { - glm::vec3 tangentX = glm::vec3(1.0f, 0.0f, 0.0f); - glm::vec3 tangentZ = glm::vec3(0.0f, 0.0f, 1.0f); - - for (const auto& wave : gerstnerWaves) { - float k = 2.0f * glm::pi() / wave.wavelength; - float w = wave.speed * k; - float dotProduct = glm::dot(wave.direction, glm::vec2(x, z)); - float sinTerm = sin(k * dotProduct - w * time + wave.phase); - float cosTerm = cos(k * dotProduct - w * time + wave.phase); - float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi() * time / wave.wavelength)); - float modulatedAmplitude = periodicAmplitude; - - // Calculate tangent vectors for EACH wave component and ACCUMULATE them directly - tangentX += glm::vec3( - -modulatedAmplitude * wave.direction.x * wave.direction.x * k * sinTerm, // dx_dx - modulatedAmplitude * wave.direction.x * k * cosTerm, // dy_dx - -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm // dz_dx - ); - - tangentZ += glm::vec3( - -modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm, // dx_dz - modulatedAmplitude * wave.direction.y * k * cosTerm, // dy_dz - -modulatedAmplitude * wave.direction.y * wave.direction.y * k * sinTerm // dz_dz - ); - } - - return glm::normalize(glm::cross(tangentZ, tangentX)); -} -void Ocean::setGridSize(int newGridSize) -{ - gridSize = newGridSize; - generateGrid(); // Re-generate the grid with the new size - - std::vector updatedVertices = vertices; // Create a copy to update - std::vector updatedNormals(vertices.size()); // Vector to store updated normals - - updateVertices(&updatedVertices, &updatedNormals, time); - - updateBuffers(updatedVertices, updatedNormals); - //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) -} - -GLuint Ocean::getVAO() const -{ - return vaoID; -} - -GLuint Ocean::getIndexCount() const -{ - return indexCount; -} - -int Ocean::getGridIndex(int x, int z) const { - return x * gridSize + z; -} + // No dynamic memory allocation in this simple version + // Release OpenGL resources (VBOs, IBO, VAO) + glDeleteBuffers(1, &vertexBufferID); + glDeleteBuffers(1, &normalBufferID); + glDeleteBuffers(1, &texCoordBufferID); + glDeleteBuffers(1, &indexBufferID); + glDeleteVertexArrays(1, &vaoID); + vertexBufferID = 0; + normalBufferID = 0; + texCoordBufferID = 0; + indexBufferID = 0; + vaoID = 0; +} \ No newline at end of file diff --git a/windows/src/utils.cpp b/windows/src/utils.cpp index 461f980..03a6b66 100644 --- a/windows/src/utils.cpp +++ b/windows/src/utils.cpp @@ -69,4 +69,25 @@ float perlinNoise(float x, float y) { frequency *= 2.0f; // Increase frequency for each octave } return value / maxAmplitude; // Normalize to [0, 1] range -} \ No newline at end of file +} + +void convert_vec3_to_float_array(const std::vector& src, float * dst) { + // Ensure dst is the correct size (numVertices * 3) - should be handled by resize in constructor + size_t numVertices = src.size(); + + for (size_t i = 0; i < numVertices; ++i) { + dst[i * 3 + 0] = src[i].x; + dst[i * 3 + 1] = src[i].y; + dst[i * 3 + 2] = src[i].z; + } +} + +void convert_float_array_to_vec3(float * src, std::vector& dst) { +size_t numVertices = dst.size(); // Assume dst has correct size already + + for (size_t i = 0; i < numVertices; ++i) { + dst[i].x = src[i * 3 + 0]; + dst[i].y = src[i * 3 + 1]; + dst[i].z = src[i * 3 + 2]; + } +}