// ECamera.c
#include "ECamera.h"
#include <math.h>

// Линейная интерполяция между a и b на t
static float lerp(float a, float b, float t) {
    return a + (b - a) * t;
}

void Camera_Init(Camera* cam, int windowW, int windowH, int imgW, int imgH) {
    // Расчет минимального зума, чтобы окно просмотра не превышало размер изображения
    float minZoomWidth = (float)windowW / imgW;
    float minZoomHeight = (float)windowH / imgH;
    cam->minZoom = minZoomWidth > minZoomHeight ? minZoomWidth : minZoomHeight;

    cam->zoom = cam->minZoom;
    cam->targetZoom = cam->zoom;
    cam->maxZoom = 3.0f; // Можно настроить по необходимости

    // Установка начальной позиции камеры в центр изображения
    cam->x = (imgW - windowW / cam->zoom) / 2.0f;
    cam->y = (imgH - windowH / cam->zoom) / 2.0f;

    cam->windowWidth = windowW;
    cam->windowHeight = windowH;
    cam->imageWidth = imgW;
    cam->imageHeight = imgH;
}

void Camera_SetTargetZoom(Camera* cam, float zoom) {
    if (zoom < cam->minZoom)
        zoom = cam->minZoom;
    if (zoom > cam->maxZoom)
        zoom = cam->maxZoom;
    cam->targetZoom = zoom;
}

void Camera_Update(Camera* cam, float deltaTime) {
    // Параметры плавности
    float zoomSpeed = 5.0f; // Скорость изменения масштаба

    // Плавное изменение зума с использованием LERP
    if (fabsf(cam->targetZoom - cam->zoom) > 0.001f) {
        cam->zoom = lerp(cam->zoom, cam->targetZoom, zoomSpeed * deltaTime);

        // Ограничение зума
        if ((cam->zoom > cam->targetZoom && cam->zoom < cam->targetZoom + 0.001f) ||
            (cam->zoom < cam->targetZoom && cam->zoom > cam->targetZoom - 0.001f)) {
            cam->zoom = cam->targetZoom;
        }

        // После зумирования необходимо ограничить позицию камеры
        float viewW = cam->windowWidth / cam->zoom;
        float viewH = cam->windowHeight / cam->zoom;

        if (cam->x < 0)
            cam->x = 0;
        if (cam->y < 0)
            cam->y = 0;
        if (cam->x + viewW > cam->imageWidth)
            cam->x = cam->imageWidth - viewW;
        if (cam->y + viewH > cam->imageHeight)
            cam->y = cam->imageHeight - viewH;
    }
}

void Camera_Move(Camera* cam, float dx, float dy) {
    // Скорость перемещения обратно-пропорциональна зуму
    float speed = 1.0f / cam->zoom;
    cam->x += dx * speed;
    cam->y += dy * speed;

    // Ограничение перемещения камеры внутри границ изображения
    float viewW = cam->windowWidth / cam->zoom;
    float viewH = cam->windowHeight / cam->zoom;

    if (cam->x < 0)
        cam->x = 0;
    if (cam->y < 0)
        cam->y = 0;
    if (cam->x + viewW > cam->imageWidth)
        cam->x = cam->imageWidth - viewW;
    if (cam->y + viewH > cam->imageHeight)
        cam->y = cam->imageHeight - viewH;
}

SDL_Rect Camera_GetViewRect(Camera* cam) {
    SDL_Rect view;
    view.x = (int)cam->x;
    view.y = (int)cam->y;
    view.w = (int)(cam->windowWidth / cam->zoom);
    view.h = (int)(cam->windowHeight / cam->zoom);

    // Корректировка, если размер выходит за границы изображения
    if (view.x + view.w > cam->imageWidth) {
        view.x = cam->imageWidth - view.w;
    }
    if (view.y + view.h > cam->imageHeight) {
        view.y = cam->imageHeight - view.h;
    }
    if (view.x < 0) view.x = 0;
    if (view.y < 0) view.y = 0;

    return view;
}
// ECamera.h
#ifndef ECAMERA_H
#define ECAMERA_H

#include <SDL2/SDL.h>

// Структура камеры
typedef struct {
    float x, y;          // Позиция камеры
    float zoom;          // Текущий масштаб
    float targetZoom;    // Целевой масштаб для плавного зума
    float minZoom;       // Минимальный масштаб
    float maxZoom;       // Максимальный масштаб
    int windowWidth;     // Ширина окна
    int windowHeight;    // Высота окна
    int imageWidth;      // Ширина изображения
    int imageHeight;     // Высота изображения
} Camera;

// Инициализация камеры
void Camera_Init(Camera* cam, int windowW, int windowH, int imgW, int imgH);

// Обновление параметров камеры (плавный зум)
void Camera_Update(Camera* cam, float deltaTime);

// Изменение масштаба
void Camera_SetTargetZoom(Camera* cam, float zoom);

// Перемещение камеры с учетом скорости
void Camera_Move(Camera* cam, float dx, float dy);

// Получение SDL_Rect для рендеринга
SDL_Rect Camera_GetViewRect(Camera* cam);

#endif // ECAMERA_H
// MapEditor.c
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "ECamera.h"
#include <stdio.h>
#include <stdbool.h>

// Размер окна
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

