Fixed parameter passing logic

master
Tomáš Goldmann 2 weeks ago
parent 01e4ab5f31
commit 373b6f44f8

@ -22,6 +22,9 @@ struct GerstnerWave {
}; };
``` ```
Tuto strukturu si můžete libovolně upravit a předat funkci například jako pole strutkur.
## Dokumentace ## Dokumentace
V dokumentaci **podrobně popište** postup optimalizace. Pro lepší přehlednost můžete využít: 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 ### 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 ### Linux

@ -58,6 +58,11 @@
"streambuf": "cpp", "streambuf": "cpp",
"thread": "cpp", "thread": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp" "typeinfo": "cpp",
"forward_list": "cpp",
"list": "cpp",
"unordered_set": "cpp",
"optional": "cpp",
"typeindex": "cpp"
} }
} }

@ -47,6 +47,7 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.s
# Clean target # Clean target
clean: clean:
rm $(BUILD_DIR)/* rm $(BUILD_DIR)/*
rm $(EXECUTABLE_PATH)
# Debug build target # Debug build target
debug: CXXFLAGS += -DDEBUG -g debug: CXXFLAGS += -DDEBUG -g

@ -79,8 +79,8 @@ private:
void generateGrid(); void generateGrid();
void createBuffers(); // Create and populate VBOs and IBO void createBuffers(); // Create and populate VBOs and IBO
void updateBuffers(const std::vector<glm::vec3>& updatedVertices, const std::vector<glm::vec3>& updatedNormals); // Update VBO data void updateBuffers(const std::vector<glm::vec3>& updatedVertices, const std::vector<glm::vec3>& updatedNormals); // Update VBO data
void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float time); // Update vertex Y positions based on wave function //void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float time); // Update vertex Y positions based on wave function
void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time);
#if ASM_TYPE==CLEAR_ASM #if ASM_TYPE==CLEAR_ASM
#else #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) 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)

@ -5,11 +5,12 @@
#include <iostream> #include <iostream>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <x86intrin.h> #include <x86intrin.h>
#include <vector>
// Helper function to check for OpenGL errors and print a message // Helper function to check for OpenGL errors and print a message
void checkGLError(const char* operation); void checkGLError(const char* operation);
float perlinNoise(float x, float y); // Placeholder declaration float perlinNoise(float x, float y); // Placeholder declaration
void convert_vec3_to_float_array(const std::vector<glm::vec3>& src, float * dst);
void convert_float_array_to_vec3(float * src, std::vector<glm::vec3>& dst);
uint64_t rdtsc(); uint64_t rdtsc();
#endif // UTILS_H #endif // UTILS_H

@ -17,12 +17,12 @@
#if ASM_TYPE==CLEAR_ASM #if ASM_TYPE==CLEAR_ASM
// Assembly version declaration (signature changed to float arrays) // 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 #else
// C++ implementation of SIMD version (now also taking float arrays for consistency) // 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 // Placeholder C++ implementation using float arrays
//for (size_t i = 0; i < numVertices; ++i) { //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}); //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() bool Ocean::init()
{ {
@ -59,29 +56,6 @@ bool Ocean::init()
return true; 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) void Ocean::update(float deltaTime)
{ {
@ -97,49 +71,40 @@ void Ocean::update(float deltaTime)
size_t numVertices = vertices.size(); size_t numVertices = vertices.size();
size_t floatArraySize = numVertices * 3; 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) //Reference C++ part
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;
}
auto start_time = std::chrono::high_resolution_clock::now(); auto start_time = std::chrono::high_resolution_clock::now();
uint64_t start = rdtsc(); uint64_t start = rdtsc();
// --- Call C++ version for comparison (using vector) --- // --- 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(); uint64_t end = rdtsc();
auto end_time = std::chrono::high_resolution_clock::now(); auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time); auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
std::cout << "Ocean::update took " << duration.count() << "ns " << "CPU cycles: " << (end - start) << std::endl; 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_time = std::chrono::high_resolution_clock::now();
start = rdtsc(); start = rdtsc();
// --- Call SIMD version (now taking float arrays) --- // READ
updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, time); // 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 = rdtsc();
end_time = std::chrono::high_resolution_clock::now(); end_time = std::chrono::high_resolution_clock::now();
@ -152,22 +117,23 @@ void Ocean::update(float deltaTime)
std::vector<glm::vec3> updatedVertices_vec_from_array(numVertices); std::vector<glm::vec3> updatedVertices_vec_from_array(numVertices);
std::vector<glm::vec3> updatedNormals_vec_from_array(numVertices); std::vector<glm::vec3> updatedNormals_vec_from_array(numVertices);
for (size_t i = 0; i < numVertices; ++i) { convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array);
updatedVertices_vec_from_array[i].x = updatedVertices_simd_array[i * 3 + 0]; convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array);
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];
}
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 void Ocean::updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time)
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<glm::vec3> 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<glm::vec2> texCoords(vertices.size());
for (int x = 0; x < gridSize; ++x)
{
for (int z = 0; z < gridSize; ++z)
{
float texU = static_cast<float>(x) / 70.0f;
float texV = static_cast<float>(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<unsigned int> 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<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, 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]; glm::vec3 &vertex = (*updatedVertices)[x * _grid_size + z]; // Use reference to modify directly
float originalX = originalWorldX[x * gridSize + z]; float originalX = originalWorldX_[x * _grid_size + z];
float originalZ = originalWorldZ[x * gridSize + z]; float originalZ = originalWorldZ_[x * _grid_size + z];
vertex.y = getWaveHeight(vertex.x, vertex.z, time); vertex.y = getWaveHeight(vertex.x, vertex.z, time);
(*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords (*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<glm::vec3> &updatedVertices, const std::vector<glm::vec3> &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 Ocean::getWaveHeight(float x, float z, float time) const {
float totalHeight = 0.0f; 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)); return glm::normalize(glm::cross(tangentZ, tangentX));
} }
void Ocean::updateBuffers(const std::vector<glm::vec3> &updatedVertices, const std::vector<glm::vec3> &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) void Ocean::setGridSize(int newGridSize)
{ {
gridSize = newGridSize; gridSize = newGridSize;
@ -382,7 +268,7 @@ void Ocean::setGridSize(int newGridSize)
std::vector<glm::vec3> updatedVertices = vertices; // Create a copy to update std::vector<glm::vec3> updatedVertices = vertices; // Create a copy to update
std::vector<glm::vec3> updatedNormals(vertices.size()); // Vector to store updated normals std::vector<glm::vec3> updatedNormals(vertices.size()); // Vector to store updated normals
updateVertices(&updatedVertices, &updatedNormals, time); updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time);
updateBuffers(updatedVertices, updatedNormals); updateBuffers(updatedVertices, updatedNormals);
//updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) //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 { int Ocean::getGridIndex(int x, int z) const {
return x * gridSize + z; 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<glm::vec3> 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<glm::vec2> texCoords(vertices.size());
for (int x = 0; x < gridSize; ++x)
{
for (int z = 0; z < gridSize; ++z)
{
float texU = static_cast<float>(x) / 70.0f;
float texV = static_cast<float>(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<unsigned int> 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;
}

@ -70,3 +70,24 @@ float perlinNoise(float x, float y) {
} }
return value / maxAmplitude; // Normalize to [0, 1] range return value / maxAmplitude; // Normalize to [0, 1] range
} }
void convert_vec3_to_float_array(const std::vector<glm::vec3>& 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<glm::vec3>& 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];
}
}

@ -79,8 +79,8 @@ private:
void generateGrid(); void generateGrid();
void createBuffers(); // Create and populate VBOs and IBO void createBuffers(); // Create and populate VBOs and IBO
void updateBuffers(const std::vector<glm::vec3>& updatedVertices, const std::vector<glm::vec3>& updatedNormals); // Update VBO data void updateBuffers(const std::vector<glm::vec3>& updatedVertices, const std::vector<glm::vec3>& updatedNormals); // Update VBO data
void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float time); // Update vertex Y positions based on wave function //void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float time); // Update vertex Y positions based on wave function
void updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time);
#if ASM_TYPE==CLEAR_ASM #if ASM_TYPE==CLEAR_ASM
#else #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) 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)

@ -5,11 +5,12 @@
#include <iostream> #include <iostream>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <x86intrin.h> #include <x86intrin.h>
#include <vector>
// Helper function to check for OpenGL errors and print a message // Helper function to check for OpenGL errors and print a message
void checkGLError(const char* operation); void checkGLError(const char* operation);
float perlinNoise(float x, float y); // Placeholder declaration float perlinNoise(float x, float y); // Placeholder declaration
void convert_vec3_to_float_array(const std::vector<glm::vec3>& src, float * dst);
void convert_float_array_to_vec3(float * src, std::vector<glm::vec3>& dst);
uint64_t rdtsc(); uint64_t rdtsc();
#endif // UTILS_H #endif // UTILS_H

@ -17,12 +17,12 @@
#if ASM_TYPE==CLEAR_ASM #if ASM_TYPE==CLEAR_ASM
// Assembly version declaration (signature changed to float arrays) // 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 #else
// C++ implementation of SIMD version (now also taking float arrays for consistency) // 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 // Placeholder C++ implementation using float arrays
//for (size_t i = 0; i < numVertices; ++i) { //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}); //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() bool Ocean::init()
{ {
@ -59,29 +56,6 @@ bool Ocean::init()
return true; 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) void Ocean::update(float deltaTime)
{ {
@ -97,49 +71,40 @@ void Ocean::update(float deltaTime)
size_t numVertices = vertices.size(); size_t numVertices = vertices.size();
size_t floatArraySize = numVertices * 3; 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) //Reference C++ part
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;
}
auto start_time = std::chrono::high_resolution_clock::now(); auto start_time = std::chrono::high_resolution_clock::now();
uint64_t start = rdtsc(); uint64_t start = rdtsc();
// --- Call C++ version for comparison (using vector) --- // --- 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(); uint64_t end = rdtsc();
auto end_time = std::chrono::high_resolution_clock::now(); auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time); auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
std::cout << "Ocean::update took " << duration.count() << "ns " << "CPU cycles: " << (end - start) << std::endl; 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_time = std::chrono::high_resolution_clock::now();
start = rdtsc(); start = rdtsc();
// --- Call SIMD version (now taking float arrays) --- // READ
updateVertices_simd(updatedVertices_simd_array, updatedNormals_simd_array, numVertices, time); // 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 = rdtsc();
end_time = std::chrono::high_resolution_clock::now(); end_time = std::chrono::high_resolution_clock::now();
@ -152,22 +117,23 @@ void Ocean::update(float deltaTime)
std::vector<glm::vec3> updatedVertices_vec_from_array(numVertices); std::vector<glm::vec3> updatedVertices_vec_from_array(numVertices);
std::vector<glm::vec3> updatedNormals_vec_from_array(numVertices); std::vector<glm::vec3> updatedNormals_vec_from_array(numVertices);
for (size_t i = 0; i < numVertices; ++i) { convert_float_array_to_vec3(updatedVertices_simd_array, updatedVertices_vec_from_array);
updatedVertices_vec_from_array[i].x = updatedVertices_simd_array[i * 3 + 0]; convert_float_array_to_vec3(updatedNormals_simd_array, updatedNormals_vec_from_array);
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];
}
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 void Ocean::updateVertices(std::vector<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, float * originalWorldX_, float * originalWorldZ_, int _grid_size, float time)
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<glm::vec3> 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<glm::vec2> texCoords(vertices.size());
for (int x = 0; x < gridSize; ++x)
{
for (int z = 0; z < gridSize; ++z)
{
float texU = static_cast<float>(x) / 70.0f;
float texV = static_cast<float>(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<unsigned int> 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<glm::vec3> * updatedVertices, std::vector<glm::vec3> * updatedNormals, 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]; glm::vec3 &vertex = (*updatedVertices)[x * _grid_size + z]; // Use reference to modify directly
float originalX = originalWorldX[x * gridSize + z]; float originalX = originalWorldX_[x * _grid_size + z];
float originalZ = originalWorldZ[x * gridSize + z]; float originalZ = originalWorldZ_[x * _grid_size + z];
vertex.y = getWaveHeight(vertex.x, vertex.z, time); vertex.y = getWaveHeight(vertex.x, vertex.z, time);
(*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords (*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<glm::vec3> &updatedVertices, const std::vector<glm::vec3> &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 Ocean::getWaveHeight(float x, float z, float time) const {
float totalHeight = 0.0f; 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)); return glm::normalize(glm::cross(tangentZ, tangentX));
} }
void Ocean::updateBuffers(const std::vector<glm::vec3> &updatedVertices, const std::vector<glm::vec3> &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) void Ocean::setGridSize(int newGridSize)
{ {
gridSize = newGridSize; gridSize = newGridSize;
@ -382,7 +268,7 @@ void Ocean::setGridSize(int newGridSize)
std::vector<glm::vec3> updatedVertices = vertices; // Create a copy to update std::vector<glm::vec3> updatedVertices = vertices; // Create a copy to update
std::vector<glm::vec3> updatedNormals(vertices.size()); // Vector to store updated normals std::vector<glm::vec3> updatedNormals(vertices.size()); // Vector to store updated normals
updateVertices(&updatedVertices, &updatedNormals, time); updateVertices(&updatedVertices, &updatedNormals, originalWorldX.data(), originalWorldZ.data(), gridSize, time);
updateBuffers(updatedVertices, updatedNormals); updateBuffers(updatedVertices, updatedNormals);
//updateVertices(); // Re-update vertices based on waves (optional, if needed immediately) //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 { int Ocean::getGridIndex(int x, int z) const {
return x * gridSize + z; 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<glm::vec3> 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<glm::vec2> texCoords(vertices.size());
for (int x = 0; x < gridSize; ++x)
{
for (int z = 0; z < gridSize; ++z)
{
float texU = static_cast<float>(x) / 70.0f;
float texV = static_cast<float>(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<unsigned int> 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;
}

@ -70,3 +70,24 @@ float perlinNoise(float x, float y) {
} }
return value / maxAmplitude; // Normalize to [0, 1] range return value / maxAmplitude; // Normalize to [0, 1] range
} }
void convert_vec3_to_float_array(const std::vector<glm::vec3>& 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<glm::vec3>& 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];
}
}

Loading…
Cancel
Save