@ -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 < std : : chrono : : nanoseconds > ( 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 < glm : : vec3 > updatedVertices_vec_from_array ( numVertices ) ;
std : : vector < glm : : vec3 > 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 < 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 )
void Ocean : : updateVertices ( std : : vector < glm : : vec3 > * updatedVertices , std : : vector < glm : : vec3 > * updatedNormals , float * originalWorldX_ , float * originalWorldZ_ , int _grid_size , float time )
{
for ( int x = 0 ; x < gridS ize; + + x )
for ( int x = 0 ; x < _grid_size ; + + x )
{
for ( int z = 0 ; z < gridS ize; + + z )
for ( int z = 0 ; z < _grid_size ; + + z )
{
glm : : vec3 & vertex = vertices [ x * gridSize + z ] ;
float originalX = originalWorldX [ x * gridS ize + z ] ;
float originalZ = originalWorldZ [ x * gridS ize + 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 < 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 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 < 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 )
{
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 > 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 < 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 ;
}