SDL_Texture 对象的使用方法

来源:互联网 发布:linux mv 隐藏文件 编辑:程序博客网 时间:2024/05/18 03:18
前两篇博客,说明了如何获取 bmp,png 图像数据内容,然后在SDL 中逐像素绘制出来.

bmp格式由于比较简单,采用的是自己读文件,把图像数据拷贝出来的形式;
png格式比较复杂,用 libpng ,获取图像数据


最终都是把图像数据放到 一段连续的,自己 new unsigned char[xxx] 的一段内存里。
然后,逐像素调用 SDL_RenderDrawPoint() 完成 图片在SDL 中的绘制.

这次不用逐一像素的绘图方法,使用 SDL 里内置的 SDL_Texture 对象来绘制图像。

总结几个关键步骤:
1.
创建 texture 对象
SDL_CreateTexture(SDL_Renderer * renderer,Uint32 format,int access, int w,int h);

参数这样传:
SDL_Texture* pTexture = SDL_CreateTexture(_pRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, _screenWidth, _screenHeight);
由于这次要绘制的是 rgba 4444 格式的png ,读取出来的 png 图像内容也是这样格式的,所以 第二个参数 SDL_PIXELFORMAT_RGBA32
_screenWidth ,_screenHeight 这里是 图像的宽高


2.
向 texture 对象 中导入 数据,使用 SDL_UpdateTexure()
SDL_UpdateTexture(SDL_Texture * texture,const SDL_Rect * rect,const void *pixels, int pitch);
参数 这样传
SDL_UpdateTexture(pTexture, NULL, pngData.imgData, _screenWidth * 4);

第2个 null指的是 整个 texture 大小
pngData.imgData 是 使用libpng 已经解析出来的 png 图像的数据 ,是一个连续的 rgba4444的形式.

最后一个参数是 图像数据 1行占用的 内存是多少,包括数据中内存的补齐.在这里 png 图像是连续的,所以直接用 图片宽度(_screenWidth 这里是图片宽度) x 4( rgba4444 是 4个 byte) 来表示图片每行所需的 内存大小

3.
绘制到 指定的renderer 上
这里直接画到窗口 renderer 上面.最后参数 两个NULL 表示 :把整个 texture(不截取) 绘制 到整个 renderer 大小的 rect 上
SDL_RenderCopy(_pRenderer, _pTestTexture, NULL, NULL);

