第15章 《乐趣》Page355~375 纹理,渲染器,代码简化版

运行效果:全屏了

简化之后的代码如下:

//main.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include "sdl_initiator.hpp"
#include "sdl_error.hpp"
#include "sdl_window.hpp"
#include "sdl_surface.hpp"
#include "sdl_renderer.hpp"
#include "sdl_texture.hpp"

using namespace std;

//加载图片为纹理,并设置透明色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                           , char const* filename
                           , Uint8 key_r, Uint8 key_g, Uint8 key_b)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }
    bmp.EnableColorKey(key_r, key_g, key_b, 0);
    return sdl2::Texture(renderer, bmp._surface).Release();
}
//加载图片为纹理,不透明,不混色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                            , char const* filename)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }

    return sdl2::Texture(renderer, bmp._surface).Release();
}
//加载图片为纹理,并设置透明色和混色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                , char const* filename
                , Uint8 key_r, Uint8 key_g, Uint8 key_b
                , Uint8 alpha_mod
                , SDL_BlendMode blend_mode = SDL_BLENDMODE_BLEND)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }
    bmp.EnableColorKey(key_r, key_g, key_b, 0);
    bmp.SetAlphaMod(alpha_mod);
    bmp.SetBlendMode(blend_mode);
    return sdl2::Texture(renderer, bmp._surface).Release();
}
int main(int argc, char* argv[])
{
    sdl2::Initiator::Instance().Init(SDL_INIT_VIDEO
                                     | SDL_INIT_AUDIO
                                     | SDL_INIT_EVENTS
                                     | SDL_INIT_TIMER);

    if(!sdl2::Initiator::Instance())//重载转换符
    {
        cerr << "初始化就出错,没得玩了!"
             << sdl2::last_error() << endl;
    }

    //创建并居中显示宽640,高480的游戏窗口
    sdl2::Window wnd("hello sdl"
                     , sdl2::WindowPosition()
                     , 640, 480
                     //使用空的特性标志
                     , sdl2::WindowFlags().FullScreenDesktop());

    if(!wnd)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备窗口的渲染器
    sdl2::Renderer renderer(wnd._window);
    if(!renderer)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }
    //重要!修改缩放质量配置
    sdl2::RendererDriver::HintScaleQuality();
    //重要!设置虚拟大小
    renderer.SetLogicalSize(640, 480);

    //准备背景图(不需要透明和混色)
    sdl2::Texture bkgnd(LoadBMPTexture(renderer._renderer, "bkgnd.bmp"));

    if(!bkgnd)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备小马图,透明色为白色
    sdl2::Texture horse(LoadBMPTexture(renderer._renderer
                                       , "sdl.bmp"
                                       , 0xff, 0xff, 0xff));
    if(!horse)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备白云图纹理,透明色为红色,不透明度188(0~255)
    sdl2::Texture cloud(LoadBMPTexture(renderer._renderer
                                       , "cloud.bmp"
                                       , 0xff, 0, 0, 188));
    if(!cloud)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }
    //事件循环
    bool Q = false;
    while(!Q)//一直循环,直到Q为真
    {
        SDL_Event event;
        //会将队列中拖出的event数据存储到event中
        while(SDL_PollEvent(&event))
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    Q = true;
                    break;
            }
        }//内循环

        /*外循环:贴骏马图*/
        //贴背景->窗口
        renderer.CopyFrom(bkgnd._texture);

        //贴第一朵白云
        SDL_Rect cloud_rect_1{200, 20, 156, 78};
        renderer.CopyFrom(cloud._texture, nullptr, &cloud_rect_1);

        //贴第二朵白云
        SDL_Rect cloud_rect_2{340, 6, 156, 78};
        renderer.CopyFrom(cloud._texture, nullptr, &cloud_rect_2);
        //贴骏马
        SDL_Rect dst_rect{86, 65, 468, 350};
        renderer.CopyFrom(horse._texture, nullptr, &dst_rect);

        renderer.Present();
        SDL_Delay(1);//防止cpu占用率太高
//        Q = true; //开发过程中,为方便程序退出,暂时这样
    }//外循环

    return 0;
}

//sdl_error.cpp
#include "sdl_error.hpp"