int main(int argc, char* argv[]) {
    // Инициализация SDL
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("SDL_Init Error: %s\n", SDL_GetError());
        return 1;
    }

    // Инициализация SDL_image с поддержкой PNG и JPEG
    if (!(IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) & (IMG_INIT_PNG | IMG_INIT_JPG))) {
        printf("IMG_Init Error: %s\n", IMG_GetError());
        SDL_Quit();
        return 1;
    }

    // Создание окна
    SDL_Window* window = SDL_CreateWindow("Map Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                          WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
    if (!window) {
        printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
        IMG_Quit();
        SDL_Quit();
        return 1;
    }

    // Создание рендерера с вертикальной синхронизацией для плавного рендеринга
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!renderer) {
        printf("SDL_CreateRenderer Error: %s\n", SDL_GetError());
        SDL_DestroyWindow(window);
        IMG_Quit();
        SDL_Quit();
        return 1;
    }

    // Загрузка изображения
    SDL_Surface* bgSurface = IMG_Load("./map/world/background.png");
    if (!bgSurface) {
        printf("IMG_Load Error: %s\n", IMG_GetError());
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        IMG_Quit();
        SDL_Quit();
        return 1;
    }

    // Создание текстуры из поверхности
    SDL_Texture* bgTexture = SDL_CreateTextureFromSurface(renderer, bgSurface);
    if (!bgTexture) {
        printf("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
        SDL_FreeSurface(bgSurface);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        IMG_Quit();
        SDL_Quit();
        return 1;
    }

    int imgWidth = bgSurface->w;
    int imgHeight = bgSurface->h;
    SDL_FreeSurface(bgSurface); // Поверхность больше не нужна

    // Инициализация камеры
    Camera cam;
    Camera_Init(&cam, WINDOW_WIDTH, WINDOW_HEIGHT, imgWidth, imgHeight);

    bool running = true;
    SDL_Event event;

    bool dragging = false;
    int lastMouseX, lastMouseY;

    Uint32 lastTime = SDL_GetTicks();

    while (running) {
        // Обработка событий
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    running = false;
                    break;
                case SDL_MOUSEWHEEL:
                    {
                        // Координаты центра окна
                        int centerX = WINDOW_WIDTH / 2;
                        int centerY = WINDOW_HEIGHT / 2;

                        // Позиция центра в мировой системе координат до зума
                        float preZoomWorldX = cam.x + centerX / cam.zoom;
                        float preZoomWorldY = cam.y + centerY / cam.zoom;

                        // Изменение целевого зума
                        float zoomFactor = 1.1f;
                        if (event.wheel.y < 0)
                            zoomFactor = 1.0f / zoomFactor;

                        // Установка нового целевого зума
                        float newTargetZoom = cam.targetZoom * zoomFactor;
                        Camera_SetTargetZoom(&cam, newTargetZoom);

                        // Позиция центра в мировой системе координат после зума
                        float postZoomWorldX = cam.x + centerX / cam.targetZoom;
                        float postZoomWorldY = cam.y + centerY / cam.targetZoom;

                        // Корректировка позиции камеры, чтобы центр оставался на месте
                        cam.x += preZoomWorldX - postZoomWorldX;
                        cam.y += preZoomWorldY - postZoomWorldY;

                        // Ограничение позиции камеры
                        float viewW = cam.windowWidth / cam.targetZoom;
                        float viewH = cam.windowHeight / cam.targetZoom;

                        if (cam.x < 0)
                            cam.x = 0;
                        if (cam.y < 0)
                            cam.y = 0;
                        if (cam.x + viewW > cam.imageWidth)
                            cam.x = cam.imageWidth - viewW;
                        if (cam.y + viewH > cam.imageHeight)
                            cam.y = cam.imageHeight - viewH;
                    }
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    if (event.button.button == SDL_BUTTON_LEFT) {
                        dragging = true;
                        lastMouseX = event.button.x;
                        lastMouseY = event.button.y;
                    }
                    break;
                case SDL_MOUSEBUTTONUP:
                    if (event.button.button == SDL_BUTTON_LEFT) {
                        dragging = false;
                    }
                    break;
                case SDL_MOUSEMOTION:
                    if (dragging) {
                        int dx = event.motion.x - lastMouseX;
                        int dy = event.motion.y - lastMouseY;
                        Camera_Move(&cam, -dx, -dy);
                        lastMouseX = event.motion.x;
                        lastMouseY = event.motion.y;
                    }
                    break;
                default:
                    break;
            }
        }

        // Расчет deltaTime
        Uint32 currentTime = SDL_GetTicks();
        float deltaTime = (currentTime - lastTime) / 1000.0f; // в секундах
        lastTime = currentTime;

        // Обновление камеры
        Camera_Update(&cam, deltaTime);

        // Очистка экрана
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        // Получение области видимости
        SDL_Rect srcRect = Camera_GetViewRect(&cam);
        SDL_Rect destRect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};

        // Рендеринг изображения
        SDL_RenderCopy(renderer, bgTexture, &srcRect, &destRect);

        // Обновление экрана
        SDL_RenderPresent(renderer);
    }

    // Очистка ресурсов
    SDL_DestroyTexture(bgTexture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}

Сделай так, чтобы в этом коде камера приближалась не двигаясь в сторону курсора, а приближалась уменьшаясь вокруг курсора, только если он находится внутри окна.