Corecteaza codul astfel incat traiectoria generata sa fie mai boltata sau arcuita
#include "lab_m1/tema1/tema1.h"
#include "lab_m1/tema1/transform2D.h"
#include "lab_m1/lab3/object2D.h"

using namespace std;
using namespace m1;

Tema1::Tema1() {
}

Tema1::~Tema1() {
}

float squareSide = 1;
float freq = 0.02f;


void Tema1::Init() {
    glm::ivec2 resolution = window->GetResolution();
    auto camera = GetSceneCamera();
    camera->SetOrthographic(0, (float)resolution.x, 0, (float)resolution.y, 0.01f, 400);
    camera->SetPosition(glm::vec3(0, 0, 50));
    camera->SetRotation(glm::vec3(0, 0, 0));
    camera->Update();
    GetCameraInput()->SetActive(false);

    glm::vec3 corner = glm::vec3(0, 0, 0);
    cx = corner.x + squareSide / 2;
    cy = corner.y + squareSide / 2;
    Mesh* square = object2D::CreateSquare("square", corner, squareSide, glm::vec3(0.2f, 0.7f, 0.3f), true);
    AddMeshToList(square);

    Mesh* baseTrapezoid1 = object2D::CreateTrapezoid("baseTrapezoid1", 110, 20, 100, glm::vec3(0.6f, 0.4f, 0.2f), true);
    AddMeshToList(baseTrapezoid1);
    Mesh* baseTrapezoid2 = object2D::CreateTrapezoid("baseTrapezoid2", 80, 17, 100, glm::vec3(0.2f, 0.2f, 0.6f), true);
    AddMeshToList(baseTrapezoid2);

    Mesh* circle = object2D::CreateCircle("circle", corner, 21, glm::vec3(0.6f, 0.4f, 0.2f), true);
    AddMeshToList(circle);

    Mesh* rectangle = object2D::CreateRectangle("rectangle", corner, 6.0f, 60.0f, glm::vec3(0.4f, 0.4f, 0.4f), true);
    AddMeshToList(rectangle);

    tank1X = 100;
    tank1Y = 100;
	turret1Angle = 0;

    tank2X = 1100;
    tank2Y = 100;
	turret2Angle = 0;

	projectileActive = false;
	gravity = 50.0f;
}

void Tema1::RenderTank(float x, float y, float rotationAngle, float turretAngle) {
    // Transformarea pentru centrul bazei tancului
    glm::mat3 modelMatrix;

    // Mută centrul bazei tancului în punctul de pe teren
    modelMatrix = glm::mat3(1);
    modelMatrix *= transform2D::Translate(x, y);
    modelMatrix *= transform2D::Rotate(rotationAngle);

    // Trapezul de baza
    glm::mat3 baseMatrix = modelMatrix;
    baseMatrix *= transform2D::Translate(0, 20);
    RenderMesh2D(meshes["baseTrapezoid1"], shaders["VertexColor"], baseMatrix);

    baseMatrix = modelMatrix;
    baseMatrix *= transform2D::Translate(0, 6);
    baseMatrix *= transform2D::Scale(-1, -1);
    RenderMesh2D(meshes["baseTrapezoid2"], shaders["VertexColor"], baseMatrix);

    // Turretul circular superior
    glm::mat3 turretMatrix = modelMatrix;
    turretMatrix *= transform2D::Translate(0, 28.0f);
    RenderMesh2D(meshes["circle"], shaders["VertexColor"], turretMatrix);

    //  țeava tancului
    glm::mat3 barrelMatrix = modelMatrix;
    barrelMatrix *= transform2D::Translate(0, 33.0f);
    float barrelInclineAngle = glm::radians(-45.0f);
    barrelMatrix *= transform2D::Rotate(barrelInclineAngle);
	barrelMatrix *= transform2D::Rotate(turretAngle);
    RenderMesh2D(meshes["rectangle"], shaders["VertexColor"], barrelMatrix);

    // Calculate the turret tip position
    glm::vec3 tipPosition = barrelMatrix * glm::vec3(0, 60.0f, 1);
    turretTipX = tipPosition.x;
    turretTipY = tipPosition.y;

}