namespace sdl2
{

char const* last_error()
{
    return SDL_GetError();
}

}//sdl2

//sdl_error.hpp
#ifndef SDL_ERROR_HPP_INCLUDED
#define SDL_ERROR_HPP_INCLUDED
#include <SDL2/SDL.h>

namespace sdl2
{
char const* last_error();
}


#endif // SDL_ERROR_HPP_INCLUDED

//sdl_initiator.hpp
#ifndef SDL_INITIATOR_HPP_INCLUDED
#define SDL_INITIATOR_HPP_INCLUDED

namespace sdl2
{

struct Initiator
{
private: //单例模式,外界无需使用构造函数
    Initiator()
        : _init_result(-1)
    {

    }

public:
    static Initiator& Instance()
    {
        static Initiator Instance;
        return Instance;
    }

    ~Initiator()
    {
        SDL_Quit();
    }

    void GetVersion(Uint8& major, Uint8& minor, Uint8& patch)
    {
        SDL_version ver;
        SDL_GetVersion(&ver);

        major = ver.major;
        minor = ver.minor;
        patch = ver.patch;
    }

    bool Init(Uint32 flags = SDL_INIT_EVERYTHING)
    {
        _init_result = SDL_Init(flags);
        return 0 == _init_result;
    }

//    bool operator bool()
    explicit operator bool() const
    {
        return _init_result == 0;
    }

private:
    int _init_result;
};//Initiator

}//sdl2

#endif // SDL_INITIATOR_HPP_INCLUDED

//sdl_renderer.hpp
#ifndef SDL_RENDERER_HPP_INCLUDED
#define SDL_RENDERER_HPP_INCLUDED

namespace sdl2
{
//渲染驱动(方法均为静态)
struct RendererDriver
{
    static bool HintScaleQuality(char const* quality = "linear")
    {
        return SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality);
    }
};

struct Renderer
{
    Renderer(SDL_Window* window, int index = -1, Uint32 flags = 0)
    {
        _renderer = SDL_CreateRenderer(window, index, flags);
    }

    ~Renderer()
    {
        SDL_assert(_renderer != nullptr);
        SDL_DestroyRenderer(_renderer);
    }

    bool SetLogicalSize(int w, int h)
    {
        SDL_assert(_renderer != nullptr);
        return 0 == SDL_RenderSetLogicalSize(_renderer, w, h);
    }

    bool CopyFrom(SDL_Texture* src_texture
                  , const SDL_Rect* src_rect = nullptr
                  , const SDL_Rect* dst_rect = nullptr)
    {
        SDL_assert(_renderer != nullptr);
        SDL_assert(src_texture != nullptr);
        return 0 == SDL_RenderCopy(_renderer, src_texture, src_rect, dst_rect);
    }

    void Present()
    {
        SDL_assert(_renderer != nullptr);
        SDL_RenderPresent(_renderer);
    }
    explicit operator bool() const
    {
        return _renderer != nullptr;
    }

    SDL_Renderer* _renderer;
};//Renderer

}//sdl2

#endif // SDL_RENDERER_HPP_INCLUDED

//sdl_surface.hpp
#ifndef SDL_SURFACE_HPP_INCLUDED
#define SDL_SURFACE_HPP_INCLUDED

namespace sdl2
{

struct Surface
{

    //代管外部创建好的surface指针
    explicit Surface(SDL_Surface* surface)
        : _surface(surface)
    {

    }
    /*父类的析构函数使用虚函数的主要原因是为了确保多态时的正确清理。
      在C++中,析构函数主要用于释放动态分配的资源。如果父类的析构函数不是虚函数,
      那么当使用子类指针删除父类对象时,由于没有动态绑定(晚绑定),
      只会调用父类的析构函数,而不会调用子类的析构函数。
      这样,子类中的资源可能不会被正确释放,导致内存泄漏或其他问题。

     如果父类的析构函数是虚函数,那么当使用子类指针删除父类对象时,
     会根据实际对象的类型动态调用相应的析构函数。这样,既可以释放父类占用的资源,
     又可以释放子类占用的资源,确保资源的正确释放。
     因此,为了确保多态时的正确清理,父类的析构函数应该声明为虚函数。*/
    virtual ~Surface()
    {
        SDL_assert(_surface != nullptr);
        SDL_FreeSurface(_surface);
    };

