第15章 《乐趣》Page355~375 代码简化版

news2024/11/27 10:21:53

运行效果:全屏了

简化之后的代码如下:

//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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1318977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DMA传输中的中断处理在STM32中的应用

DMA&#xff08;Direct Memory Access&#xff09;是一种在数字系统中进行数据传输的技术&#xff0c;它可以在不依赖CPU的情况下直接从内存中读取或写入数据。在STM32微控制器中&#xff0c;DMA控制器可以与外设进行数据传输&#xff0c;减轻了CPU的负担&#xff0c;提高了数据…

什么同源策略?

同源 同源指的是URL有相同的协议、主机名和端口号。 同源策略 同源策略指的是浏览器提供的安全功能&#xff0c;非同源的RUL之间不能进行资源交互 跨域 两个非同源之间要进行资源交互就是跨域。 浏览器对跨域请求的拦截 浏览器是允许跨域请求的&#xff0c;但是请求返回…

C语言学习day09:运算符优先级

运算符优先级&#xff1a; //& 假如设一个int a; 给a一个变量&#xff1b; &a取a对应的地址 优先级运算符名称或含义使用形式结合方向说明1[1,2,3,4]数组下标数组名[常量表达形式]左到右()圆括号(表达式)/函数名(形参).成员选择(对象)对象.成员名->成员选择(指…

【Linux】模拟实现shell命令行解释器

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 主要思路2. 流程图3. 实现过程3.1 初步实现3.2 当前路径3.3 内建命令/外部命令3.4…

Mistral MOE架构全面解析

从代码角度理解Mistral架构 Mistral架构全面解析前言Mistral 架构分析分词网络主干MixtralDecoderLayerAttentionMOEMLP 下游任务因果推理文本分类 Mistral架构全面解析 前言 Mixtral-8x7B 大型语言模型 (LLM) 是一种预训练的生成式稀疏专家混合模型。在大多数基准测试中&…

Android 架构 - MVVM

一、概念 概念基于观察者模式&#xff0c;数据的变化会自动更新到UI。通信 View→ViewModel&#xff1a;View作为观察者&#xff0c;监听ViewModel中数据&#xff08;LiveData、Flow&#xff09;的变化从而自动更新UI。 ViewModel→Model&#xff1a;ViewModel调用Model获取数据…

FPGA设计与实战之时钟及时序简介1

文章目录 一、时钟定义二、基本时序三、总结一、时钟定义 我们目前设计的电路以同步时序电路为主,时钟做为电路工作的基准而显得非常重要。 简单的接口电路比如I2C、SPI等,复杂一点接口比如Ethernet的MII、GMII等接口,它们都有一个或多个时钟信号。 那么什么是时钟信号?它…

【华为】文档中命令行约定格式规范(命令行格式规范、命令行行为规范、命令行参数格式、命令行规范)

文章目录 命令行约定格式**粗体&#xff1a;命令行关键字***斜体&#xff1a;命令行参数*[ ]&#xff1a;可选配置{ x | y | ... } 和 [ x | y | ... ]&#xff1a;选项{ x | y | ... }* 和 [ x | y | ... ]*&#xff1a;多选项&<1-n>&#xff1a;重复参数#&#xff…

算法-动态规划

动态规划算法 应用场景-背包问题 介绍 动态规划(Dynamic Programming)算法的核心思想是&#xff1a;将大问题划分为小问题进行解决&#xff0c;从而一步步获取最优解的处理算法动态规划算法与分治算法类似&#xff0c;其基本思想也是将待求解问题分解成若干个子问题&#xff0…

算法:最短路径

文章目录 Dijkstra算法Bellman-Ford算法Floyd-Warshall 本篇总结的是图当中的最短路径算法 Dijkstra算法 单源最短路径问题&#xff1a;给定一个图G ( V &#xff0c; E ) G(V&#xff0c;E)G(V&#xff0c;E)&#xff0c;求源结点s ∈ V s∈Vs∈V到图中每个结点v ∈ V v∈V…