float TerrainFunction(float t) {
    t *= freq;
    return 5 * sin(t) + 10 * sin(0.5f * t) + 0.5f * sin(0.5f * t);
}

float CalculateSlopeAngle(glm::vec2 A, glm::vec2 B) {
    glm::vec2 V = B - A;
    return atan2(V.y, V.x);
}

// Function to find interpolated y-position for the tank's given x-position
float CalculateTankY(float tankX, glm::vec2 A, glm::vec2 B) {
    float t = (tankX - A.x) / (B.x - A.x);
    return A.y + t * (B.y - A.y);
}

std::vector<glm::vec2> CalculateProjectilePath(glm::vec2 startPosition, float angle, float initialSpeed, float gravity, int numSegments) {
    std::vector<glm::vec2> trajectory;
    float timeStep = 0.1f; // Intervalul de timp dintre fiecare punct

    for (int i = 0; i < numSegments; ++i) {
        float t = i * timeStep;
        float x = startPosition.x + initialSpeed * cos(angle) * t;
        float y = startPosition.y + initialSpeed * sin(angle) * t - 0.3f * gravity * t * t;
        trajectory.push_back(glm::vec2(x, y));
        if (y < 0) break;
    }

    return trajectory;
}

void Tema1::RenderTrajectory(glm::vec2 startPosition, float angle, float initialSpeed, float gravity) {
    int numSegments = 50;
    std::vector<glm::vec2> trajectory = CalculateProjectilePath(startPosition, angle, initialSpeed, gravity, numSegments);

    for (size_t i = 1; i < trajectory.size(); ++i) {
        glm::vec2 p1 = trajectory[i - 1];
        glm::vec2 p2 = trajectory[i];

        modelMatrix = glm::mat3(1);
        modelMatrix *= transform2D::Translate(p1.x, p1.y);

        float segmentLength = glm::length(p2 - p1);
        float angle = atan2(p2.y - p1.y, p2.x - p1.x);
        modelMatrix *= transform2D::Rotate(angle);
        modelMatrix *= transform2D::Scale(segmentLength, 1.0f); // Lungimea liniei

        RenderMesh2D(meshes["square"], shaders["VertexColor"], modelMatrix);
    }
}

void Tema1::Update(float deltaTimeSeconds) {
	glm::ivec2 resolution1 = window->GetResolution();
    int num_points = resolution1.x;
    std::vector<float> height_map(num_points);
    

    for (int i = 0; i < num_points; i++) {
        float x = i * ((resolution1.x / num_points)/ squareSide);
        float y = 8 * TerrainFunction(i) + 300;

        height_map[i] = y;

        if (i > 0) {
            float prev_x = (i - 1) * ((resolution1.x / num_points) / squareSide);
            float prev_y = height_map[i - 1];

            modelMatrix = glm::mat3(1);
            float width = x - prev_x;
            float height = std::max(y, prev_y);

            modelMatrix *= transform2D::Translate(prev_x, prev_y);
            float sheerFactor = (y - prev_y) / (x - prev_x);
            modelMatrix *= transform2D::Sheer(sheerFactor);
            modelMatrix *= transform2D::Scale(width, -height);
           

            RenderMesh2D(meshes["square"], shaders["VertexColor"], modelMatrix);
            if (tank1X >= prev_x && tank1X <= x) {
                glm::vec2 A(prev_x, prev_y);
                glm::vec2 B(x, y);

                // Calculate the interpolated y-position of the tank on the terrain
                tank1Y = CalculateTankY(tank1X, A, B);

                // Calculate the slope angle for rotation
                float rotationAngle = CalculateSlopeAngle(A, B);
                RenderTank(tank1X, tank1Y, rotationAngle, turret1Angle);
                RenderTrajectory(glm::vec2(turretTipX, turretTipY), turret1Angle, 50.0f, 100.0f);
            }

			if (tank2X >= prev_x && tank2X <= x) {
				glm::vec2 A(prev_x, prev_y);
				glm::vec2 B(x, y);

				// Calculate the interpolated y-position of the tank on the terrain
				tank2Y = CalculateTankY(tank2X, A, B);

				// Calculate the slope angle for rotation
				float rotationAngle = CalculateSlopeAngle(A, B);
				RenderTank(tank2X, tank2Y, rotationAngle, turret2Angle);
				RenderTrajectory(glm::vec2(turretTipX, turretTipY), turret2Angle, 300.0f, gravity);
			}
        }
    }
    
}

