(1)SDL::窗口/绘图

https://wiki.libsdl.org/SDL3/FrontPage
1.01 创建窗口/绘图
#include <SDL.h>
#include <iostream>

int main(int argc, char* argv[]) {
    // 1. 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cerr << "SDL 初始化失败: " << SDL_GetError() << std::endl;
        return -1;
    }
    
    auto resoult = SDL_WasInit(SDL_INIT_VIDEO);

    // 2. 创建窗口
    SDL_Window* window = SDL_CreateWindow(
        "SDL2 入门",              // 窗口标题
        SDL_WINDOWPOS_CENTERED,   // X 位置(居中)
        SDL_WINDOWPOS_CENTERED,   // Y 位置
        800,                      // 宽度
        600,                      // 高度
        SDL_WINDOW_SHOWN          // 窗口标志
    );

    if (!window) {
        std::cerr << "窗口创建失败: " << SDL_GetError() << std::endl;
        SDL_Quit();
        return -1;
    }

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        std::cerr << "渲染器创建失败: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(window);
        SDL_Quit();
        return -1;
    }

    bool isquit = false;
    SDL_Event event;
    while (!isquit)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT) {
                isquit = true;
            }
        }

        // 设置透明
        SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);

        // 设置背景色为蓝色
        //  - RGBA 
        //  - CMYK - Red Yellow Blue
        //  - HSV 
        //  - YUV 
        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);  // RGBA
        SDL_RenderClear(renderer);

        // 绘制一个点
        SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);  
        SDL_RenderDrawPoint(renderer, 100, 100);

        SDL_Rect rect{ .x = 100, .y = 100, .w = 100, .h = 100 };
        //SDL_RenderDrawRect(renderer, &rect);// 绘制矩形
        SDL_RenderFillRect(renderer, &rect);// 绘制填充的矩形
        // 等等。。。

        SDL_RenderPresent(renderer);
    }

    // 4. 清理资源
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
1.02 SDL_Surface与SDL_Texture(绘制.bmp)
#include <SDL.h>
#include <iostream>