    bool SetAlphaMod(Uint8 alpha)
    {
        SDL_assert(_surface != nullptr);
        return 0 == SDL_SetSurfaceAlphaMod(_surface, alpha);
    }

    bool SetBlendMode(SDL_BlendMode const& mode)
    {
        SDL_assert(_surface != nullptr);
        return 0 == SDL_SetSurfaceBlendMode(_surface, mode);
    }

    //    EnableColorKey(Uint32 r, Uint32 g, Uint32 b, Uint32 a)
    bool EnableColorKey(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
    {
        SDL_assert(_surface != nullptr);
        Uint32 key = SDL_MapRGBA(_surface->format, r, g, b, a);
        return 0 == SDL_SetColorKey(_surface, SDL_TRUE, key);
    }

    bool BlitTo(SDL_Surface* dst_surface, SDL_Rect* src_rect, SDL_Rect* dst_rect)
    {
        SDL_assert(_surface != nullptr);
        return 0 == SDL_BlitSurface(_surface, src_rect, dst_surface, dst_rect);
    }

    explicit operator bool() const
    {
        return _surface != nullptr;
    }

    SDL_Surface* _surface;
};

//来自位图的表层
struct BitmapSurface : public Surface
{
    explicit BitmapSurface (char const* filename)
        : Surface(SDL_LoadBMP(filename))
    {

    }
};

}//sdl2

#endif // SDL_SURFACE_HPP_INCLUDED

//sdl_texture.hpp
#ifndef SDL_TEXTURE_HPP_INCLUDED
#define SDL_TEXTURE_HPP_INCLUDED

namespace sdl2
{

struct Texture
{
    Texture(SDL_Texture* texture)
        : _texture(texture)
    {

    }

    Texture(SDL_Renderer* renderer, SDL_Surface* surface)
        : _texture(SDL_CreateTextureFromSurface(renderer, surface))
    {

    }

    ~Texture()
    {
//        SDL_assert(_texture != nullptr);
        //_texture不一定就不空,所以需要修改
        if(_texture)
        SDL_DestroyTexture(_texture);
    }

    SDL_Texture* Release()
    {
        SDL_Texture* tmp;
        tmp = _texture;
//        *tmp = *_texture; //tmp和_texture已经指向同一数据了
        _texture = nullptr;
        return tmp;
    }

    explicit operator bool() const
    {
        return _texture != nullptr;
    }

    SDL_Texture* _texture;
};//Texture

}//sdl2

#endif // SDL_TEXTURE_HPP_INCLUDED

//sdl_window.hpp
#ifndef SDL_WINDOW_HPP_INCLUDED
#define SDL_WINDOW_HPP_INCLUDED

#include <SDL2/SDL.h>

namespace sdl2
{

struct WindowPosition
{
    WindowPosition()//默认构造
        : _x(SDL_WINDOWPOS_CENTERED), _y(SDL_WINDOWPOS_CENTERED)
    {

    }

    WindowPosition(int x, int y)//常规初始化
        : _x(x), _y(y)
    {

    }

    ~WindowPosition()
    {

    }

    WindowPosition& Centered(bool x_centered = true
                             , bool y_centered = true)
    {
        if(x_centered)
            _x = SDL_WINDOWPOS_CENTERED;
        if(y_centered)
            _y = SDL_WINDOWPOS_CENTERED;
    }

    int _x, _y;
};

struct WindowFlags
{
    //默认构造,用于构建一个没有指定任何特性的普通窗口
    WindowFlags()
        : _flags(0)
    {

    }

    ~WindowFlags()
    {

    }

    WindowFlags& FullScreenDesktop()
    {
        _flags &= ~SDL_WINDOW_FULLSCREEN;
        _flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
        return *this;
    }

    Uint32 _flags;
};

struct Window
{
    Window(char const* title
           , WindowPosition const& win_position
           , int x, int y
           , WindowFlags const& win_flags) //必须有const,否则无法引用右值()
    {
        _window = SDL_CreateWindow(title
                                   , win_position._x, win_position._y
                                   , x, y
                                   , win_flags._flags);
    }

    ~Window()
    {
        SDL_DestroyWindow(_window);
    }