//void Tema1::CheckProjectileCollision() {
//    if (!projectileActive) return;
//
//    // Check collision with terrain
//    for (int i = 1; i < num_points; i++) {
//        float prev_x = (i - 1) * (window->GetResolution().y / 10);
//        float prev_y = height_map[i - 1];
//        float x = i * (window->GetResolution().y / 10);
//        float y = height_map[i];
//
//        // Simple bounding box check for collision with terrain
//        if (projectilePosition.x >= prev_x && projectilePosition.x <= x &&
//            projectilePosition.y >= std::min(prev_y, y) && projectilePosition.y <= std::max(prev_y, y)) {
//            projectileActive = false;
//            break;
//        }
//    }
//
//    // Check collision with tanks (you can adjust the radius if needed)
//    float tankRadius = 25.0f;
//    glm::vec2 tank1Pos(tank1X, tank1Y);
//    glm::vec2 tank2Pos(tank2X, tank2Y);
//
//    if (glm::distance(projectilePosition, tank1Pos) < tankRadius ||
//        glm::distance(projectilePosition, tank2Pos) < tankRadius) {
//        projectileActive = false;
//        // Apply damage logic here
//    }
//}

void Tema1::FrameStart()
{
    glClearColor(0.52f, 0.81f, 0.92f, 1);  // Light blue background
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::ivec2 resolution = window->GetResolution();
    glViewport(0, 0, resolution.x, resolution.y);
}

void Tema1::FrameEnd()
{
}

void Tema1::OnInputUpdate(float deltaTime, int mods)
{
    if (window->KeyHold(GLFW_KEY_A)) {
        tank1X -= 200 * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_D)) {
        tank1X += 200 * deltaTime;
    }

	if (window->KeyHold(GLFW_KEY_LEFT)) {
		tank2X -= 200 * deltaTime;
	}

	if (window->KeyHold(GLFW_KEY_RIGHT)) {
		tank2X += 200 * deltaTime;
	}

    if (window->KeyHold(GLFW_KEY_W) && turret1Angle <= glm::pi<float>() / 1.5) {
        turret1Angle += 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_S) && turret1Angle > -0.5) {
        turret1Angle -= 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_UP) && turret2Angle < glm::pi<float>() / 1.5) {
        turret2Angle += 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_DOWN) && turret2Angle > -0.5) {
        turret2Angle -= 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_SPACE) && !projectileActive) {
        // Launch projectile for Tank1
        projectileActive = true;
        projectilePosition = glm::vec2(turretTipX, turretTipY);
        projectileVelocity = glm::vec2(cos(turret1Angle), sin(turret1Angle)) * 300.0f;
    }
    else if (window->KeyHold(GLFW_KEY_ENTER) && !projectileActive) {
        projectileActive = true;
        projectilePosition = glm::vec2(turretTipX, turretTipY);
        projectileVelocity = glm::vec2(cos(turret2Angle), sin(turret2Angle)) * 300.0f;
    }
}


void Tema1::OnKeyPress(int key, int mods)
{
    // Add key press event
}


void Tema1::OnKeyRelease(int key, int mods)
{
    // Add key release event
}


void Tema1::OnMouseMove(int mouseX, int mouseY, int deltaX, int deltaY)
{
    // Add mouse move event
}


void Tema1::OnMouseBtnPress(int mouseX, int mouseY, int button, int mods)
{
    // Add mouse button press event
}


void Tema1::OnMouseBtnRelease(int mouseX, int mouseY, int button, int mods)
{
    // Add mouse button release event
}


void Tema1::OnMouseScroll(int mouseX, int mouseY, int offsetX, int offsetY)
{
}


void Tema1::OnWindowResize(int width, int height)
{
}