int main(int argc, char* argv[]) {
    // 1. 初始化 SDL 子系统
    // SDL_INIT_VIDEO 表示只初始化视频(窗口、渲染)子系统
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cerr << "SDL 初始化失败: " << SDL_GetError() << std::endl;
        return -1;
    }

    // 获取成功初始化了 VIDEO 子系统
    auto result = SDL_WasInit(SDL_INIT_VIDEO);  // 返回已初始化的标志位
    if (result & SDL_INIT_VIDEO) {
        std::cout << "SDL 视频子系统已成功初始化" << std::endl;
    }

    // 2. 创建主窗口
    // 参数说明:
    // - 标题:"SDL2 入门"
    // - x/y 位置:居中显示
    // - 宽度、高度
    // - 窗口标志:SDL_WINDOW_SHOWN(创建后立即显示)
    SDL_Window* window = SDL_CreateWindow(
        "SDL2 入门",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        800,
        600,
        SDL_WINDOW_SHOWN
    );

    // 检查窗口是否创建成功
    if (!window) {
        std::cerr << "窗口创建失败: " << SDL_GetError() << std::endl;
        SDL_Quit();  // 清理 SDL 资源
        return -1;
    }

    // 3. 创建渲染器(Renderer)
    // 渲染器用于在窗口上绘制图形、纹理等
    // - 关联窗口:window
    // - 渲染驱动:-1(自动选择最佳驱动)
    // - 标志:SDL_RENDERER_ACCELERATED(使用 GPU 加速)
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        std::cerr << "渲染器创建失败: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(window);  // 销毁窗口
        SDL_Quit();
        return -1;
    }

    // 4. 加载 BMP 图像文件为 Surface(CPU 内存中的图像数据)
    SDL_Surface* surface = SDL_LoadBMP("resources/number_8.bmp");
    if (!surface) {
        std::cerr << "图片加载失败: " << SDL_GetError() << std::endl;
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        SDL_Quit();
        return -1;
    }

    // 获取图片原始宽度和高度
    int w = surface->w;
    int h = surface->h;

    // 5. 将 Surface 转换为 Texture(GPU 内存中的纹理)
    // Texture 可以被高效渲染到屏幕上
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    if (!texture) {
        std::cerr << "纹理创建失败: " << SDL_GetError() << std::endl;
        SDL_FreeSurface(surface);           // 释放 Surface
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        SDL_Quit();
        return -1;
    }

    // Surface 已经上传到 GPU,可以安全释放 CPU 端数据
    SDL_FreeSurface(surface);

    // 6. 主循环控制变量
    float degree = 0;           // 用于控制旋转角度(每帧递增)
    bool isquit = false;        // 控制主循环是否退出
    SDL_Event event;            // 用于存储事件

    // 7. 主循环:持续渲染画面并处理事件
    while (!isquit) {
        // 事件处理:检查是否有用户输入或系统事件
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                isquit = true;  // 用户点击关闭窗口,退出循环
            }
        }

        // 8. 清屏:设置背景色为黑色,并清除渲染器内容
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);  // RGBA: 黑色不透明
        SDL_RenderClear(renderer);

        // 9. 更新逻辑:每帧旋转角度增加 1 度
        degree += 1;
        if (degree >= 360) degree -= 360;  // 可选:保持角度在 0~360 范围内

        // 10. 定义目标矩形(图片在屏幕上的显示位置和大小)
        SDL_Rect dstrect;
        dstrect.x = 200;        // 左上角 X 坐标
        dstrect.y = 200;        // 左上角 Y 坐标
        dstrect.w = w;          // 宽度(使用原图宽度)
        dstrect.h = h;          // 高度(使用原图高度)

        // 11. 设置旋转中心点(相对于纹理左上角)
        SDL_Point rotateCenter = { w, h };  // 旋转中心设为右下角(w, h)
        // 注意:如果想绕中心旋转,应设为 { w/2, h/2 }

        // 12. 渲染纹理(多种方式,当前启用的是翻转渲染)
        
        // 方式一:普通渲染(无旋转/翻转)
        // SDL_RenderCopy(renderer, texture, NULL, &dstrect);

        // 方式二:带旋转和中心点的渲染
        // SDL_RenderCopyEx(renderer, texture, NULL, &dstrect, degree, &rotateCenter, SDL_FLIP_NONE);

        // 方式三:当前启用 —— 垂直翻转渲染(上下翻转),无旋转
        SDL_RenderCopyEx(renderer, texture, NULL, &dstrect, 0, NULL, SDL_FLIP_VERTICAL);

        // 13. 显示渲染结果到屏幕(双缓冲机制)
        // SDL_RenderPresent 将后台缓冲区内容交换到前台显示
        SDL_RenderPresent(renderer);

        // 可选:控制帧率,避免 CPU/GPU 过载
        // SDL_Delay(16);  // 约 60 FPS
    }

    // 14. 清理资源(重要!防止内存泄漏)
    SDL_DestroyTexture(texture);      // 销毁纹理
    SDL_DestroyRenderer(renderer);    // 销毁渲染器
    SDL_DestroyWindow(window);        // 销毁窗口
    SDL_Quit();                       // 关闭 SDL 子系统

    return 0;
}
1.03 SDL_Surface与SDL_Texture(绘制一个区域)
#include <SDL.h>
#include <iostream>