    bool UpdateSurface()
    {
        SDL_assert(_window != nullptr);
        return 0 == SDL_UpdateWindowSurface(_window);
    }

    SDL_Surface* GetSurface()
    {
        SDL_assert(_window);
        return SDL_GetWindowSurface(_window);
    }

    explicit operator bool() const
    {
        return _window != nullptr;
    }

    Uint32 GetID()
    {
        SDL_assert(_window != nullptr);
        return SDL_GetWindowID(_window);
    }

    bool SetOpacity(float opacity)
    {
        SDL_assert(_window != nullptr);
        return 0 == SDL_SetWindowOpacity(_window, opacity);
    }

    void Hide()
    {
        SDL_assert(_window != nullptr);
        SDL_HideWindow(_window);
    }

    void Show()
    {
        SDL_assert(_window != nullptr);
        SDL_ShowWindow(_window);
    }

    SDL_Window* _window;
};

}//sdl2

#endif // SDL_WINDOW_HPP_INCLUDED

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LINUX设备驱动第三_ 前言 第一章 设备驱动程序简介 设备驱动程序的作用 内核功能划分 设备和模块的分类 安全问题 本编号 许可证条款 加入内核开发社团 本书概要 第二章 构造和运行模块 设置测试系统 Hello World模块 核心模块与应用程序的对比 编译和装载 内核符号表 预备知识 初始化和关闭 模块参数 在用户空间编写驱动程序 快速参考 第三章 字符设备驱动程序 scull的设计 主设备号和次设备号 一些重要的数据结构 字符设备的注册 open和release scull的内存使用 read和write 试试新设备 快速参考 第四章 调试技术 内核中的调试支持 通过打印调试 通过查询调试 通过监视调试 调试系统故障 调试和相关工具 第五章 并发和竞态 scull的缺陷 并发及其管理 信号量和互斥体 completion 自旋锁 锁陷阱 除了锁之外的办法 快速参考 第六章 高级字符驱动程序操作 ioctl 阻塞型I/O poll和select 异步通知 定位设备 设备文件的访问控制 快速参考 第七章 时间、延迟及延缓操作 度量时间差 获取当前时间 延迟执行 内核定时 tasklet 工作队列 快速参考 第八章 分配内存 kmalloc函数的内幕 后备高速缓存 get_free_page和相关函数 vmalloc及其辅助函数 per-CPU变量 获取大的缓冲区 快速参考 第九章 与硬件通信 I/O端口和I/O内存 使用I/O端口 I/O端口示例 使用I/O内存 快速参考 第十章 中断处理 准备并口 安装中断处理例程 实现中断处理例程 顶半部和底半部 中断共享 中断驱动的I/O 快速参考 第十一章 内核的数据类型 使用标准C语言类型 为数据项分配确定的空间大小 接口特定的类型 其他有关移植性的问题 链表 快速参考 第十二章 PCI驱动程序 PCI接口 ISA回顾 PC/104和PC/104+ 其他的PC总线 SBus NuBus 外部总线 快速参考 第十三章 USB驱动程序 USB设备基础 USB和Sysfs USB urb 编写USB驱动程序 不使用urb的USB传输 快速参考 第十四章 Linux设备模型 kobject、kset和子系统 低层sysfs操作 热插拔事件的产生 总线、设备和驱动程序 类 各环节的整合 热插拔 处理固件 快速索引 第十五章 内存映射和DMA Linux的内存管理 mmap设备操作 执行直接I/O访问 直接内存访问 快速参考 第十六章 块设备驱动程序 注册 块设备操作 请求处理 其他一些细节 快速参考 第十七章 网络驱动程序 snull设计 连接到内核 net_device结构细节 打开和关闭 数据包传输 数据包的接收 中断处理例程 不使用接收中断 链路状态的改变 套接字缓冲区 MAC 地址解析 定制 ioctl 命令 统计信息 组播 其他知识点详解 快速参考 第十八章 TTY驱动程序 小型TTY驱动程序 tty_driver函数指针 TTY线路设置 ioctls proc和sysfs对TTY设备的处理 tty_driver结构详解 tty_operations结构详解 tty_struct结构详解 快速参考 参考书目 9112405-1_o.jpg (85.53 KB, 下载次数: 50)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值