H266/VVC标准的编码结构介绍

概述 CVS&#xff1a; H266的编码码流包含一个或多个编码视频序列&#xff08;Coded Video Swquence&#xff0c;CVS&#xff09;&#xff0c;每个CVS以帧内随机接入点&#xff08;Intra Random Access Point&#xff0c; IRAP&#xff09;或逐渐解码刷新&#xff08;Gradual …

力扣题:数字与字符串间转换-12.18

力扣题-12.18 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;38. 外观数列 解题思想&#xff1a;进行遍历然后对字符进行描述即可 class Solution(object):def countAndSay(self, n):""":type n: int:rtype: str""&quo…

小程序静默登录-登录拦截实现方案【全局loginPromis加页面拦截】

实现效果&#xff1a; 用户进入小程序访问所有页面运行onload、onShow、onReady函数时保证业务登录态是有效的 实现难点&#xff1a; 由于小程序的启动流程中&#xff0c;页面级和组件级的生命周期函数都不支持异步阻塞&#xff1b;因此会造成一个情况&#xff0c;app.onLau…

【从零开始学习--设计模式--策略模式】

返回首页 前言 感谢各位同学的关注与支持&#xff0c;我会一直更新此专题&#xff0c;竭尽所能整理出更为详细的内容分享给大家&#xff0c;但碍于时间及精力有限&#xff0c;代码分享较少&#xff0c;后续会把所有代码示例整理到github&#xff0c;敬请期待。 此章节介绍策…

植物分类-PlantsClassification

一、模型配置 一、backbone resnet50 二、neck GlobalAveragePooling 三、head fc 四、loss type‘LabelSmoothLoss’, label_smooth_val0.1, num_classes30, reduction‘mean’, loss_weight1.0 五、optimizer lr0.1, momentum0.9, type‘SGD’, weight_decay0.0001 六、sche…

磁力计LIS2MDL开发(3)----九轴姿态解算

磁力计LIS2MDL开发.3--九轴姿态解算 概述视频教学样品申请完整代码下载使用硬件欧拉角万向节死锁四元数法姿态解算双环PI控制器偏航角陀螺仪解析代码 概述 LIS2MDL 包含三轴磁力计。 lsm6ds3trc包含三轴陀螺仪与三轴加速度计。 姿态有多种数学表示方式&#xff0c;常见的是四元…

【运维笔记】mvware centos挂载共享文件夹

安装mvware-tools 这里用的centos安装 yum install open-vm-tools 设置共享文件夹 依次点击&#xff1a;选项-共享文件夹-总是启用-添加&#xff0c;安装添加向导操作添加自己想共享的文件夹后。成功后即可在文件夹栏看到自己共享的文件夹 挂载文件夹 临时挂载 启动虚拟机&…

lvs-nat部署

LVS负载均衡群集部署——NAT模式 实验环境&#xff1a; 负载调度器&#xff1a;内网关 lvs&#xff0c;ens33&#xff1a;172.16.23.10&#xff1b;外网关&#xff1a;ens36&#xff1a;12.0.0.1 Web服务器1&#xff1a;172.16.23.11 Web服务器2&#xff1a;172.16.23.12 NFS…

【Spring】09 BeanClassLoaderAware 接口

文章目录 1. 简介2. 作用3. 使用3.1 创建并实现接口3.2 配置 Bean 信息3.3 创建启动类3.4 启动 4. 应用场景总结 Spring 框架为开发者提供了丰富的扩展点&#xff0c;其中之一就是 Bean 生命周期中的回调接口。本文将聚焦于其中的一个接口 BeanClassLoaderAware&#xff0c;介…

数据仓库与数据挖掘小结

更加详细的只找得到pdf版本 填空10分 判断并改错10分 计算8分 综合20分 客观题 填空10分 判断并改错10分--错的要改 mooc中的--尤其考试题 名词解释12分 4个&#xff0c;每个3分 经常碰到的专业术语 简答题40分 5个&#xff0c;每道8分 综合 画roc曲线 …