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]; + convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array); + convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array); - 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]; - } - 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. - // --- Deallocate float arrays --- + //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,124 +159,27 @@ void Ocean::generateGrid() } } -void Ocean::createBuffers() -{ - glGenVertexArrays(1, &vaoID); - checkGLError("glGenVertexArrays"); // Check after glGenVertexArrays - glBindVertexArray(vaoID); - checkGLError("glBindVertexArray"); // Check after glBindVertexArray - // Generate VBOs - glGenBuffers(1, &vertexBufferID); - checkGLError("glGenBuffers - vertexBufferID"); // Check after glGenBuffers - glGenBuffers(1, &normalBufferID); - checkGLError("glGenBuffers - normalBufferID"); // Check after glGenBuffers - glGenBuffers(1, &texCoordBufferID); - checkGLError("glGenBuffers - texCoordBufferID"); // Check after glGenBuffers - glGenBuffers(1, &indexBufferID); - checkGLError("glGenBuffers - indexBufferID"); // Check after glGenBuffers - // 1. Vertex Positions VBO - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - checkGLError("glBindBuffer - vertexBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_DYNAMIC_DRAW); - checkGLError("glBufferData - vertexBufferID"); // Check after glBufferData - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - vertexBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(0); - checkGLError("glEnableVertexAttribArray - location 0"); // Check after glEnableVertexAttribArray - - // 2. Vertex Normals VBO (initially flat normals - updated in updateVertices/updateBuffers) - std::vector normals(vertices.size(), glm::vec3(0.0f, 1.0f, 0.0f)); // Initialize with flat normals - glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); - checkGLError("glBindBuffer - normalBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_DYNAMIC_DRAW); - checkGLError("glBufferData - normalBufferID"); // Check after glBufferData - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - normalBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(1); - checkGLError("glEnableVertexAttribArray - location 1"); // Check after glEnableVertexAttribArray - - // 3. Texture Coordinates VBO - std::vector texCoords(vertices.size()); - for (int x = 0; x < gridSize; ++x) - { - for (int z = 0; z < gridSize; ++z) - { - float texU = static_cast(x) / 70.0f; - float texV = static_cast(z) / 70.0f; - texCoords[x * gridSize + z] = glm::vec2(texU, texV); - } - } - glBindBuffer(GL_ARRAY_BUFFER, texCoordBufferID); - checkGLError("glBindBuffer - texCoordBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW); - checkGLError("glBufferData - texCoordBufferID"); // Check after glBufferData - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - texCoordBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(2); - checkGLError("glEnableVertexAttribArray - location 2"); // Check after glEnableVertexAttribArray - - // 4. Index Buffer Object (IBO) for Quads - std::vector indices; - for (int x = 0; x < gridSize - 1; ++x) - { - for (int z = 0; z < gridSize - 1; ++z) - { - unsigned int v00 = x * gridSize + z; - unsigned int v10 = (x + 1) * gridSize + z; - unsigned int v11 = (x + 1) * gridSize + (z + 1); - unsigned int v01 = x * gridSize + (z + 1); - indices.insert(indices.end(), {v00, v10, v11, v01}); // Quad indices (counter-clockwise) - } - } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); - checkGLError("glBindBuffer - indexBufferID"); // Check after glBindBuffer - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); - checkGLError("glBufferData - indexBufferID"); // Check after glBufferData - - glBindVertexArray(0); // Unbind VAO - checkGLError("glBindVertexArray(0)"); // Check after unbinding VAO - glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO - Optional, VAO unbinding often unbinds VBOs - checkGLError("glBindBuffer(0) - ARRAY_BUFFER"); // Check after unbinding ARRAY_BUFFER - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind IBO - Optional, VAO unbinding often unbinds IBO - checkGLError("glBindBuffer(0) - ELEMENT_ARRAY_BUFFER"); // Check after unbinding ELEMENT_ARRAY_BUFFER - indexCount = indices.size(); // Store index count for rendering -} - -void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time) +void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) { - for (int x = 0; x < gridSize; ++x) + for (int x = 0; x < _grid_size; ++x) { - for (int z = 0; z < gridSize; ++z) + for (int z = 0; z < _grid_size; ++z) { - glm::vec3 &vertex = vertices[x * gridSize + z]; - float originalX = originalWorldX[x * gridSize + z]; - float originalZ = originalWorldZ[x * gridSize + 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 } } - //vertices = updatedVertices; // Assign the updated vertices back - //updateBuffers(updatedVertices, updatedNormals); } -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]; -} float Ocean::getWaveHeight(float x, float z, float time) const { float totalHeight = 0.0f; @@ -374,6 +243,23 @@ glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { 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; @@ -382,7 +268,7 @@ void Ocean::setGridSize(int newGridSize) std::vector updatedVertices = vertices; // Create a copy to update std::vector updatedNormals(vertices.size()); // Vector to store updated normals - updateVertices(&updatedVertices, &updatedNormals, time); + updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time); updateBuffers(updatedVertices, updatedNormals); //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) @@ -401,3 +287,109 @@ GLuint Ocean::getIndexCount() const int Ocean::getGridIndex(int x, int z) const { return x * gridSize + z; } + +void Ocean::createBuffers() +{ + glGenVertexArrays(1, &vaoID); + checkGLError("glGenVertexArrays"); // Check after glGenVertexArrays + glBindVertexArray(vaoID); + checkGLError("glBindVertexArray"); // Check after glBindVertexArray + + // Generate VBOs + glGenBuffers(1, &vertexBufferID); + checkGLError("glGenBuffers - vertexBufferID"); // Check after glGenBuffers + glGenBuffers(1, &normalBufferID); + checkGLError("glGenBuffers - normalBufferID"); // Check after glGenBuffers + glGenBuffers(1, &texCoordBufferID); + checkGLError("glGenBuffers - texCoordBufferID"); // Check after glGenBuffers + glGenBuffers(1, &indexBufferID); + checkGLError("glGenBuffers - indexBufferID"); // Check after glGenBuffers + + // 1. Vertex Positions VBO + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); + checkGLError("glBindBuffer - vertexBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_DYNAMIC_DRAW); + checkGLError("glBufferData - vertexBufferID"); // Check after glBufferData + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - vertexBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(0); + checkGLError("glEnableVertexAttribArray - location 0"); // Check after glEnableVertexAttribArray + + // 2. Vertex Normals VBO (initially flat normals - updated in updateVertices/updateBuffers) + std::vector normals(vertices.size(), glm::vec3(0.0f, 1.0f, 0.0f)); // Initialize with flat normals + glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); + checkGLError("glBindBuffer - normalBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_DYNAMIC_DRAW); + checkGLError("glBufferData - normalBufferID"); // Check after glBufferData + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - normalBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(1); + checkGLError("glEnableVertexAttribArray - location 1"); // Check after glEnableVertexAttribArray + + // 3. Texture Coordinates VBO + std::vector texCoords(vertices.size()); + for (int x = 0; x < gridSize; ++x) + { + for (int z = 0; z < gridSize; ++z) + { + float texU = static_cast(x) / 70.0f; + float texV = static_cast(z) / 70.0f; + texCoords[x * gridSize + z] = glm::vec2(texU, texV); + } + } + glBindBuffer(GL_ARRAY_BUFFER, texCoordBufferID); + checkGLError("glBindBuffer - texCoordBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW); + checkGLError("glBufferData - texCoordBufferID"); // Check after glBufferData + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - texCoordBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(2); + checkGLError("glEnableVertexAttribArray - location 2"); // Check after glEnableVertexAttribArray + + // 4. Index Buffer Object (IBO) for Quads + std::vector indices; + for (int x = 0; x < gridSize - 1; ++x) + { + for (int z = 0; z < gridSize - 1; ++z) + { + unsigned int v00 = x * gridSize + z; + unsigned int v10 = (x + 1) * gridSize + z; + unsigned int v11 = (x + 1) * gridSize + (z + 1); + unsigned int v01 = x * gridSize + (z + 1); + indices.insert(indices.end(), {v00, v10, v11, v01}); // Quad indices (counter-clockwise) + } + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); + checkGLError("glBindBuffer - indexBufferID"); // Check after glBindBuffer + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); + checkGLError("glBufferData - indexBufferID"); // Check after glBufferData + + glBindVertexArray(0); // Unbind VAO + checkGLError("glBindVertexArray(0)"); // Check after unbinding VAO + glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO - Optional, VAO unbinding often unbinds VBOs + checkGLError("glBindBuffer(0) - ARRAY_BUFFER"); // Check after unbinding ARRAY_BUFFER + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind IBO - Optional, VAO unbinding often unbinds IBO + checkGLError("glBindBuffer(0) - ELEMENT_ARRAY_BUFFER"); // Check after unbinding ELEMENT_ARRAY_BUFFER + indexCount = indices.size(); // Store index count for rendering +} + +Ocean::~Ocean() +{ + cleanup(); // Call cleanup to release OpenGL resources +} + +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; +} \ 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]; + convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array); + convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array); - 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]; - } - 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. - // --- Deallocate float arrays --- + //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,124 +159,27 @@ void Ocean::generateGrid() } } -void Ocean::createBuffers() -{ - glGenVertexArrays(1, &vaoID); - checkGLError("glGenVertexArrays"); // Check after glGenVertexArrays - glBindVertexArray(vaoID); - checkGLError("glBindVertexArray"); // Check after glBindVertexArray - // Generate VBOs - glGenBuffers(1, &vertexBufferID); - checkGLError("glGenBuffers - vertexBufferID"); // Check after glGenBuffers - glGenBuffers(1, &normalBufferID); - checkGLError("glGenBuffers - normalBufferID"); // Check after glGenBuffers - glGenBuffers(1, &texCoordBufferID); - checkGLError("glGenBuffers - texCoordBufferID"); // Check after glGenBuffers - glGenBuffers(1, &indexBufferID); - checkGLError("glGenBuffers - indexBufferID"); // Check after glGenBuffers - // 1. Vertex Positions VBO - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - checkGLError("glBindBuffer - vertexBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_DYNAMIC_DRAW); - checkGLError("glBufferData - vertexBufferID"); // Check after glBufferData - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - vertexBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(0); - checkGLError("glEnableVertexAttribArray - location 0"); // Check after glEnableVertexAttribArray - - // 2. Vertex Normals VBO (initially flat normals - updated in updateVertices/updateBuffers) - std::vector normals(vertices.size(), glm::vec3(0.0f, 1.0f, 0.0f)); // Initialize with flat normals - glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); - checkGLError("glBindBuffer - normalBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_DYNAMIC_DRAW); - checkGLError("glBufferData - normalBufferID"); // Check after glBufferData - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - normalBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(1); - checkGLError("glEnableVertexAttribArray - location 1"); // Check after glEnableVertexAttribArray - - // 3. Texture Coordinates VBO - std::vector texCoords(vertices.size()); - for (int x = 0; x < gridSize; ++x) - { - for (int z = 0; z < gridSize; ++z) - { - float texU = static_cast(x) / 70.0f; - float texV = static_cast(z) / 70.0f; - texCoords[x * gridSize + z] = glm::vec2(texU, texV); - } - } - glBindBuffer(GL_ARRAY_BUFFER, texCoordBufferID); - checkGLError("glBindBuffer - texCoordBufferID"); // Check after glBindBuffer - glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW); - checkGLError("glBufferData - texCoordBufferID"); // Check after glBufferData - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0); - checkGLError("glVertexAttribPointer - texCoordBufferID"); // Check after glVertexAttribPointer - glEnableVertexAttribArray(2); - checkGLError("glEnableVertexAttribArray - location 2"); // Check after glEnableVertexAttribArray - - // 4. Index Buffer Object (IBO) for Quads - std::vector indices; - for (int x = 0; x < gridSize - 1; ++x) - { - for (int z = 0; z < gridSize - 1; ++z) - { - unsigned int v00 = x * gridSize + z; - unsigned int v10 = (x + 1) * gridSize + z; - unsigned int v11 = (x + 1) * gridSize + (z + 1); - unsigned int v01 = x * gridSize + (z + 1); - indices.insert(indices.end(), {v00, v10, v11, v01}); // Quad indices (counter-clockwise) - } - } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); - checkGLError("glBindBuffer - indexBufferID"); // Check after glBindBuffer - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); - checkGLError("glBufferData - indexBufferID"); // Check after glBufferData - - glBindVertexArray(0); // Unbind VAO - checkGLError("glBindVertexArray(0)"); // Check after unbinding VAO - glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO - Optional, VAO unbinding often unbinds VBOs - checkGLError("glBindBuffer(0) - ARRAY_BUFFER"); // Check after unbinding ARRAY_BUFFER - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind IBO - Optional, VAO unbinding often unbinds IBO - checkGLError("glBindBuffer(0) - ELEMENT_ARRAY_BUFFER"); // Check after unbinding ELEMENT_ARRAY_BUFFER - indexCount = indices.size(); // Store index count for rendering -} - -void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float time) +void Ocean::updateVertices(std::vector * updatedVertices, std::vector * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time) { - for (int x = 0; x < gridSize; ++x) + for (int x = 0; x < _grid_size; ++x) { - for (int z = 0; z < gridSize; ++z) + for (int z = 0; z < _grid_size; ++z) { - glm::vec3 &vertex = vertices[x * gridSize + z]; - float originalX = originalWorldX[x * gridSize + z]; - float originalZ = originalWorldZ[x * gridSize + 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 } } - //vertices = updatedVertices; // Assign the updated vertices back - //updateBuffers(updatedVertices, updatedNormals); } -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]; -} float Ocean::getWaveHeight(float x, float z, float time) const { float totalHeight = 0.0f; @@ -374,6 +243,23 @@ glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const { 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; @@ -382,7 +268,7 @@ void Ocean::setGridSize(int newGridSize) std::vector updatedVertices = vertices; // Create a copy to update std::vector updatedNormals(vertices.size()); // Vector to store updated normals - updateVertices(&updatedVertices, &updatedNormals, time); + updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time); updateBuffers(updatedVertices, updatedNormals); //updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) @@ -401,3 +287,109 @@ GLuint Ocean::getIndexCount() const int Ocean::getGridIndex(int x, int z) const { return x * gridSize + z; } + +void Ocean::createBuffers() +{ + glGenVertexArrays(1, &vaoID); + checkGLError("glGenVertexArrays"); // Check after glGenVertexArrays + glBindVertexArray(vaoID); + checkGLError("glBindVertexArray"); // Check after glBindVertexArray + + // Generate VBOs + glGenBuffers(1, &vertexBufferID); + checkGLError("glGenBuffers - vertexBufferID"); // Check after glGenBuffers + glGenBuffers(1, &normalBufferID); + checkGLError("glGenBuffers - normalBufferID"); // Check after glGenBuffers + glGenBuffers(1, &texCoordBufferID); + checkGLError("glGenBuffers - texCoordBufferID"); // Check after glGenBuffers + glGenBuffers(1, &indexBufferID); + checkGLError("glGenBuffers - indexBufferID"); // Check after glGenBuffers + + // 1. Vertex Positions VBO + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); + checkGLError("glBindBuffer - vertexBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_DYNAMIC_DRAW); + checkGLError("glBufferData - vertexBufferID"); // Check after glBufferData + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - vertexBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(0); + checkGLError("glEnableVertexAttribArray - location 0"); // Check after glEnableVertexAttribArray + + // 2. Vertex Normals VBO (initially flat normals - updated in updateVertices/updateBuffers) + std::vector normals(vertices.size(), glm::vec3(0.0f, 1.0f, 0.0f)); // Initialize with flat normals + glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); + checkGLError("glBindBuffer - normalBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_DYNAMIC_DRAW); + checkGLError("glBufferData - normalBufferID"); // Check after glBufferData + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - normalBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(1); + checkGLError("glEnableVertexAttribArray - location 1"); // Check after glEnableVertexAttribArray + + // 3. Texture Coordinates VBO + std::vector texCoords(vertices.size()); + for (int x = 0; x < gridSize; ++x) + { + for (int z = 0; z < gridSize; ++z) + { + float texU = static_cast(x) / 70.0f; + float texV = static_cast(z) / 70.0f; + texCoords[x * gridSize + z] = glm::vec2(texU, texV); + } + } + glBindBuffer(GL_ARRAY_BUFFER, texCoordBufferID); + checkGLError("glBindBuffer - texCoordBufferID"); // Check after glBindBuffer + glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW); + checkGLError("glBufferData - texCoordBufferID"); // Check after glBufferData + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0); + checkGLError("glVertexAttribPointer - texCoordBufferID"); // Check after glVertexAttribPointer + glEnableVertexAttribArray(2); + checkGLError("glEnableVertexAttribArray - location 2"); // Check after glEnableVertexAttribArray + + // 4. Index Buffer Object (IBO) for Quads + std::vector indices; + for (int x = 0; x < gridSize - 1; ++x) + { + for (int z = 0; z < gridSize - 1; ++z) + { + unsigned int v00 = x * gridSize + z; + unsigned int v10 = (x + 1) * gridSize + z; + unsigned int v11 = (x + 1) * gridSize + (z + 1); + unsigned int v01 = x * gridSize + (z + 1); + indices.insert(indices.end(), {v00, v10, v11, v01}); // Quad indices (counter-clockwise) + } + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); + checkGLError("glBindBuffer - indexBufferID"); // Check after glBindBuffer + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW); + checkGLError("glBufferData - indexBufferID"); // Check after glBufferData + + glBindVertexArray(0); // Unbind VAO + checkGLError("glBindVertexArray(0)"); // Check after unbinding VAO + glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO - Optional, VAO unbinding often unbinds VBOs + checkGLError("glBindBuffer(0) - ARRAY_BUFFER"); // Check after unbinding ARRAY_BUFFER + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind IBO - Optional, VAO unbinding often unbinds IBO + checkGLError("glBindBuffer(0) - ELEMENT_ARRAY_BUFFER"); // Check after unbinding ELEMENT_ARRAY_BUFFER + indexCount = indices.size(); // Store index count for rendering +} + +Ocean::~Ocean() +{ + cleanup(); // Call cleanup to release OpenGL resources +} + +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; +} \ 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]; + } +}