Init commit. Windows version was checked.
This commit is contained in:
215
windows/src/Boat.cpp
Normal file
215
windows/src/Boat.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* File: Boat.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Class for representng boat
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "Boat.h"
|
||||
#include <iostream>
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include <tiny_obj_loader.h> // Include tinyobjloader
|
||||
#include <glm/gtc/type_ptr.hpp> // For value_ptr (if needed for debugging)
|
||||
|
||||
Boat::Boat() : position(0.0f, 0.5f, 0.0f), rotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), speed(0.0f), steeringSpeed(1.0f), materials(), boatScale(1.0f) {} // Initialize boatScale to 1.0f
|
||||
Boat::~Boat() {}
|
||||
|
||||
bool Boat::init(const char* modelPath, const char* texturePath) {
|
||||
materials.clear(); // Explicitly clear materials before loading model
|
||||
if (!loadModel(modelPath)) {
|
||||
std::cerr << "Error loading boat model: " << modelPath << std::endl;
|
||||
return false;
|
||||
}
|
||||
boatTexturePath = texturePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Boat::cleanup() {
|
||||
// No dynamic memory cleanup in this simple example, but if you used dynamic allocation in loadModel, clean it up here.
|
||||
}
|
||||
|
||||
void Boat::update(const Input& input, const Ocean& ocean, float deltaTime) {
|
||||
handleInput(input, deltaTime);
|
||||
applyWaveMotion(ocean);
|
||||
}
|
||||
|
||||
void Boat::handleInput(const Input& input, float deltaTime) {
|
||||
if (input.isKeyDown('w')) {
|
||||
speed += 0.5f * deltaTime; // Accelerate forward
|
||||
}
|
||||
if (input.isKeyDown('s')) {
|
||||
speed -= 0.5f * deltaTime; // Decelerate/reverse
|
||||
}
|
||||
if (input.isKeyDown('a')) {
|
||||
rotation = glm::rotate(rotation, steeringSpeed * deltaTime, glm::vec3(0.0f, 1.0f, 0.0f)); // Steer left
|
||||
}
|
||||
if (input.isKeyDown('d')) {
|
||||
rotation = glm::rotate(rotation, -steeringSpeed * deltaTime, glm::vec3(0.0f, 1.0f, 0.0f)); // Steer right
|
||||
}
|
||||
|
||||
speed = glm::clamp(speed, -0.5f, 4.0f); // Clamp speed
|
||||
if (!input.isKeyDown('w') && !input.isKeyDown('s')) {
|
||||
speed *= (1.0f - 0.5f * deltaTime); // Natural deceleration
|
||||
if (fabs(speed) < 0.01f) speed = 0.0f; // Stop completely
|
||||
}
|
||||
|
||||
// Move boat forward/backward based on rotation and speed
|
||||
glm::vec3 forwardVector = rotation * glm::vec3(0.0f, 0.0f, -1.0f); // Boat's forward direction
|
||||
position += forwardVector * speed * deltaTime;
|
||||
}
|
||||
|
||||
void Boat::applyWaveMotion(const Ocean& ocean) {
|
||||
// Sample wave height at boat's position
|
||||
position.y = ocean.getWaveHeight(position.x, position.z, ocean.time);
|
||||
|
||||
// Get wave normal
|
||||
glm::vec3 waveNormal = ocean.getWaveNormal(position.x, position.z, ocean.time);
|
||||
//std::cout << "Wave Normal: (" << waveNormal.x << ", " << waveNormal.y << ", " << waveNormal.z << ")" << std::endl;
|
||||
|
||||
// Get current boat forward direction
|
||||
glm::vec3 currentBoatForward = rotation * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 horizontalForward = glm::normalize(glm::vec3(currentBoatForward.x, 0.0f, currentBoatForward.z));
|
||||
if (horizontalForward == glm::vec3(0.0f)) {
|
||||
horizontalForward = glm::vec3(0.0f, 0.0f, -1.0f); // Default if boat is pointing straight up/down
|
||||
}
|
||||
|
||||
glm::vec3 targetUp = waveNormal;
|
||||
glm::vec3 targetForward = glm::normalize(glm::cross(glm::cross(targetUp, horizontalForward), targetUp)); // Project horizontalForward onto plane perpendicular to targetUp
|
||||
|
||||
if (targetForward == glm::vec3(0.0f)) {
|
||||
targetForward = horizontalForward; // Fallback if projection fails (waveNormal is vertical or horizontalForward is parallel to waveNormal somehow)
|
||||
}
|
||||
|
||||
glm::vec3 targetRight = glm::normalize(glm::cross(targetForward, targetUp));
|
||||
|
||||
// Create rotation matrix from basis vectors
|
||||
glm::mat3 targetRotationMatrix(targetRight, targetUp, -targetForward); // Boat forward is -Z
|
||||
glm::quat targetRotation = glm::quat_cast(targetRotationMatrix);
|
||||
|
||||
rotation = glm::slerp(rotation, targetRotation, 0.1f);
|
||||
}
|
||||
|
||||
|
||||
bool Boat::loadModel(const char* path) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string warn, err;
|
||||
|
||||
// Extract the directory path from the OBJ file path
|
||||
std::string inputfile_dir = "./";
|
||||
std::string path_str = path;
|
||||
size_t last_slash_pos = path_str.find_last_of("/\\"); // Handle both / and \ path separators
|
||||
if (last_slash_pos != std::string::npos) {
|
||||
inputfile_dir = path_str.substr(0, last_slash_pos + 1); // Include the last slash
|
||||
}
|
||||
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path, inputfile_dir.c_str()); // Pass mtl_basepath
|
||||
|
||||
if (!warn.empty()) {
|
||||
std::cout << "tinyobjloader warning: " << warn << std::endl;
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << "tinyobjloader error: " << err << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vertices.clear();
|
||||
normals.clear();
|
||||
texCoords.clear();
|
||||
materialIndices.clear(); // Clear material indices
|
||||
// Loop through each shape in the OBJ file
|
||||
for (const auto& shape : shapes) {
|
||||
// Loop over faces(polygon)
|
||||
for (size_t f = 0; f < shape.mesh.indices.size() / 3; f++) {
|
||||
int material_index = shape.mesh.material_ids[f]; // Get material index for this face
|
||||
|
||||
// Loop over vertices in the face (triangle)
|
||||
for (size_t v = 0; v < 3; v++) {
|
||||
tinyobj::index_t idx = shape.mesh.indices[3 * f + v];
|
||||
|
||||
tinyobj::real_t vx = attrib.vertices[3 * idx.vertex_index + 0];
|
||||
tinyobj::real_t vy = attrib.vertices[3 * idx.vertex_index + 1];
|
||||
tinyobj::real_t vz = attrib.vertices[3 * idx.vertex_index + 2];
|
||||
vertices.push_back(glm::vec3(vx, vy, vz));
|
||||
|
||||
if (!attrib.normals.empty()) {
|
||||
tinyobj::real_t nx = attrib.normals[3 * idx.normal_index + 0];
|
||||
tinyobj::real_t ny = attrib.normals[3 * idx.normal_index + 1];
|
||||
tinyobj::real_t nz = attrib.normals[3 * idx.normal_index + 2];
|
||||
normals.push_back(glm::vec3(nx, ny, nz));
|
||||
} else {
|
||||
normals.push_back(glm::vec3(0.0f, 1.0f, 0.0f)); // Default normal if no normals in OBJ
|
||||
}
|
||||
|
||||
if (!attrib.texcoords.empty()) {
|
||||
tinyobj::real_t tx = attrib.texcoords[2 * idx.texcoord_index + 0];
|
||||
tinyobj::real_t ty = attrib.texcoords[2 * idx.texcoord_index + 1];
|
||||
texCoords.push_back(glm::vec2(tx, 1.0f - ty)); // Flip V texture coord (OpenGL convention)
|
||||
} else {
|
||||
texCoords.push_back(glm::vec2(0.0f, 0.0f)); // Default texcoord if no texcoords in OBJ
|
||||
}
|
||||
materialIndices.push_back(material_index); // Store material index for this vertex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
|
||||
glm::quat modelRotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); // Identity quaternion (no rotation initially)
|
||||
|
||||
// **Experiment with these rotations to find the correct orientation!**
|
||||
// Example 1: Rotate 180 degrees around Y-axis (to flip the boat horizontally if it's backwards)
|
||||
modelRotation = glm::rotate(modelRotation, glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // Rotate 180 degrees yaw
|
||||
modelRotation = glm::rotate(modelRotation, glm::radians(180.f), glm::vec3(1.0f, 0.0f, 0.0f)); // Yaw rotation (example: 0 degrees)
|
||||
modelRotation = glm::rotate(modelRotation, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // Pitch rotation (example: 0 degrees)
|
||||
// Example 2: Rotate around X-axis (Pitch) - Adjust angle as needed
|
||||
// modelRotation = glm::rotate(modelRotation, glm::radians(0.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // No pitch rotation in this example
|
||||
|
||||
// Example 3: Rotate around Z-axis (Roll) - Adjust angle as needed
|
||||
// modelRotation = glm::rotate(modelRotation, glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); // No roll rotation in this example
|
||||
|
||||
|
||||
// **Apply rotation to vertices AFTER model loading**
|
||||
for (glm::vec3& vertex : vertices) {
|
||||
vertex = modelRotation * vertex; // Apply rotation to each vertex in model space
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// **Calculate Bounding Box AFTER model loading**
|
||||
if (!vertices.empty()) {
|
||||
boundingBoxMin = vertices[0]; // Initialize with first vertex
|
||||
boundingBoxMax = vertices[0];
|
||||
std::cout << "Boat Bounding Box Min: (" << boundingBoxMin.x << ", " << boundingBoxMin.y << ", " << boundingBoxMin.z << ")" << std::endl;
|
||||
|
||||
// **Bounding Box Calculation Loop - This is where boundingBoxMin and boundingBoxMax are calculated and set**
|
||||
for (const auto& vertex : vertices) {
|
||||
boundingBoxMin.x = glm::min(boundingBoxMin.x, vertex.x);
|
||||
boundingBoxMin.y = glm::min(boundingBoxMin.y, vertex.y);
|
||||
boundingBoxMin.z = glm::min(boundingBoxMin.z, vertex.z);
|
||||
|
||||
boundingBoxMax.x = glm::max(boundingBoxMax.x, vertex.x);
|
||||
boundingBoxMax.y = glm::max(boundingBoxMax.y, vertex.y);
|
||||
boundingBoxMax.z = glm::max(boundingBoxMax.z, vertex.z);
|
||||
}
|
||||
std::cout << "Boat Bounding Box Min: (" << boundingBoxMin.x << ", " << boundingBoxMin.y << ", " << boundingBoxMin.z << ")" << std::endl;
|
||||
std::cout << "Boat Bounding Box Max: (" << boundingBoxMax.x << ", " << boundingBoxMax.y << ", " << boundingBoxMax.z << ")" << std::endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
83
windows/src/Camera.cpp
Normal file
83
windows/src/Camera.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* File: Camera.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Camera
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
#include "Camera.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
Camera::Camera() : position(10.0f, 10.0f, 10.0f), target(0.0f, 0.0f, 0.0f), up(0.0f, 1.0f, 0.0f),
|
||||
aspectRatio(1.0f), fov(45.0f), nearPlane(0.1f), farPlane(100.0f) {}
|
||||
|
||||
Camera::~Camera() {}
|
||||
|
||||
void Camera::init() {
|
||||
// Initial camera setup if needed
|
||||
}
|
||||
|
||||
void Camera::update(const Input& input, const glm::vec3& boatPosition) {
|
||||
target = boatPosition;
|
||||
|
||||
glm::vec3 lookDirection;
|
||||
lookDirection.x = cos(glm::radians(pitchAngle)) * cos(glm::radians(yawAngle));
|
||||
lookDirection.y = sin(glm::radians(pitchAngle));
|
||||
lookDirection.z = cos(glm::radians(pitchAngle)) * sin(glm::radians(yawAngle));
|
||||
lookDirection = glm::normalize(lookDirection);
|
||||
|
||||
position = target - lookDirection * glm::vec3(10.0f); // **Update position here in update**
|
||||
position.y = glm::max(position.y, 2.0f);
|
||||
|
||||
//position = boatPosition + glm::vec3(5.0f, 5.0f, 5.0f); // Offset from boat
|
||||
//position.y = glm::max(position.y, 2.0f); // Keep camera above water
|
||||
|
||||
up = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
|
||||
glm::vec3 forward = glm::normalize(target - position);
|
||||
glm::vec3 right = glm::normalize(glm::cross(forward, up));
|
||||
// Recalculate up to ensure orthogonality (important for gluLookAt)
|
||||
up = glm::normalize(glm::cross(right, forward));
|
||||
|
||||
handleMouseInput(input, 1.0f/60.0f); // Example deltaTime (fixed 60fps for now)
|
||||
}
|
||||
|
||||
void Camera::lookAt() const {
|
||||
gluLookAt(position.x, position.y, position.z,
|
||||
target.x, target.y, target.z,
|
||||
up.x, up.y, up.z);
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getViewMatrix() const { // Keep `const` method
|
||||
// Recalculate camera position and up vector based on yawAngle and pitchAngle
|
||||
|
||||
|
||||
// **Calculate view matrix based on CURRENT position, target, up - NO MODIFICATION of members in getViewMatrix**
|
||||
return glm::lookAt(position, target, up); // Use current position, target, up
|
||||
}
|
||||
|
||||
|
||||
void Camera::handleMouseInput(const Input& input, float deltaTime) {
|
||||
if (input.isMouseButtonDown(GLUT_RIGHT_BUTTON)) { // Rotate only when right mouse button is pressed
|
||||
float mouseSensitivity = 0.1f; // Adjust sensitivity
|
||||
yawAngle += input.getMouseDeltaX() * mouseSensitivity;
|
||||
pitchAngle -= input.getMouseDeltaY() * mouseSensitivity; // Invert vertical mouse motion
|
||||
|
||||
// Clamp pitch angle to prevent camera flipping
|
||||
pitchAngle = glm::clamp(pitchAngle, -89.0f, 89.0f);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::rotateYaw(float angle) {
|
||||
yawAngle += angle;
|
||||
}
|
||||
|
||||
void Camera::rotatePitch(float angle) {
|
||||
pitchAngle += angle;
|
||||
}
|
137
windows/src/Game.cpp
Normal file
137
windows/src/Game.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* File: Game.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: This class integrates all items into the game world.
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
#include "Game.h"
|
||||
|
||||
Game* Game::instance = nullptr;
|
||||
|
||||
Game::Game() : renderer(), input(), ocean(200), boat(), camera(), terrain(150, 1.0f) {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
Game::~Game() {
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
bool Game::init(int argc, char** argv) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
|
||||
glutInitWindowSize(1200, 800);
|
||||
glutCreateWindow("3D Boat Simulation");
|
||||
|
||||
// **Initialize GLEW AFTER creating the window:**
|
||||
if (glewInit() != GLEW_OK) {
|
||||
//std::cerr << "GLEW initialization failed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
glutDisplayFunc(displayCallback);
|
||||
glutReshapeFunc(reshapeCallback);
|
||||
glutKeyboardFunc(keyboardCallback);
|
||||
glutKeyboardUpFunc(keyboardUpCallback);
|
||||
glutSpecialFunc(specialCallback);
|
||||
glutSpecialUpFunc(specialUpCallback);
|
||||
glutMouseFunc(mouseCallback);
|
||||
glutMotionFunc(motionCallback);
|
||||
glutTimerFunc(16, timerCallback, 0); // ~60 FPS
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
renderer.init();
|
||||
//int oceanGridSize = 1000; // Default gridSize (you can change this)
|
||||
//ocean = Ocean(oceanGridSize); // Pass gridSize to constructor
|
||||
ocean.init();
|
||||
|
||||
if (!boat.init("assets/models/boat.obj", "assets/models/boat.jpg")) {
|
||||
std::cerr << "Boat initialization failed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
boat.setScale(0.01f); // Example: Make the boat half its original size
|
||||
|
||||
|
||||
|
||||
|
||||
std::cerr << "Terrain init" << std::endl;
|
||||
|
||||
// Initialize Terrain
|
||||
if (!terrain.init(renderer.heightMapTextureID)) {
|
||||
std::cerr << "Terrain initialization failed!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cerr << "Camera init" << std::endl;
|
||||
|
||||
camera.init();
|
||||
std::cerr << "Input init" << std::endl;
|
||||
|
||||
input.init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Game::run() {
|
||||
glutMainLoop();
|
||||
}
|
||||
|
||||
void Game::cleanup() {
|
||||
renderer.cleanup();
|
||||
ocean.cleanup();
|
||||
boat.cleanup();
|
||||
terrain.cleanup(); // Cleanup terrain
|
||||
|
||||
}
|
||||
|
||||
void Game::displayCallback() {
|
||||
instance->renderer.renderScene(instance->ocean, instance->boat, instance->camera, instance->terrain); // **Pass instance->terrain**
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
void Game::reshapeCallback(int width, int height) {
|
||||
instance->renderer.reshape(width, height);
|
||||
instance->camera.setAspectRatio(static_cast<float>(width) / height);
|
||||
}
|
||||
|
||||
void Game::keyboardCallback(unsigned char key, int x, int y) {
|
||||
instance->input.handleKeyPress(key);
|
||||
}
|
||||
|
||||
void Game::keyboardUpCallback(unsigned char key, int x, int y) {
|
||||
instance->input.handleKeyRelease(key);
|
||||
}
|
||||
|
||||
void Game::specialCallback(int key, int x, int y) {
|
||||
instance->input.handleSpecialKeyPress(key);
|
||||
}
|
||||
|
||||
void Game::specialUpCallback(int key, int x, int y) {
|
||||
instance->input.handleSpecialKeyRelease(key);
|
||||
}
|
||||
|
||||
void Game::mouseCallback(int button, int state, int x, int y) {
|
||||
instance->input.handleMouseClick(button, state, x, y);
|
||||
}
|
||||
|
||||
void Game::motionCallback(int x, int y) {
|
||||
instance->input.handleMouseMove(x, y);
|
||||
}
|
||||
|
||||
void Game::updateGame() {
|
||||
float deltaTime = 1.0f / 60.0f; // Fixed timestep for simplicity
|
||||
instance->input.update();
|
||||
instance->boat.update(instance->input, instance->ocean, deltaTime);
|
||||
instance->camera.update(instance->input, instance->boat.getPosition()); // Camera follows boat (optional)
|
||||
instance->ocean.update(deltaTime);
|
||||
}
|
||||
|
||||
void Game::timerCallback(int value) {
|
||||
instance->updateGame();
|
||||
glutTimerFunc(16, timerCallback, 0); // Re-register timer
|
||||
glutPostRedisplay(); // Request redraw
|
||||
}
|
||||
|
65
windows/src/Input.cpp
Normal file
65
windows/src/Input.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* File: Input.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: This class defines the game inputs.
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
#include "Input.h"
|
||||
#include <GL/freeglut.h>
|
||||
#include <cstring>
|
||||
Input::Input() {
|
||||
memset(mouseButtonsDown, false, sizeof(mouseButtonsDown)); // Initialize mouse button states to false
|
||||
mouseX = mouseY = lastMouseX = lastMouseY = 0;
|
||||
mouseDeltaX = mouseDeltaY = 0;
|
||||
}
|
||||
Input::~Input() {}
|
||||
|
||||
void Input::init() {}
|
||||
void Input::update() {
|
||||
// Calculate mouse delta
|
||||
mouseDeltaX = mouseX - lastMouseX;
|
||||
mouseDeltaY = mouseY - lastMouseY;
|
||||
|
||||
// Update last mouse positions for next frame
|
||||
lastMouseX = mouseX;
|
||||
lastMouseY = mouseY;
|
||||
}
|
||||
void Input::handleKeyPress(unsigned char key) {
|
||||
keysDown.insert(key);
|
||||
}
|
||||
|
||||
void Input::handleKeyRelease(unsigned char key) {
|
||||
keysDown.erase(key);
|
||||
}
|
||||
|
||||
void Input::handleSpecialKeyPress(int key) {
|
||||
specialKeysDown.insert(key);
|
||||
}
|
||||
|
||||
void Input::handleSpecialKeyRelease(int key) {
|
||||
specialKeysDown.erase(key);
|
||||
}
|
||||
|
||||
void Input::handleMouseClick(int button, int state, int x, int y) {
|
||||
if (button >= 0 && button < 5) { // Check button index is within range
|
||||
mouseButtonsDown[button] = (state == GLUT_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void Input::handleMouseMove(int x, int y) {
|
||||
mouseX = x;
|
||||
mouseY = y;
|
||||
}
|
||||
|
||||
bool Input::isKeyDown(unsigned char key) const {
|
||||
return keysDown.count(key);
|
||||
}
|
||||
|
||||
bool Input::isSpecialKeyDown(int key) const {
|
||||
return specialKeysDown.count(key);
|
||||
}
|
403
windows/src/Ocean.cpp
Normal file
403
windows/src/Ocean.cpp
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* File: Ocean.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: This class defines ocean (surface). The core functions of this class are optimized by the IPA Project 2025.
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
#include "Ocean.h"
|
||||
#include <cmath>
|
||||
#include <glm/gtc/constants.hpp> // For pi
|
||||
#include <chrono>
|
||||
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
#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)
|
||||
{
|
||||
// Placeholder C++ implementation using float arrays
|
||||
//for (size_t i = 0; i < numVertices; ++i) {
|
||||
// updatedVertices_array[i * 3 + 0] += time * 0.1f; // Example: simple movement in x-direction (modifying float array directly)
|
||||
//}
|
||||
// Update normals in the float array as needed based on your simulation
|
||||
}
|
||||
#endif
|
||||
|
||||
Ocean::Ocean(int gridSize) : time(0.0f),gridSize(gridSize), gridSpacing(1.0f),
|
||||
amplitude(0.8f), wavelength(10.0f), frequency(1.0f), // Adjusted amplitude slightly
|
||||
direction(glm::vec2(1.0f, 0.0f)), phase(0.0f)
|
||||
{
|
||||
gerstnerWaves.push_back({1.0f, 10.0f, 1.0f, glm::normalize(glm::vec2(1.0f, 0.0f)), 0.0f});
|
||||
gerstnerWaves.push_back({0.3f, 5.0f, 2.0f, glm::normalize(glm::vec2(1.0f, 1.0f)), 0.0f});
|
||||
//gerstnerWaves.push_back({1.0f, 3.0f, 1.0f, glm::normalize(glm::vec2(1.0f, 0.5f)), 0.0f});
|
||||
//gerstnerWaves.push_back({0.3f, 5.0f, 2.0f, glm::normalize(glm::vec2(0.5f, 0.5f)), 0.0f});
|
||||
//gerstnerWaves.push_back({1.0f, 10.0f, 1.0f, glm::normalize(glm::vec2(1.0f, 0.0f)), 0.0f});
|
||||
//gerstnerWaves.push_back({0.5f, 2.0f, 3.0f, glm::normalize(glm::vec2(1.0f, 1.0f)), 0.0f});
|
||||
//gerstnerWaves.push_back({1.0f, 1.0f, 0.2f, glm::normalize(glm::vec2(0.7f, 0.2f)), 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()
|
||||
{
|
||||
generateGrid();
|
||||
createBuffers(); // Create VBOs and IBO
|
||||
|
||||
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)
|
||||
{
|
||||
time += deltaTime;
|
||||
std::vector<glm::vec3> updatedVertices_vec = vertices; // Create a copy to update (vector version)
|
||||
std::vector<glm::vec3> updatedNormals_vec(vertices.size()); // Vector to store updated normals (vector version)
|
||||
|
||||
std::vector<glm::vec3> updatedVertices_simd_vec = vertices; // Create a copy to update (vector for comparison)
|
||||
std::vector<glm::vec3> updatedNormals_simd_vec(vertices.size()); // Vector to store updated normals (vector for comparison)
|
||||
|
||||
|
||||
// --- Conversion to Float Arrays for SIMD function ---
|
||||
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;
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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);
|
||||
end = rdtsc();
|
||||
|
||||
end_time = std::chrono::high_resolution_clock::now();
|
||||
duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
|
||||
|
||||
std::cout << "Ocean::update (SIMD) took " << duration.count() << "ns " << "CPU cycles: " << (end - start) << std::endl;
|
||||
|
||||
|
||||
// --- Convert float arrays back to vectors for updateBuffers (if needed) ---
|
||||
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];
|
||||
|
||||
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
|
||||
|
||||
|
||||
// --- Deallocate float arrays ---
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Ocean::generateGrid()
|
||||
{
|
||||
//std::cout << "Ocean::generateGrid - gridSize: " << gridSize << " " << vertices.size()<< std::endl;
|
||||
vertices.resize(gridSize * gridSize);
|
||||
// Resize original coordinate vectors
|
||||
originalWorldX.resize(gridSize * gridSize);
|
||||
originalWorldZ.resize(gridSize * gridSize);
|
||||
|
||||
for (int x = 0; x < gridSize; ++x) {
|
||||
for (int z = 0; z < gridSize; ++z) {
|
||||
float worldX = (x - gridSize / 2.0f) * gridSpacing;
|
||||
float worldZ = (z - gridSize / 2.0f) * gridSpacing;
|
||||
vertices[x * gridSize + z] = glm::vec3(worldX, 0.0f, worldZ);
|
||||
|
||||
// Store original world coordinates
|
||||
originalWorldX[x * gridSize + z] = worldX;
|
||||
originalWorldZ[x * gridSize + z] = worldZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
for (int x = 0; x < gridSize; ++x)
|
||||
{
|
||||
for (int z = 0; z < gridSize; ++z)
|
||||
{
|
||||
|
||||
glm::vec3 &vertex = vertices[x * gridSize + z];
|
||||
float originalX = originalWorldX[x * gridSize + z];
|
||||
float originalZ = originalWorldZ[x * gridSize + z];
|
||||
vertex.y = getWaveHeight(vertex.x, vertex.z, time);
|
||||
|
||||
(*updatedNormals)[x * gridSize + z] = getWaveNormal(originalX, originalZ, time); // Calculate normal using original coords
|
||||
}
|
||||
}
|
||||
//vertices = updatedVertices; // Assign the updated vertices back
|
||||
//updateBuffers(updatedVertices, updatedNormals);
|
||||
}
|
||||
|
||||
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;
|
||||
for (const auto& wave : gerstnerWaves) {
|
||||
totalHeight += getGerstnerWaveHeight(wave, x, z, time);
|
||||
}
|
||||
return totalHeight;
|
||||
}
|
||||
|
||||
float Ocean::getGerstnerWaveHeight(const GerstnerWave& wave, float x, float z, float time) const {
|
||||
float k = 2.0f * glm::pi<float>() / wave.wavelength;
|
||||
float w = wave.speed * k;
|
||||
float dotProduct = glm::dot(wave.direction, glm::vec2(x, z));
|
||||
float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi<float>() * time / wave.wavelength));
|
||||
float waveHeightValue = periodicAmplitude * sin(k * dotProduct - w * time + wave.phase);
|
||||
|
||||
if (fabs(x) < 0.5f && fabs(z) < 0.5f) {
|
||||
//std::cout << " getGerstnerWaveHeight - time: " << time << ", periodicAmplitude: " << periodicAmplitude << ", waveHeightValue: " << waveHeightValue << std::endl;
|
||||
}
|
||||
|
||||
return waveHeightValue;
|
||||
}
|
||||
|
||||
glm::vec3 Ocean::getGerstnerWaveDisplacement(const GerstnerWave& wave, float x, float z, float time) const {
|
||||
float k = 2.0f * glm::pi<float>() / wave.wavelength;
|
||||
float w = wave.speed * k;
|
||||
float dotProduct = glm::dot(wave.direction, glm::vec2(x, z));
|
||||
float cosTerm = cos(k * dotProduct - w * time + wave.phase);
|
||||
float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi<float>() * time / wave.wavelength));
|
||||
return glm::vec3(wave.direction.x * periodicAmplitude * cosTerm,
|
||||
0.0f,
|
||||
wave.direction.y * periodicAmplitude * cosTerm);
|
||||
}
|
||||
|
||||
glm::vec3 Ocean::getWaveNormal(float x, float z, float time) const {
|
||||
glm::vec3 tangentX = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 tangentZ = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
|
||||
for (const auto& wave : gerstnerWaves) {
|
||||
float k = 2.0f * glm::pi<float>() / wave.wavelength;
|
||||
float w = wave.speed * k;
|
||||
float dotProduct = glm::dot(wave.direction, glm::vec2(x, z));
|
||||
float sinTerm = sin(k * dotProduct - w * time + wave.phase);
|
||||
float cosTerm = cos(k * dotProduct - w * time + wave.phase);
|
||||
float periodicAmplitude = wave.amplitude * 0.5f * (1.0f + sin(2.0f * glm::pi<float>() * time / wave.wavelength));
|
||||
float modulatedAmplitude = periodicAmplitude;
|
||||
|
||||
// Calculate tangent vectors for EACH wave component and ACCUMULATE them directly
|
||||
tangentX += glm::vec3(
|
||||
-modulatedAmplitude * wave.direction.x * wave.direction.x * k * sinTerm, // dx_dx
|
||||
modulatedAmplitude * wave.direction.x * k * cosTerm, // dy_dx
|
||||
-modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm // dz_dx
|
||||
);
|
||||
|
||||
tangentZ += glm::vec3(
|
||||
-modulatedAmplitude * wave.direction.x * wave.direction.y * k * sinTerm, // dx_dz
|
||||
modulatedAmplitude * wave.direction.y * k * cosTerm, // dy_dz
|
||||
-modulatedAmplitude * wave.direction.y * wave.direction.y * k * sinTerm // dz_dz
|
||||
);
|
||||
}
|
||||
|
||||
return glm::normalize(glm::cross(tangentZ, tangentX));
|
||||
}
|
||||
void Ocean::setGridSize(int newGridSize)
|
||||
{
|
||||
gridSize = newGridSize;
|
||||
generateGrid(); // Re-generate the grid with the new size
|
||||
|
||||
std::vector<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);
|
||||
|
||||
updateBuffers(updatedVertices, updatedNormals);
|
||||
//updateVertices(); // Re-update vertices based on waves (optional, if needed immediately)
|
||||
}
|
||||
|
||||
GLuint Ocean::getVAO() const
|
||||
{
|
||||
return vaoID;
|
||||
}
|
||||
|
||||
GLuint Ocean::getIndexCount() const
|
||||
{
|
||||
return indexCount;
|
||||
}
|
||||
|
||||
int Ocean::getGridIndex(int x, int z) const {
|
||||
return x * gridSize + z;
|
||||
}
|
126
windows/src/Shader.cpp
Normal file
126
windows/src/Shader.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* File: Shader.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Shader controll
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
#include "Shader.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
Shader::Shader() : vertexShaderID(0), fragmentShaderID(0), programID(0) {}
|
||||
|
||||
Shader::~Shader() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
|
||||
bool Shader::loadShader(const char* vertexShaderPath, const char* fragmentShaderPath) {
|
||||
// 1. Compile vertex and fragment shaders
|
||||
if (!compileShader(vertexShaderID, GL_VERTEX_SHADER, vertexShaderPath)) return false;
|
||||
if (!compileShader(fragmentShaderID, GL_FRAGMENT_SHADER, fragmentShaderPath)) return false;
|
||||
|
||||
// 2. Link shader program
|
||||
if (!linkShaderProgram()) return false;
|
||||
|
||||
return true; // Shader program loaded and linked successfully
|
||||
}
|
||||
|
||||
|
||||
bool Shader::compileShader(GLuint& shaderID, GLenum shaderType, const char* shaderPath) {
|
||||
shaderID = glCreateShader(shaderType);
|
||||
std::string shaderCode;
|
||||
std::ifstream shaderFile;
|
||||
shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); // Enable exception throwing
|
||||
try {
|
||||
shaderFile.open(shaderPath);
|
||||
std::stringstream shaderStream;
|
||||
shaderStream << shaderFile.rdbuf();
|
||||
shaderFile.close();
|
||||
shaderCode = shaderStream.str();
|
||||
} catch (std::ifstream::failure& e) {
|
||||
std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << shaderPath << std::endl;
|
||||
return false;
|
||||
}
|
||||
const char* shaderCodeCStr = shaderCode.c_str();
|
||||
glShaderSource(shaderID, 1, &shaderCodeCStr, NULL);
|
||||
glCompileShader(shaderID);
|
||||
|
||||
// Check for shader compile errors
|
||||
int success;
|
||||
char infoLog[512];
|
||||
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(shaderID, 512, NULL, infoLog);
|
||||
std::cerr << "ERROR::SHADER::COMPILATION_FAILED: " << shaderPath << "\n" << infoLog << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Shader::linkShaderProgram() {
|
||||
programID = glCreateProgram();
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
|
||||
// Check for linking errors
|
||||
int success;
|
||||
char infoLog[512];
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetProgramInfoLog(programID, 512, NULL, infoLog);
|
||||
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
glDeleteShader(vertexShaderID); // Delete shaders as they are linked into program now and no longer necessary
|
||||
glDeleteShader(fragmentShaderID); // Shader objects are deleted after linking
|
||||
vertexShaderID = 0;
|
||||
fragmentShaderID = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Shader::use() {
|
||||
glUseProgram(programID);
|
||||
}
|
||||
|
||||
void Shader::unuse() {
|
||||
glUseProgram(0); // Unuse shader program (use fixed-function pipeline)
|
||||
}
|
||||
|
||||
void Shader::cleanup() {
|
||||
if (programID != 0) {
|
||||
glDeleteProgram(programID);
|
||||
programID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Shader::setInt(const std::string& name, int value) const {
|
||||
glUniform1i(glGetUniformLocation(programID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setFloat(const std::string& name, float value) const {
|
||||
glUniform1f(glGetUniformLocation(programID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setVec3(const std::string& name, const glm::vec3& value) const {
|
||||
glUniform3fv(glGetUniformLocation(programID, name.c_str()), 1, glm::value_ptr(value));
|
||||
}
|
||||
|
||||
void Shader::setMat4(const std::string& name, const glm::mat4& mat) const {
|
||||
glUniformMatrix4fv(glGetUniformLocation(programID, name.c_str()), 1, GL_FALSE, glm::value_ptr(mat));
|
||||
}
|
||||
void Shader::setMat3(const std::string& name, const glm::mat3& mat) const {
|
||||
glUniformMatrix3fv(glGetUniformLocation(programID, name.c_str()), 1, GL_FALSE, glm::value_ptr(mat));
|
||||
}
|
195
windows/src/Terrain.cpp
Normal file
195
windows/src/Terrain.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* File: Terran.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: This class defines terrain (surface).
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
#include "Terrain.h"
|
||||
#include <cmath>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <iostream>
|
||||
#include "utils.h" // Include utils.h for checkGLError
|
||||
#include <GL/glew.h>
|
||||
|
||||
Terrain::Terrain(int gridSize, float gridSpacing)
|
||||
: gridSize(gridSize),
|
||||
gridSpacing(gridSpacing),
|
||||
vertices(gridSize * gridSize),
|
||||
normals(gridSize * gridSize),
|
||||
texCoords(gridSize * gridSize),
|
||||
vertexBufferID(0),
|
||||
normalBufferID(0),
|
||||
texCoordBufferID(0),
|
||||
indexBufferID(0),
|
||||
vaoID(0),
|
||||
indexCount(0) {}
|
||||
|
||||
Terrain::~Terrain() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool Terrain::init(GLuint heightMapTextureID) {
|
||||
generateGrid(heightMapTextureID);
|
||||
createBuffers();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Terrain::cleanup() {
|
||||
glDeleteBuffers(1, &vertexBufferID);
|
||||
glDeleteBuffers(1, &normalBufferID);
|
||||
glDeleteBuffers(1, &texCoordBufferID);
|
||||
glDeleteBuffers(1, &indexBufferID);
|
||||
glDeleteVertexArrays(1, &vaoID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Terrain::generateGrid(GLuint heightMapTextureID) {
|
||||
|
||||
std::cout << "Terrain::generateGrid - gridSize: " << gridSize << std::endl;
|
||||
vertices.resize(gridSize * gridSize);
|
||||
normals.resize(gridSize * gridSize);
|
||||
texCoords.resize(gridSize * gridSize);
|
||||
|
||||
// **Access Heightmap Texture Data**
|
||||
glBindTexture(GL_TEXTURE_2D, heightMapTextureID); // Bind heightmap texture
|
||||
GLint textureWidth, textureHeight;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &textureWidth); // Get texture width
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &textureHeight); // Get texture height
|
||||
|
||||
std::vector<unsigned char> heightmapData(textureWidth * textureHeight); // Assuming 8-bit grayscale heightmap
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_UNSIGNED_BYTE, heightmapData.data()); // Get texture pixel data (Red channel = grayscale height)
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
|
||||
float heightScale = 40.0f; // Adjust this to control terrain height scale
|
||||
|
||||
for (int x = 0; x < gridSize; ++x) {
|
||||
for (int z = 0; z < gridSize; ++z) {
|
||||
float worldX = (x - gridSize / 2.0f) * gridSpacing;
|
||||
float worldZ = (z - gridSize / 2.0f) * gridSpacing;
|
||||
|
||||
// **Sample height from heightmap texture**
|
||||
float height = 0.0f;
|
||||
if (x < textureWidth && z < textureHeight && x >= 0 && z >= 0) { // Bounds check - important!
|
||||
height = static_cast<float>(heightmapData[z * textureWidth + x]) / 255.0f * heightScale-15.0; // Normalize to [0, 1], scale by heightScale
|
||||
|
||||
} else {
|
||||
// Handle out-of-bounds access (e.g., set height to 0 or a default value)
|
||||
height = 0.0f;
|
||||
}
|
||||
|
||||
//vertices[x * gridSize + z] = glm::vec3(worldX, height, worldZ); // Set vertex position with height from heightmap
|
||||
vertices[x * gridSize + z] = glm::vec3(worldX, height, worldZ); // Flat terrain at y=0
|
||||
normals[x * gridSize + z] = glm::vec3(0.0f, 1.0f, 0.0f); // Upward normals for flat terrain
|
||||
texCoords[x * gridSize + z] = glm::vec2(static_cast<float>(x) / 50.0f, static_cast<float>(z) / 50.0f); // Example texture tiling
|
||||
//originalWorldX[x * gridSize + z] = worldX;
|
||||
//originalWorldZ[x * gridSize + z] = worldZ;
|
||||
}
|
||||
}
|
||||
std::cout << "Width: " << textureWidth << "Geight: " << textureHeight << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void Terrain::createBuffers() {
|
||||
glGenVertexArrays(1, &vaoID);
|
||||
checkGLError("1"); // Check after drawMeshVBO call
|
||||
|
||||
glBindVertexArray(vaoID);
|
||||
checkGLError("2"); // Check after drawMeshVBO call
|
||||
|
||||
glGenBuffers(1, &vertexBufferID);
|
||||
checkGLError("3"); // Check after drawMeshVBO call
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
|
||||
checkGLError("4"); // Check after drawMeshVBO call
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
|
||||
checkGLError("5"); // Check after drawMeshVBO call
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
checkGLError("6"); // Check after drawMeshVBO call
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
checkGLError("7"); // Check after drawMeshVBO call
|
||||
|
||||
glGenBuffers(1, &normalBufferID);
|
||||
checkGLError("8"); // Check after drawMeshVBO call
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, normalBufferID);
|
||||
checkGLError("9"); // Check after drawMeshVBO call
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
|
||||
checkGLError("10"); // Check after drawMeshVBO call
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
checkGLError("11"); // Check after drawMeshVBO call
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
checkGLError("12"); // Check after drawMeshVBO call
|
||||
|
||||
|
||||
glGenBuffers(1, &texCoordBufferID);
|
||||
checkGLError("13"); // Check after drawMeshVBO call
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texCoordBufferID);
|
||||
checkGLError("14"); // Check after drawMeshVBO call
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW);
|
||||
checkGLError("15"); // Check after drawMeshVBO call
|
||||
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
checkGLError("16"); // Check after drawMeshVBO call
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
checkGLError("17"); // Check after drawMeshVBO call
|
||||
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
glGenBuffers(1, &indexBufferID);
|
||||
checkGLError("glGenBuffers - indexBufferID"); // Check after glGenBuffers
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
|
||||
checkGLError("18"); // Check after drawMeshVBO call
|
||||
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
|
||||
checkGLError("19"); // Check after drawMeshVBO call
|
||||
|
||||
glBindVertexArray(0);
|
||||
checkGLError("20"); // Check after drawMeshVBO call
|
||||
|
||||
indexCount = indices.size();
|
||||
}
|
||||
|
||||
void Terrain::updateBuffers() {
|
||||
// Not needed for static terrain in this basic example
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 Terrain::getVertex(int x, int z) const {
|
||||
assert(x >= 0 && x < gridSize);
|
||||
assert(z >= 0 && z < gridSize);
|
||||
return vertices[x * gridSize + z];
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 Terrain::getNormal(float x, float z) const
|
||||
{
|
||||
return normals[x * gridSize + z];
|
||||
|
||||
}
|
21
windows/src/main.cpp
Normal file
21
windows/src/main.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* File: main.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Main
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
#include "Game.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Game game;
|
||||
if (!game.init(argc, argv)) {
|
||||
return 1;
|
||||
}
|
||||
game.run();
|
||||
game.cleanup();
|
||||
return 0;
|
||||
}
|
634
windows/src/render.cpp
Normal file
634
windows/src/render.cpp
Normal file
@ -0,0 +1,634 @@
|
||||
/*
|
||||
* File: render.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Game renderer
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "Renderer.h"
|
||||
#include <iostream>
|
||||
#include <SOIL/SOIL.h>
|
||||
#include "utils.h"
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
Renderer::Renderer() : oceanTextureID(0), boatTextureID(0), terrainTextureID(0), heightMapTextureID(0) {}
|
||||
|
||||
Renderer::~Renderer() {}
|
||||
|
||||
bool Renderer::init()
|
||||
{
|
||||
glewInit();
|
||||
if (glewIsSupported("GL_VERSION_3_0"))
|
||||
{
|
||||
std::cout << "OpenGL 3.0 or higher supported: Shaders will work." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "OpenGL 3.0 or higher NOT supported: Shaders might not work." << std::endl;
|
||||
}
|
||||
|
||||
glClearColor(0.529f, 0.808f, 0.922f, 1.0f); // Light blue background
|
||||
|
||||
if (!loadTexture("assets/textures/ocean_texture.png", oceanTextureID))
|
||||
{
|
||||
std::cerr << "Error loading ocean texture." << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!loadTexture("assets/textures/rock_texture.png", terrainTextureID)) { // Assuming you name it terrain_texture.jpg
|
||||
std::cerr << "Error loading terrain texture." << std::endl;
|
||||
return false;
|
||||
}
|
||||
checkGLError("loadTexture - terrainTexture"); // Check after terrain texture loading
|
||||
|
||||
// **Load heightmap texture:**
|
||||
if (!loadTexture("assets/textures/terain.png", heightMapTextureID)) { // Assuming heightmap is terrain_heightmap.png
|
||||
std::cerr << "Error loading terrain heightmap texture." << std::endl;
|
||||
return false;
|
||||
}
|
||||
checkGLError("loadTexture - heightMapTexture"); // Check after heightmap texture loading
|
||||
|
||||
terrainShader.loadShader("assets/shaders/terrain_vertex_shader.glsl", "assets/shaders/terrain_fragment_shader.glsl");
|
||||
if (!terrainShader.isLoaded()) {
|
||||
std::cerr << "Error loading terrain shader program!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
checkGLError("terrainShader.loadShader"); // Check after shader loading
|
||||
// Load and compile ocean shader program:
|
||||
oceanShader.loadShader("assets/shaders/ocean_vertex_shader.glsl", "assets/shaders/ocean_fragment_shader.glsl");
|
||||
if (!oceanShader.isLoaded()) {
|
||||
std::cerr << "Error loading ocean shader program!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
checkGLError("oceanShader.loadShader"); // Check after shader loading
|
||||
// Boat texture is now loaded in drawBoat, based on Boat class texture path
|
||||
|
||||
setupLighting();
|
||||
// shaderProgram.loadShader("assets/shaders/vertex_shader.glsl", "assets/shaders/fragment_shader.glsl"); // Optional shader loading
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::cleanup()
|
||||
{
|
||||
glDeleteTextures(1, &oceanTextureID);
|
||||
glDeleteTextures(1, &boatTextureID);
|
||||
glDeleteTextures(1, &terrainTextureID);
|
||||
glDeleteTextures(1, &heightMapTextureID);
|
||||
|
||||
// shaderProgram.cleanup(); // Optional shader cleanup
|
||||
}
|
||||
|
||||
void Renderer::renderScene(const Ocean &ocean, const Boat &boat, const Camera &camera, const Terrain &terrain)
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
|
||||
camera.lookAt(); // Set up camera view
|
||||
|
||||
setupLighting(); // Ensure lighting is enabled each frame
|
||||
drawTerrain(terrain, camera); // **Call drawTerrain here - BEFORE drawOcean**
|
||||
|
||||
drawOcean(ocean, camera);
|
||||
drawBoat(boat);
|
||||
checkGLError("drawTerrain"); // Check after drawTerrain
|
||||
// Optional: Render skybox, UI, etc.
|
||||
// ...
|
||||
}
|
||||
|
||||
void Renderer::reshape(int width, int height)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(45.0f, static_cast<float>(width) / height, 0.1f, 100.0f); // Adjust near/far planes
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
bool Renderer::loadTexture(const char *filename, GLuint &textureID)
|
||||
{
|
||||
textureID = SOIL_load_OGL_texture(filename, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
|
||||
if (textureID == 0)
|
||||
{
|
||||
std::cerr << "SOIL loading error: '" << SOIL_last_result() << "' (" << filename << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps for better quality at distance
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::setupLighting()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
|
||||
GLfloat lightAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f};
|
||||
GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
|
||||
GLfloat lightSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
GLfloat lightPosition[] = {10.0f, 10.0f, 10.0f, 0.0f}; // Directional light from above and to the right
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
|
||||
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); // Material colors track glColor
|
||||
GLfloat matSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
GLfloat matShininess[] = {50.0f};
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpecular);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, matShininess);
|
||||
}
|
||||
|
||||
void Renderer::drawOcean(const Ocean& ocean, const Camera& camera)
|
||||
{
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// Use the ocean shader program:
|
||||
oceanShader.use();
|
||||
checkGLError("oceanShader.use"); // Check after shader use
|
||||
|
||||
// Set Uniforms for Ocean Shader:
|
||||
glm::mat4 modelMatrix;
|
||||
glm::mat4 projectionMatrix;
|
||||
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(modelMatrix));
|
||||
checkGLError("glGetFloatv(GL_MODELVIEW_MATRIX)"); // Check after glGetFloatv
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, glm::value_ptr(projectionMatrix));
|
||||
checkGLError("glGetFloatv(GL_PROJECTION_MATRIX)"); // Check after glGetFloatv
|
||||
|
||||
|
||||
oceanShader.setMat4("model", modelMatrix);
|
||||
oceanShader.setMat4("view", camera.getViewMatrix());
|
||||
oceanShader.setMat4("projection", projectionMatrix);
|
||||
oceanShader.setMat3("normalMatrix", glm::transpose(glm::inverse(glm::mat3(modelMatrix))));
|
||||
checkGLError("shader.setMat4/setMat3 uniforms"); // Check after setting matrix uniforms
|
||||
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, oceanTextureID);
|
||||
oceanShader.setInt("oceanTexture", 0);
|
||||
checkGLError("glBindTexture - oceanTexture"); // Check after glBindTexture
|
||||
|
||||
//glActiveTexture(GL_TEXTURE1);
|
||||
//glBindTexture(GL_TEXTURE_2D, normalMapTextureID);
|
||||
//oceanShader.setInt("normalMap", 1);
|
||||
//checkGLError("glBindTexture - normalMapTexture"); // Check after glBindTexture
|
||||
|
||||
|
||||
oceanShader.setVec3("lightDir", glm::normalize(glm::vec3(1.0f, 1.0f, 1.0f)));
|
||||
oceanShader.setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
oceanShader.setVec3("viewPosWorld", camera.getPosition());
|
||||
checkGLError("shader.setVec3 uniforms"); // Check after setting vec3 uniforms
|
||||
|
||||
|
||||
drawMeshVBO(ocean); // Draw using VBOs and IBO
|
||||
checkGLError("drawMeshVBO"); // Check after drawMeshVBO call
|
||||
|
||||
// Unuse shader program after drawing ocean
|
||||
oceanShader.unuse();
|
||||
checkGLError("oceanShader.unuse"); // Check after shader unuse
|
||||
|
||||
//glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
//glTranslatef(0.0f, -1.0f, 0.0f); // Lower the ocean slightly
|
||||
|
||||
// **Disable Texture and Lighting for Normal Visualization**
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor3f(1.0f, 0.0f, 0.0f); // Red color for normals (you can change this)
|
||||
|
||||
int gridSize = ocean.getGridSize();
|
||||
float gridSpacing = ocean.getGridSpacing();
|
||||
|
||||
#if SHOW_NORM
|
||||
|
||||
|
||||
// **Draw Normals as Lines**
|
||||
glBegin(GL_LINES);
|
||||
for (int x = 0; x < gridSize; ++x)
|
||||
{
|
||||
for (int z = 0; z < gridSize; ++z)
|
||||
{
|
||||
glm::vec3 v = ocean.getVertex(x, z);
|
||||
glm::vec3 normal = ocean.getWaveNormal(v.x, v.z, ocean.time); // Get normal at vertex
|
||||
|
||||
// Calculate endpoint of normal line - Scale normal for visibility
|
||||
float normalLength = 0.5f; // Adjust this value to control normal line length
|
||||
glm::vec3 normalEndpoint = v + normal * normalLength;
|
||||
|
||||
// Draw line representing the normal
|
||||
glVertex3f(v.x, v.y, v.z); // Start point of normal line (vertex position)
|
||||
glVertex3f(normalEndpoint.x, normalEndpoint.y, normalEndpoint.z); // End point of normal line (along normal direction)
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
#endif
|
||||
|
||||
// **Re-enable Texture and Lighting (if you want to switch back to textured rendering later)**
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// glEnable(GL_LIGHTING);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// **Disable Texture and Lighting for Wireframe Rendering**
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor3f(0.0f, 0.0f, 0.0f); // Green color for wireframe (you can change this)
|
||||
|
||||
|
||||
|
||||
|
||||
#if SHOW_GRID
|
||||
|
||||
// **Change glBegin mode to GL_LINES for Wireframe**
|
||||
glBegin(GL_LINES);
|
||||
for (int x = 0; x < gridSize; ++x)
|
||||
{
|
||||
for (int z = 0; z < gridSize; ++z)
|
||||
{
|
||||
glm::vec3 v = ocean.getVertex(x, z);
|
||||
|
||||
// Draw horizontal lines (along Z-axis)
|
||||
if (x < gridSize - 1)
|
||||
{
|
||||
glm::vec3 v_next_x = ocean.getVertex(x + 1, z);
|
||||
glVertex3f(v.x, v.y, v.z);
|
||||
glVertex3f(v_next_x.x, v_next_x.y, v_next_x.z);
|
||||
}
|
||||
// Draw vertical lines (along X-axis)
|
||||
if (z < gridSize - 1)
|
||||
{
|
||||
glm::vec3 v_next_z = ocean.getVertex(x, z + 1);
|
||||
glVertex3f(v.x, v.y, v.z);
|
||||
glVertex3f(v_next_z.x, v_next_z.y, v_next_z.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
#endif
|
||||
|
||||
// **Re-enable Texture and Lighting (if you want to switch back to textured rendering later)**
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// glEnable(GL_LIGHTING);
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// ... (rest of Renderer.cpp - Renderer::drawBoat, Renderer::drawMesh, etc.) ...
|
||||
|
||||
void Renderer::drawBoat(const Boat &boat)
|
||||
{
|
||||
glPushMatrix();
|
||||
glm::vec3 boatPos = boat.getPosition();
|
||||
glm::quat boatRotation = boat.getRotation();
|
||||
float boatScale = boat.getScale(); // Get the boat's scale factor
|
||||
|
||||
glTranslatef(boatPos.x, boatPos.y, boatPos.z);
|
||||
glm::mat4 rotationMatrix = glm::mat4_cast(boatRotation);
|
||||
glMultMatrixf(glm::value_ptr(rotationMatrix));
|
||||
|
||||
glScalef(boatScale, boatScale, boatScale); // Uniform scaling - scale equally in all directions
|
||||
|
||||
// Load boat texture here, based on the texture path from the Boat class
|
||||
if (!boat.getTexturePath().empty())
|
||||
{
|
||||
if (boatTextureID == 0 || boat.getTexturePath() != lastBoatTexturePath)
|
||||
{ // Check if texture needs to be loaded or reloaded
|
||||
if (boatTextureID != 0)
|
||||
{ // If there's a previous texture, delete it
|
||||
glDeleteTextures(1, &boatTextureID);
|
||||
boatTextureID = 0;
|
||||
}
|
||||
if (!loadTexture(boat.getTexturePath().c_str(), boatTextureID))
|
||||
{
|
||||
std::cerr << "Error loading boat texture: " << boat.getTexturePath() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastBoatTexturePath = boat.getTexturePath(); // Store the path of the loaded texture
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, boatTextureID);
|
||||
glColor3f(1.0f, 1.0f, 1.0f); // Texture color modulation
|
||||
|
||||
// Draw the loaded boat mesh
|
||||
drawMesh(boat.getVertices(), boat.getNormals(), boat.getTexCoords(), boat.getMaterialIndices(), boat.getMaterials()); // Pass material data
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glm::vec3 minPoint = boat.getBoundingBoxMin(); // Get model-space min point
|
||||
glm::vec3 maxPoint = boat.getBoundingBoxMax(); // Get model-space max point
|
||||
|
||||
glTranslatef(boatPos.x, boatPos.y, boatPos.z);
|
||||
glMultMatrixf(glm::value_ptr(rotationMatrix));
|
||||
glScalef(boatScale, boatScale, boatScale); // Uniform scaling - scale equally in all directions
|
||||
// **Draw Wireframe Bounding Box:**
|
||||
glDisable(GL_LIGHTING); // Disable lighting for bounding box (solid color wireframe)
|
||||
glColor3f(1.0f, 1.0f, 0.0f); // Yellow color for bounding box
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Set polygon mode to line (wireframe)
|
||||
|
||||
|
||||
#if SHOW_BOUDING_BOX
|
||||
glBegin(GL_QUADS); // Draw a cube using quads (wireframe)
|
||||
|
||||
// Front face
|
||||
glVertex3f(minPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, maxPoint.z);
|
||||
glVertex3f(minPoint.x, maxPoint.y, maxPoint.z);
|
||||
|
||||
// Back face
|
||||
glVertex3f(minPoint.x, minPoint.y, minPoint.z);
|
||||
glVertex3f(maxPoint.x, minPoint.y, minPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, minPoint.z);
|
||||
glVertex3f(minPoint.x, maxPoint.y, minPoint.z);
|
||||
|
||||
// Top face
|
||||
glVertex3f(minPoint.x, maxPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, minPoint.z);
|
||||
glVertex3f(minPoint.x, maxPoint.y, minPoint.z);
|
||||
|
||||
// Bottom face
|
||||
glVertex3f(minPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, minPoint.y, minPoint.z);
|
||||
glVertex3f(minPoint.x, minPoint.y, minPoint.z);
|
||||
|
||||
// Right face
|
||||
glVertex3f(maxPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, maxPoint.z);
|
||||
glVertex3f(maxPoint.x, maxPoint.y, minPoint.z);
|
||||
glVertex3f(maxPoint.x, minPoint.y, minPoint.z);
|
||||
|
||||
// Left face
|
||||
glVertex3f(minPoint.x, minPoint.y, maxPoint.z);
|
||||
glVertex3f(minPoint.x, maxPoint.y, maxPoint.z);
|
||||
glVertex3f(minPoint.x, maxPoint.y, minPoint.z);
|
||||
glVertex3f(minPoint.x, minPoint.y, minPoint.z);
|
||||
|
||||
glEnd();
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Restore polygon mode to fill
|
||||
#endif
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
// Re-enable lighting for boat model
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::drawMeshVBO(const Ocean& ocean) {
|
||||
// 1. Bind Vertex Array Object (VAO) - if you are using VAOs. If not, bind VBOs directly.
|
||||
glBindVertexArray(ocean.getVAO()); // Assuming Ocean class has getVAO() that returns VAO ID
|
||||
|
||||
// If NOT using VAOs, you would bind VBOs individually like this:
|
||||
/*
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getVertexBufferID()); // Bind vertex VBO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getNormalBufferID()); // Bind normal VBO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getTexCoordBufferID()); // Bind texCoord VBO
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ocean.getIndexBufferID()); // Bind IBO
|
||||
*/
|
||||
|
||||
|
||||
// 2. Draw using glDrawElements (assuming you are using indexed rendering with IBO)
|
||||
glDrawElements(GL_QUADS, ocean.getIndexCount(), GL_UNSIGNED_INT, 0); // Draw using indices from IBO
|
||||
|
||||
// If drawing as triangles instead of quads, use:
|
||||
// glDrawElements(GL_TRIANGLES, ocean.getIndexCount(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
|
||||
// 3. Unbind VAO (or VBOs if not using VAOs) - optional, but good practice
|
||||
glBindVertexArray(0);
|
||||
|
||||
// If NOT using VAOs, unbind VBOs individually (optional):
|
||||
/*
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
*/
|
||||
}
|
||||
|
||||
void Renderer::drawMeshTerainVBO(const Terrain& terrain) {
|
||||
// 1. Bind Vertex Array Object (VAO) - if you are using VAOs. If not, bind VBOs directly.
|
||||
glBindVertexArray(terrain.getVAO()); // Assuming Ocean class has getVAO() that returns VAO ID
|
||||
|
||||
// If NOT using VAOs, you would bind VBOs individually like this:
|
||||
/*
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getVertexBufferID()); // Bind vertex VBO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getNormalBufferID()); // Bind normal VBO
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ocean.getTexCoordBufferID()); // Bind texCoord VBO
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ocean.getIndexBufferID()); // Bind IBO
|
||||
*/
|
||||
|
||||
|
||||
// 2. Draw using glDrawElements (assuming you are using indexed rendering with IBO)
|
||||
glDrawElements(GL_QUADS, terrain.getIndexCount(), GL_UNSIGNED_INT, 0); // Draw using indices from IBO
|
||||
|
||||
// If drawing as triangles instead of quads, use:
|
||||
// glDrawElements(GL_TRIANGLES, ocean.getIndexCount(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
|
||||
// 3. Unbind VAO (or VBOs if not using VAOs) - optional, but good practice
|
||||
glBindVertexArray(0);
|
||||
|
||||
// If NOT using VAOs, unbind VBOs individually (optional):
|
||||
/*
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
*/
|
||||
}
|
||||
|
||||
// Static variable to store the last loaded boat texture path
|
||||
|
||||
void Renderer::drawMesh(const std::vector<glm::vec3> &vertices, const std::vector<glm::vec3> &normals, const std::vector<glm::vec2> &texCoords,
|
||||
const std::vector<int> &materialIndices, const std::vector<tinyobj::material_t> &materials)
|
||||
{
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (size_t i = 0; i < vertices.size(); ++i)
|
||||
{
|
||||
int material_index = materialIndices[i];
|
||||
if (material_index != -1 && static_cast<std::vector<tinyobj::material_t>::size_type>(material_index) < materials.size())
|
||||
{ // Check if material index is valid
|
||||
const tinyobj::material_t &material = materials[material_index];
|
||||
glColor3f(material.diffuse[0], material.diffuse[1], material.diffuse[2]); // Set diffuse color
|
||||
}
|
||||
else
|
||||
{
|
||||
glColor3f(1.0f, 1.0f, 1.0f); // Default white color if no valid material
|
||||
}
|
||||
|
||||
glNormal3f(normals[i].x, normals[i].y, normals[i].z);
|
||||
glTexCoord2f(texCoords[i].x, texCoords[i].y);
|
||||
glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// Renderer.cpp - Add drawTerrain function
|
||||
void Renderer::drawTerrain(const Terrain& terrain, const Camera& camera) {
|
||||
|
||||
//printf("Drawing terrain\n");
|
||||
glPushMatrix();
|
||||
// No translation needed for terrain in this basic example
|
||||
glTranslatef(0.0f, 0.0f, 0.0f); // Lower the ocean slightly
|
||||
|
||||
// Use the terrain shader program:
|
||||
terrainShader.use();
|
||||
checkGLError("terrainShader.use");
|
||||
|
||||
glm::mat4 modelMatrix;
|
||||
glm::mat4 projectionMatrix;
|
||||
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(modelMatrix));
|
||||
checkGLError("glGetFloatv(GL_MODELVIEW_MATRIX)"); // Check after glGetFloatv
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, glm::value_ptr(projectionMatrix));
|
||||
checkGLError("glGetFloatv(GL_PROJECTION_MATRIX)"); // Check after glGetFloatv
|
||||
|
||||
terrainShader.setMat4("model", modelMatrix);
|
||||
terrainShader.setMat4("view", camera.getViewMatrix());
|
||||
terrainShader.setMat4("projection", projectionMatrix);
|
||||
terrainShader.setMat3("normalMatrix", glm::transpose(glm::inverse(glm::mat3(modelMatrix))));
|
||||
checkGLError("terrainShader setMat4/setMat3 uniforms");
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, terrainTextureID);
|
||||
terrainShader.setInt("terrainTexture", 0);
|
||||
checkGLError("glBindTexture - terrainTexture");
|
||||
|
||||
glActiveTexture(GL_TEXTURE1); // Activate texture unit 1 for heightmap
|
||||
glBindTexture(GL_TEXTURE_2D, heightMapTextureID); // Bind heightmap texture
|
||||
terrainShader.setInt("heightMapTexture", 1); // Set uniform sampler2D heightMapTexture to texture unit 1
|
||||
checkGLError("glBindTexture - heightMapTexture"); // Check after binding heightmap texture
|
||||
|
||||
// Lighting Uniforms (reuse same light parameters as ocean for simplicity)
|
||||
terrainShader.setVec3("lightDir", glm::normalize(glm::vec3(1.0f, -1.0f, 1.0f))); // Example light direction
|
||||
terrainShader.setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f)); // White light
|
||||
terrainShader.setVec3("viewPosWorld", camera.getPosition());
|
||||
checkGLError("terrainShader setVec3 uniforms");
|
||||
|
||||
|
||||
drawMeshTerainVBO(terrain); // Render terrain mesh using VBOs and IBO
|
||||
checkGLError("drawMeshVBO - terrain");
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Bind heightmap texture
|
||||
|
||||
terrainShader.unuse();
|
||||
checkGLError("terrainShader.unuse");
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0.0f, 0.0f, 0.0f); // Lower the ocean slightly
|
||||
|
||||
// **Disable Texture and Lighting for Normal Visualization**
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor3f(1.0f, 0.0f, 0.0f); // Red color for normals (you can change this)
|
||||
|
||||
|
||||
#if SHOW_NORM
|
||||
|
||||
int gridSize = terrain.getGridSize();
|
||||
float gridSpacing = terrain.getGridSpacing();
|
||||
|
||||
// **Draw Normals as Lines**
|
||||
glBegin(GL_LINES);
|
||||
for (int x = 0; x < gridSize; ++x)
|
||||
{
|
||||
for (int z = 0; z < gridSize; ++z)
|
||||
{
|
||||
glm::vec3 v = terrain.getVertex(x, z);
|
||||
glm::vec3 normal = terrain.getNormal(x, z); // Get normal at vertex
|
||||
|
||||
// Calculate endpoint of normal line - Scale normal for visibility
|
||||
float normalLength = 0.5f; // Adjust this value to control normal line length
|
||||
glm::vec3 normalEndpoint = v + normal * normalLength;
|
||||
|
||||
// Draw line representing the normal
|
||||
glVertex3f(v.x, v.y, v.z); // Start point of normal line (vertex position)
|
||||
glVertex3f(normalEndpoint.x, normalEndpoint.y, normalEndpoint.z); // End point of normal line (along normal direction)
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
#endif
|
||||
|
||||
// **Re-enable Texture and Lighting (if you want to switch back to textured rendering later)**
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// glEnable(GL_LIGHTING);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0.0f, 0.2f, 0.0f); // Lower the ocean slightly
|
||||
|
||||
// **Disable Texture and Lighting for Wireframe Rendering**
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor3f(0.0f, 0.0f, 0.0f); // Green color for wireframe (you can change this)
|
||||
|
||||
#if SHOW_GRID
|
||||
// **Change glBegin mode to GL_LINES for Wireframe**
|
||||
glBegin(GL_LINES);
|
||||
for (int x = 0; x < gridSize; ++x)
|
||||
{
|
||||
for (int z = 0; z < gridSize; ++z)
|
||||
{
|
||||
glm::vec3 v = terrain.getVertex(x, z);
|
||||
|
||||
// Draw horizontal lines (along Z-axis)
|
||||
if (x < gridSize - 1)
|
||||
{
|
||||
glm::vec3 v_next_x = terrain.getVertex(x + 1, z);
|
||||
glVertex3f(v.x, v.y, v.z);
|
||||
glVertex3f(v_next_x.x, v_next_x.y, v_next_x.z);
|
||||
}
|
||||
// Draw vertical lines (along X-axis)
|
||||
if (z < gridSize - 1)
|
||||
{
|
||||
glm::vec3 v_next_z = terrain.getVertex(x, z + 1);
|
||||
glVertex3f(v.x, v.y, v.z);
|
||||
glVertex3f(v_next_z.x, v_next_z.y, v_next_z.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
#endif
|
||||
// **Re-enable Texture and Lighting (if you want to switch back to textured rendering later)**
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// glEnable(GL_LIGHTING);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
72
windows/src/utils.cpp
Normal file
72
windows/src/utils.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* File: utils.cpp
|
||||
* Author: Tomas Goldmann
|
||||
* Date: 2025-03-23
|
||||
* Description: Utils - perlinNoise is does not use in this project
|
||||
*
|
||||
* Copyright (c) 2025, Brno University of Technology. All rights reserved.
|
||||
* Licensed under the MIT.
|
||||
*/
|
||||
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
uint64_t rdtsc() {
|
||||
return __rdtsc(); // Read Time-Stamp Counter
|
||||
}
|
||||
|
||||
void checkGLError(const char* operation) {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
std::cerr << "OpenGL Error after " << operation << ": ";
|
||||
switch (error) {
|
||||
case GL_INVALID_ENUM:
|
||||
std::cerr << "GL_INVALID_ENUM - An unacceptable value is specified for an enumerated argument.";
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
std::cerr << "GL_INVALID_VALUE - A numeric argument is out of range.";
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
std::cerr << "GL_INVALID_OPERATION - The specified operation is not allowed in the current state.";
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION - The framebuffer object is not complete.";
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
std::cerr << "GL_OUT_OF_MEMORY - There is not enough memory left to execute the command.";
|
||||
break;
|
||||
case GL_STACK_UNDERFLOW:
|
||||
std::cerr << "GL_STACK_UNDERFLOW - An attempt has been made to perform an operation that would cause the stack to underflow.";
|
||||
break;
|
||||
case GL_STACK_OVERFLOW:
|
||||
std::cerr << "GL_STACK_OVERFLOW - An attempt has been made to perform an operation that would cause a stack overflow.";
|
||||
break;
|
||||
// Add more cases for other specific OpenGL errors if needed
|
||||
default:
|
||||
std::cerr << "Unknown OpenGL error code: " << error;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Basic Perlin Noise implementation (simplified 2D version)
|
||||
float perlinNoise(float x, float y) {
|
||||
// ... (Implement Perlin noise algorithm here - this is a simplified example) ...
|
||||
// For a complete Perlin noise implementation, refer to online resources.
|
||||
// This is a placeholder for demonstration - it will produce very basic noise.
|
||||
float value = 0.0f;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float maxAmplitude = 0.0f;
|
||||
|
||||
for (int i = 0; i < 4; ++i) { // 4 octaves
|
||||
//float sampleX = x * frequency;
|
||||
//float sampleY = y * frequency;
|
||||
//value += glm::perlin(glm::vec2(sampleX, sampleY)) * amplitude; // Using glm::perlin for simplicity
|
||||
maxAmplitude += amplitude;
|
||||
amplitude *= 0.5f; // Reduce amplitude for each octave
|
||||
frequency *= 2.0f; // Increase frequency for each octave
|
||||
}
|
||||
return value / maxAmplitude; // Normalize to [0, 1] range
|
||||
}
|
18
windows/src/xlogin00.s
Normal file
18
windows/src/xlogin00.s
Normal file
@ -0,0 +1,18 @@
|
||||
.intel_syntax noprefix
|
||||
.code64
|
||||
|
||||
|
||||
.data
|
||||
|
||||
|
||||
.text
|
||||
|
||||
|
||||
.global updateVertices_simd
|
||||
updateVertices_simd:
|
||||
push rbp
|
||||
mov rbp, rsp #asm
|
||||
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
Reference in New Issue
Block a user