4.
为了alpha值能够起作用,实现半透效果,需要注意的是这两行:
SDL_SetTextureBlendMode(pTexture, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawBlendMode(_pRenderer, SDL_BLENDMODE_BLEND);

(1)
如果是逐一像素绘制到 renderer 上时:
SDL_SetRenderDrawColor(_pRenderer, r, g, b, a);
SDL_RenderDrawPoint(_pRenderer, col, row);


由于是直接绘制到 renderer 上,所以需要 renderer 支持 半透明,
SDL_SetRenderDrawBlendMode(_pRenderer, SDL_BLENDMODE_BLEND);
这一行是必须的

(2)
如果使用 SDL_RenderCopy(renderer,texture)  这种直接把 texture 拷贝到 renderer 上面的形式,
则不需要 renderer 支持半透明,
SDL_SetRenderDrawBlendMode(_pRenderer, SDL_BLENDMODE_BLEND) 没有用处。
但是需要 texture 本身支持半透明,所以:
SDL_SetTextureBlendMode(pTexture, SDL_BLENDMODE_BLEND);
这一行是必须的


贴代码:

miaopng.h

#ifndef __PNG_H__#define __PNG_H__#include <iostream>namespace miaopng{void testpng(std::string filePath);struct PngData{int nWidth;int nHeight;unsigned char* imgData;unsigned char getRAt(int x, int y){unsigned char* addr = getAddrAt(x, y);char col = addr[0];return col;}unsigned char getGAt(int x, int y){unsigned char* addr = getAddrAt(x, y);char col = addr[1];return col;}unsigned char getBAt(int x, int y){unsigned char* addr = getAddrAt(x, y);char col = addr[2];return col;}unsigned char getAAt(int x, int y){unsigned char* addr = getAddrAt(x, y);char col = addr[3];return col;}unsigned char* getAddrAt(int x, int y){int sizePerLine = nWidth * 4;long offset = sizePerLine * y + x * 4;return this->imgData + offset;}};size_t loadpng(const char* filePath, int* pnWidth, int* pnHeight, unsigned char** cbData);}#endif //__PNG_H__

miaopng.cpp

#include "miaopng.h"#include <stdio.h>#include <iostream>#include <win32/png.h>#include <assert.h>namespace{typedef struct{const unsigned char* data;size_t size;int offset;} tImageSource;static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length){tImageSource* isource = (tImageSource*)png_get_io_ptr(png_ptr);if ((int)(isource->offset + length) <= isource->size){memcpy(data, isource->data + isource->offset, length);isource->offset += length;}else{png_error(png_ptr, "pngReaderCallback failed");}printf("123\n");}}namespace miaopng{//void testpng(std::string filePath)//{//png_structp png_ptr = nullptr;//png_infopinfo_ptr = nullptr;////png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);//assert(png_ptr != nullptr);//info_ptr = png_create_info_struct(png_ptr);//assert(info_ptr != nullptr);//FILE* fp = fopen(filePath.c_str(),"rb");//fseek(fp, 0, SEEK_END);//long len = ftell(fp);//fseek(fp, 0, SEEK_SET);//unsigned char* data = new unsigned char[len];//fread(data, len, 1, fp);//fclose(fp);//tImageSource imageSource;//imageSource.data = (unsigned char*)data;//imageSource.size = len;//imageSource.offset = 0;//png_set_read_fn(png_ptr, &imageSource, pngReadCallback);//// read png file info//png_read_info(png_ptr, info_ptr);//int _width = png_get_image_width(png_ptr, info_ptr);//int _height = png_get_image_height(png_ptr, info_ptr);//png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);//png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);//// force palette images to be expanded to 24-bit RGB//// it may include alpha channel//if (color_type == PNG_COLOR_TYPE_PALETTE)//{//png_set_palette_to_rgb(png_ptr);//}//// low-bit-depth grayscale images are to be expanded to 8 bits//if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)//{//bit_depth = 8;//png_set_expand_gray_1_2_4_to_8(png_ptr);//}//// expand any tRNS chunk data into a full alpha channel//if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))//{//png_set_tRNS_to_alpha(png_ptr);//}//// reduce images with 16-bit samples to 8 bits//if (bit_depth == 16)//{//png_set_strip_16(png_ptr);//}//// Expanded earlier for grayscale, now take care of palette and rgb//if (bit_depth < 8) {//png_set_packing(png_ptr);//}//// update info//png_read_update_info(png_ptr, info_ptr);//bit_depth = png_get_bit_depth(png_ptr, info_ptr);//color_type = png_get_color_type(png_ptr, info_ptr);//switch (color_type)//{//case PNG_COLOR_TYPE_GRAY:////_renderFormat = Texture2D::PixelFormat::I8;//printf("123");//break;//case PNG_COLOR_TYPE_GRAY_ALPHA:////_renderFormat = Texture2D::PixelFormat::AI88;//printf("123");//break;//case PNG_COLOR_TYPE_RGB:////_renderFormat = Texture2D::PixelFormat::RGB888;//printf("123");//break;//case PNG_COLOR_TYPE_RGB_ALPHA:////_renderFormat = Texture2D::PixelFormat::RGBA8888;//printf("123");//break;//default://break;//}//}size_t loadpng(const char* filePath, int* pnWidth, int* pnHeight, unsigned char** cbData){int file_size = 0;FILE* fp = fopen(filePath,"rb");assert(fp != nullptr);png_infop info_ptr;png_structp png_ptr;png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);info_ptr = png_create_info_struct(png_ptr);png_init_io(png_ptr,fp);// png_ptr 与 文件绑定png_read_png(png_ptr,info_ptr,PNG_TRANSFORM_EXPAND,0);//读取 png 文件// 基础信息 *pnWidth = png_get_image_width(png_ptr, info_ptr);*pnHeight = png_get_image_height(png_ptr, info_ptr);png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);assert(color_type == PNG_COLOR_TYPE_RGB_ALPHA);//临时只支持一种 RGBA 的 png 格式const int BLOCK_SIZE = 4;//(rgba 4 bytes)file_size = (*pnWidth) * (*pnHeight) * BLOCK_SIZE;*cbData = new unsigned char[file_size];//*cbData = (unsigned char*)malloc(file_size);// 开始读取数据 填充数据png_bytep *row_point = NULL;row_point = png_get_rows(png_ptr, info_ptr);int pos = 0;for (int y = 0; y < *pnHeight;y++){for (int x = 0; x < *pnWidth * BLOCK_SIZE; x += BLOCK_SIZE){(*cbData)[pos++] = row_point[y][x + 0];//R(*cbData)[pos++] = row_point[y][x + 1];//G(*cbData)[pos++] = row_point[y][x + 2];//B(*cbData)[pos++] = row_point[y][x + 3];//A}}png_destroy_read_struct(&png_ptr, &info_ptr, 0);fclose(fp);return file_size;}}


Application.h

#ifndef __APPLICATION_H__#define __APPLICATION_H__#include "SDL.h"#include <stdio.h>class Application{public:Application();virtual ~Application();public:bool initialize(int screenWidth,int screenHeight);void mainLoop();void cleanup();private:SDL_Window*_pWindow;SDL_Surface*_pScreenSurface;SDL_Renderer*_pRenderer;int _screenWidth, _screenHeight;private:void drawTexture();void drawByPixels();void initRes();private:void startGame();void showMainMenu();void restartGame();private:SDL_Texture*_pTestTexture;};#endif //__APPLICATION_H__


Application.cpp

#include "Application.h"#include <assert.h>#include <stdlib.h>#include "mp3.h"#include "miaopng.h"const int SCALE_FACTOR = 1;//const int SCALE_FACTOR = 200;Application::Application(): _pWindow(nullptr), _pScreenSurface(nullptr), _pRenderer(nullptr), _screenWidth(100), _screenHeight(100), _pTestTexture(nullptr){}Application::~Application(){cleanup();}bool Application::initialize(int screenWidth, int screenHeight){if (SDL_Init(SDL_INIT_VIDEO) < 0){printf("SDL can not initialized!SDL Error:%s\n", SDL_GetError());return false;}_screenWidth = screenWidth * SCALE_FACTOR;_screenHeight = screenHeight * SCALE_FACTOR;_pWindow = SDL_CreateWindow("msdl1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _screenWidth, _screenHeight, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);//_pWindow = SDL_CreateWindow("msdl1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _screenWidth, _screenHeight, SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN);if (_pWindow == nullptr){printf("SDL can't create window!SDL Error:%s\n", SDL_GetError());return false;}int w, h;SDL_GetWindowSize(_pWindow, &w, &h);printf("Viewport Size: %d,%d\n",w,h);_pScreenSurface = SDL_GetWindowSurface(_pWindow);_pRenderer = SDL_CreateRenderer(_pWindow, -1, SDL_RENDERER_ACCELERATED);if (_pRenderer == nullptr){return false;}SDL_FillRect(_pScreenSurface, nullptr, SDL_MapRGBA(_pScreenSurface->format, 0, 0, 0, 0));initRes();return true;}void Application::initRes(){extern miaopng::PngData pngData;SDL_Texture* pTexture = SDL_CreateTexture(_pRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, _screenWidth, _screenHeight);//SDL_SetTextureAlphaMod(pTexture, SDL_BLENDMODE_BLEND);SDL_SetTextureBlendMode(pTexture, SDL_BLENDMODE_BLEND);SDL_UpdateTexture(pTexture, NULL, pngData.imgData, _screenWidth * 4);_pTestTexture = pTexture;}void Application::cleanup(){SDL_DestroyRenderer(_pRenderer);SDL_DestroyWindow(_pWindow);SDL_Quit();}void Application::mainLoop(){bool quit = false;SDL_Event evt;while (!quit){while (SDL_PollEvent(&evt) != 0){if (evt.type == SDL_QUIT){quit = true;}}{SDL_SetRenderDrawColor(_pRenderer, (Uint8)255, (Uint8)255, (Uint8)255, 0xff);SDL_RenderClear(_pRenderer);SDL_SetRenderDrawColor(_pRenderer, 0x00, 0xff, 0x00, 0xff);SDL_Rect fillRect = { 0, 0, _screenWidth, _screenHeight };SDL_RenderFillRect(_pRenderer, &fillRect);SDL_SetRenderDrawBlendMode(_pRenderer, SDL_BLENDMODE_BLEND);}this->drawTexture();//this->drawByPixels();SDL_RenderPresent(_pRenderer);}}void Application::drawTexture(){SDL_RenderCopy(_pRenderer, _pTestTexture, NULL, NULL);}void Application::drawByPixels(){for (int row = 0; row < _screenHeight; row++){for (int col = 0; col < _screenWidth; col++){/*随机颜色*//*int r = rand() / 100 % 256;int g = rand() / 100 % 256;int b = rand() / 100 % 256;int a = 0xff;*//*bmp 格式图片*//*extern miaomp3::The24BitBmp bitmap;int x = col/SCALE_FACTOR;int y = row/SCALE_FACTOR;y = bitmap.height - y - 1;Uint8 r, g, b, a;r = (Uint8)bitmap.getRAt(x, y);g = (Uint8)bitmap.getGAt(x,y);b = (Uint8)bitmap.getBAt(x,y);a = 0xff;//printf("(%d,%d):[%d,%d,%d]\n",x,y,r,g,b);*//*png 格式图片*/extern miaopng::PngData pngData;int x = col / SCALE_FACTOR;int y = row / SCALE_FACTOR;Uint8 r, g, b, a;r = (Uint8)pngData.getRAt(x, y);g = (Uint8)pngData.getGAt(x, y);b = (Uint8)pngData.getBAt(x, y);a = (Uint8)pngData.getAAt(x, y);//if (a > 0)//{////r = 255;////g = 255;////b = 255;//a = 150;//}//a = 150;SDL_SetRenderDrawColor(_pRenderer, r, g, b, a);SDL_RenderDrawPoint(_pRenderer, col, row);}}}void Application::startGame(){}void Application::showMainMenu(){}void Application::restartGame(){}

main.cpp

#include <iostream>#include "Application.h"#include "mp3.h"#include "miaopng.h"#include <win32/png.h>miaomp3::The24BitBmp bitmap;miaopng::PngData pngData;int main(){//miaomp3::testmp3("res/login.mp3");miaomp3::testmp3("res/laoshi.bmp",bitmap);//miaomp3::testmp3("res/linshiyin.bmp",bitmap);//miaomp3::testmp3("res/ceshi.bmp", bitmap);//miaopng::testpng("res/mingyuexin.png");pngData.nWidth = 0;pngData.nHeight = 0;pngData.imgData = nullptr;miaopng::loadpng("res/mingyuexin.png",&pngData.nWidth,&pngData.nHeight,&pngData.imgData);//miaopng::loadpng("res/murongjiu.png",&pngData.nWidth,&pngData.nHeight,&pngData.imgData);Application app;//app.initialize(bitmap.width, bitmap.height);app.initialize(pngData.nWidth, pngData.nHeight);app.mainLoop();return 0;}

另外,把没有用上的 bmp 解析的代码也贴上吧,保证能编译通过

mp3.h

#ifndef __MP3_H__#define __MP3_H__#include <iostream>namespace miaomp3{/*addr 地址bytes 多少字节 (每个字节是8位)*/int getDecimal(char* addr, int bytes);class The24BitBmp{public:~The24BitBmp(){delete[] data;data = nullptr;}long fileSize;long dataOffset;int width;int height;char* data;int fillZeroPerLine;int sizePerLine;unsigned char getRAt(int x, int y);unsigned char getGAt(int x, int y);unsigned char getBAt(int x, int y);char* getAddrAt(int x, int y);};void testmp3(std::string filePath, The24BitBmp& bitmap);}#endif //__MP3_H__

mp3.cpp

#include "mp3.h"#include <assert.h>namespace miaomp3{unsigned char The24BitBmp::getRAt(int x, int y){char* addr = getAddrAt(x, y);char col = addr[2];return col;}unsigned char The24BitBmp::getGAt(int x, int y){char* addr = getAddrAt(x, y);char col = addr[1];return col;}unsigned char The24BitBmp::getBAt(int x, int y){char* addr = getAddrAt(x, y);char col = addr[0];return col;}char* The24BitBmp::getAddrAt(int x, int y){long offset = sizePerLine * y + x * 3;return this->data + offset;}long fileSize(FILE* fp){fseek(fp, 0L, SEEK_END);long pos = ftell(fp);fseek(fp,0L,SEEK_SET);return pos;}/*addr 地址 bytes 多少字节 (每个字节是8位)*/int getDecimal(char* addr,int bytes){int ret = 0;assert(bytes%2 == 0);for (int index = 0; index < bytes;index++){int base = addr[index];int pownum = index * 2;int inc = base * pow(16, pownum);//printf("base:%d,pownum:%d,inc:%d\n",base,pownum,inc);ret += inc;}return ret;}void testmp3(std::string file,The24BitBmp& bitmap){FILE*fp = fopen(file.c_str(), "rb");if (fp == nullptr) return;long size = fileSize(fp);char* fd = new char[size];for (long index = 0; index < size;index++){fd[index] = 0;}fread(fd, size,1, fp);fclose(fp);bitmap.dataOffset = getDecimal(fd + 10, 4);bitmap.fileSize = getDecimal(fd + 2, 4);bitmap.width = getDecimal(fd + 18, 4);bitmap.height = getDecimal(fd + 22, 4);long dataSize = bitmap.fileSize - bitmap.dataOffset;bitmap.data = new char[dataSize]();memcpy(bitmap.data, fd + bitmap.dataOffset, dataSize);int shouldBytesPerLine = bitmap.width * 3;bitmap.fillZeroPerLine = 0;if (shouldBytesPerLine %4 != 0){printf("123");}bitmap.sizePerLine = shouldBytesPerLine + bitmap.fillZeroPerLine;delete[] fd;}}










原创粉丝点击