int main(int argc, char* argv[]) {
    // 1. 初始化 SDL 视频子系统
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cerr << "SDL 初始化失败: " << SDL_GetError() << std::endl;
        return -1;
    }

    // 2. 创建窗口
    // 窗口标题:"SDL2 入门"
    // 位置:居中
    // 尺寸:800x600
    // 标志:显示 + 可调整大小
    SDL_Window* window = SDL_CreateWindow(
        "SDL2 入门",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        800,
        600,
        SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE  // 支持窗口缩放
    );

    // 3. 创建渲染器
    // 第二个参数:-1 表示自动选择最佳渲染驱动
    // 第三个参数:0 表示让 SDL 自动选择最佳渲染标志(可能是硬件加速)
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer) {
        std::cerr << "渲染器创建失败: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(window);
        SDL_Quit();
        return -1;
    }

    
    //SDL_Surface* surface_1 = SDL_CreateRGBSurfaceWithFormat(0, 200, 300, 16, SDL_PIXELFORMAT_RGB565);
    //// 格式转换
    //SDL_Surface* surface_new = SDL_ConvertSurfaceFormat(surface_1, SDL_PIXELFORMAT_RGBA8888, 0);

    // 4. 创建一个 SDL_Surface(CPU 内存中的图像)
    // 参数说明:
    // - flags: 0(无特殊标志)
    // - width: 200 像素
    // - height: 300 像素
    // - depth: 32 位色深(RGBA 各占 8 位)
    // - format: 使用 RGBA8888 格式(每个像素 4 字节)
    SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(
        0,                    // flags
        200,                  // 宽
        300,                  // 高
        32,                   // 位深
        SDL_PIXELFORMAT_RGBA8888  // 像素格式
    );

    // 检查是否创建成功
    if (!surface) {
        std::cerr << "Surface 创建失败: " << SDL_GetError() << std::endl;
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        SDL_Quit();
        return -1;
    }

    // 5. 使用白色填充整个 Surface
    // SDL_MapRGBA: 根据 surface 的像素格式,将 RGBA 值转换为对应整数
    // NULL 表示填充整个区域
    SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255));

    // 6. 直接操作像素数据:将上半部分改为绿色
    Uint32* ptr = (Uint32*)surface->pixels;  // 获取像素数据起始指针(RGBA8888 下每像素 4 字节)
    
    // pitch 是每行字节数(不是像素数),但这里我们知道是 200 * 4 = 800 字节
    SDL_Log("pitch = %d", surface->pitch);  // 输出:800(200 像素 * 4 字节)

    // 循环修改前一半像素(上半图)为绿色
    for (int i = 0; i < surface->w * surface->h / 2; i++) {
        *ptr = SDL_MapRGBA(surface->format, 0, 255, 0, 255);  // 绿色,不透明
        ptr++;  // 移动到下一个像素
    }

    // 7. 将 Surface 转换为 GPU 纹理(Texture)
    // Texture 可被高效渲染到屏幕上
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);


    // 8. 释放 CPU 端的 Surface(数据已上传到 GPU)
    SDL_FreeSurface(surface);

    // 9. 查询纹理的原始尺寸(用于渲染时参考)
    int w, h;
    SDL_QueryTexture(texture, NULL, NULL, &w, &h);  // 获取纹理宽高
    SDL_Log("纹理尺寸: %d x %d", w, h);  // 输出:200 x 300

    // 10. 主循环控制变量
    bool isquit = false;
    SDL_Event event;

    // 11. 主循环:事件处理 + 渲染
    while (!isquit) {
        // 事件轮询
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                isquit = true;  // 用户点击关闭按钮
            }
        }

        // 清屏:设置背景为黑色
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        // 定义目标渲染区域(dstrect)
        SDL_Rect dstrect;
        dstrect.x = 100;        // 屏幕 X 坐标
        dstrect.y = 100;        // 屏幕 Y 坐标
        dstrect.w = 200;        // 宽度(与纹理一致)
        dstrect.h = 300;        // 高度(与纹理一致)

        // 12. 渲染纹理到目标区域
        SDL_RenderCopy(renderer, texture, NULL, &dstrect);

        // 13. 重置渲染目标(确保渲染到屏幕)
        // 在使用离屏渲染(Render Target)时需要,此处可省略,但保留无害
        SDL_SetRenderTarget(renderer, NULL);

        // 14. 显示渲染结果(双缓冲交换)
        SDL_RenderPresent(renderer);

        // 可选:控制帧率,避免 CPU 占用过高
        // SDL_Delay(16);  // 约 60 FPS
    }

    // 15. 清理资源(重要!防止内存泄漏)
    SDL_DestroyTexture(texture);      // 销毁纹理
    SDL_DestroyRenderer(renderer);    // 销毁渲染器
    SDL_DestroyWindow(window);        // 销毁窗口
    SDL_Quit();                       // 关闭 SDL 子系统

    return 0;
}
1.04 SDL_Image拓展库,加载其他格式图片
posted @ 2019-06-01 13:54  osbreak  阅读(146)  评论(0)    收藏  举报