cpp文件:
#include "sdlqtrgb.h"
#include <sdl/SDL.h>
static SDL_Window* sdl_win = NULL;
static SDL_Renderer* sdl_render = NULL;
static SDL_Texture* sdl_texture = NULL;
static int sdl_width = 0;
static int sdl_height = 0;
static unsigned char* rgb = NULL;
static int pix_size = 4;
void SdlQtRGB::timerEvent(QTimerEvent* ev)
{
static unsigned char tmp = 255;
tmp--;
for (int j = 0; j < sdl_height; j++)
{
int b = j * sdl_width * pix_size;
for (int i = 0; i < sdl_width * pix_size; i += pix_size)
{
rgb[b + i] = 0; //B
rgb[b + i + 1] = tmp; //G
rgb[b + i + 2] = 0; //R
rgb[b + i + 3] = 0; //A
}
}
SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pix_size);
SDL_RenderClear(sdl_render);
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = sdl_width;
rect.h = sdl_height;
SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect);
SDL_RenderPresent(sdl_render);
}
SdlQtRGB::SdlQtRGB(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);
sdl_width = ui.label->width();
sdl_height = ui.label->height();
//初始化SDL
SDL_Init(SDL_INIT_VIDEO);
//创建窗口
sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId());
//创建渲染器
sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
//创建材质
sdl_texture = SDL_CreateTexture(sdl_render,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
sdl_width,
sdl_height
);
rgb = new unsigned char[sdl_width * sdl_height * pix_size];
startTimer(10);
}
1. 前要知识
1.像素
在这个上下文中,像素通常被表示为一组连续的颜色分量值。对于RGB图像来说,每个像素通常由三个分量组成:红色(R)、绿色(G)和蓝色(B)。在某些情况下还可能包含一个Alpha通道(A),像素的颜色分量值以一定的顺序存储在内存中,用一个一维数组存储,你可以想象成BGRABGRABGRABGRA........,一组BGRA就是一个像素点,不同分量的值的配比对应不同的颜色
2.代码中的循环
在这个循环中,每次迭代的单位是像素。换句话说,每次循环迭代处理的是一行中的一个像素。在RGB图像中,一个像素通常由多个字节组成,每个字节对应一个颜色通道(红色、绿色、蓝色和可能的Alpha通道),我们可以想象一张图片有很多行,每一行上有许多像素点(BGRA),比如
BGRABGRABGRABGRABGRA
BGRABGRABGRABGRABGRA
BGRABGRABGRABGRABGRA
BGRABGRABGRABGRABGRA
BGRABGRABGRABGRABGRA
上面是五行 每一行有五个像素点
2.代码解析
1.定时器函数解析
1.外部循环(行循环):
- 目的:遍历图像的每一行。
- 变量:
-
j
:当前行的索引,从0开始直到sdl_height - 1
。
-
- 每次迭代:
- 计算当前行在图像数据数组中的起始偏移量
b
:b = j * sdl_width * pix_size
。 - 这确保我们处理每一行的像素数据。
- 计算当前行在图像数据数组中的起始偏移量
2.内部循环(像素循环):
- 目的:遍历当前行的每个像素,并设置其RGB值。
- 变量:
-
i
:当前像素中第一个颜色通道(通常是蓝色)的偏移量,从0开始,每次递增pix_size
。
-
- 每次迭代:
- 对当前像素的每个颜色通道(B、G、R、A),设置相应的值:
-
rgb[b + i] = 0
:将蓝色分量(B)设为0。 -
rgb[b + i + 1] = tmp
:将绿色分量(G)设为tmp
的值,它在每次定时器事件中递减,导致逐渐减少的绿色。 -
rgb[b + i + 2] = 0
:将红色分量(R)设为0。 -
rgb[b + i + 3] = 0
:如果存在,将Alpha通道(A)设为0
-
- 对当前像素的每个颜色通道(B、G、R、A),设置相应的值:
3.SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pix_size) 更新纹理数据
- 这一步是将新的图像数据(存储在
rgb
数组中)更新到SDL纹理中。 - 在这个例子中,
SDL_UpdateTexture
函数用于更新纹理,使其包含了最新的图像数据。 - 这个函数的参数包括要更新的纹理、更新的矩形区域(如果为NULL,则更新整个纹理)、指向新图像数据的指针,以及新图像数据的行距(通常为图像宽度乘以每个像素的大小)。
4.SDL_RenderClear 清空当前渲染器:
- 这一步是清空当前渲染器的内容,准备开始绘制新的内容。
-
SDL_RenderClear
函数用于清空渲染器,以便在其上绘制新的内容。
5.SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect);
- 在这一步中,你首先定义一个矩形区域,然后使用
SDL_RenderCopy
函数将纹理复制到渲染器中。 - 这个矩形区域定义了纹理将要绘制到屏幕上的位置和大小。
-
SDL_RenderCopy
函数将指定的纹理复制到渲染器中,并根据矩形区域的位置和大小进行调整。
6.SDL_RenderPresent 更新屏幕显示:
- 这一步是将渲染器中的内容更新到屏幕上,使其可见。
-
SDL_RenderPresent
函数用于更新屏幕显示,将渲染器中的内容呈现到屏幕上。
综上所述,这些步骤组成了SDL中绘制图形的基本流程:更新纹理数据、清空渲染器、复制纹理到渲染器中,然后更新屏幕显示。通过这个流程,你可以实现动态更新和显示图形,例如在这个例子中每次定时器事件都会更新屏幕显示,使图像逐渐变化。
2.构造函数解析
- 调用
SDL_Init
函数来初始化SDL库的视频子系统。这是必要的,因为我们将使用SDL来处理图形。 - 调用
SDL_CreateWindowFrom
函数来创建一个SDL窗口,并将其与界面上的label
控件关联起来。这样,我们可以在该控件内部显示图形。 - 调用
SDL_CreateRenderer
函数来创建一个SDL渲染器,用于在窗口上进行绘制。参数-1
表示选择第一个可用的渲染器,SDL_RENDERER_ACCELERATED
表示使用硬件加速。 - 调用
SDL_CreateTexture
函数来创建一个SDL纹理,用于存储图像数据。参数指定了纹理的格式(ARGB8888)、访问方式(STREAMING,表示数据将被频繁更新)、宽度和高度。 - 动态分配了一个大小为
sdl_width * sdl_height * pix_size
字节的内存块,并将指针存储在rgb
变量中。这个内存块用于存储图像数据。 - 调用
startTimer
函数,启动一个定时器,每隔10毫秒触发一次定时器事件。定时器事件在之前的代码中已经被重载,用于更新图像数据并刷新屏幕显示。
构造函数完成了SDL的初始化、窗口、渲染器和纹理的创建,以及图像数据的内存分配和定时器的启动。整个流程为在Qt应用程序中嵌入SDL图形显示提供了基础。
3.运行结果展示
颜色从绿色到黑色再到绿色一直循环,根据循环里的temp变化而变化