「SDL第五篇」徹底理解紋理(Texture)

前言

這是SDL系列文章的第五篇,本文將徹底讓你理解什麼是紋理。並帶你深入探討SDL的幾個重要概念SDL_Window、SDL_Render、SDL_Surface 與 SDL_Texture。在文章的最後向你展示SDL如何通過SDL_Texture進行渲染。

對於前面系列文章感興趣的同學可以通過下面的鏈接查看:

另外,我在慕課網分享了音影片免費入門課程,有興趣的同學可以去學習更多的音影片知識。

SDL_Surface vs SDL_Texture

在SDL系列文章的第二篇里,我詳細的介紹了SDL 渲染的工作原理。即在SDL_Render對象中有一個影片緩衝區,該緩衝區我們稱之為SDL_Surface,它是按照像素存放影像的。我們一般把真彩色的像素稱為RGB24數據。也就是說,每一個像素由24位組成,每8位代表一種顏色,像素的最終顏色是由RGB三種顏色混合而成的。

SDL_Texture 與SDL_Surface相似,也是一種緩衝區。只不過它存放的不是真正的像素數據,而是存放的影像的描述資訊。當渲染紋理時,SDL以這些描述資訊為數據,底層通過OpenGL、D3D 或 Metal操作GPU,最終繪製出與SDL_Surface一樣的圖形,且效率更高(因為它是GPU硬體計算的)。

看了以上的介紹,是不是對紋理有了一個清楚的認識了?

介紹完 SDL_Surface 和 SDL_Texture後,我們再看下SDL_Window 與 SDL_Render。

SDL_Window 與 SDL_Render

SDL_Window代表的是窗口的邏輯概念,它是存放在主記憶體中的一個對象。所以當我們調用SDL API 創建窗口後,它並不會被顯示出來。

SDL_Render 是渲染器,它也是主存中的一個對象。對Render操作時實際上分為兩個階段:

一、渲染階段。在該階段,用戶可以畫各種圖形渲染到SDL_Surface或SDL_Texture 中;

二、顯示階段。參SDL_Texture為數據,通過OpenGL操作GPU,最終將 SDL_Surfce 或SDL_Texture中的數據輸出到顯示器上。

通過上面的介紹,我們就將 SDL_Window、SDL_Render、SDL_Surface與 SDL_Texture之間的關係梳理清楚了,下面我們來看一下如何使用 SDL_Texture。

使用SDL_Texture

SDL提供了非常好用的操作SDL_Texture的方法,下面我們來重點介紹一下使用SDL_Texute的基本步驟。

  • 創建一個 SDL_Texture。
  • 渲染 Texture
  • Destory Texture

API詳細介紹

  • 創建 SDL_Texture SDL_Texture* SDL_CreateTexture(SDL_Renderer* renderer, Uint32 format, int access, int w, int h)
    • format: 指明像素格式,可以是YUV,也可以是RGB
    • access: 指明Texture的類型。可以是 Stream(影片),也可以是Target一般的類型。
  • 渲染 int SDL_RenderCopy(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* srcrect, const SDL_Rect* dstrect)
    • srcrect: 指定 Texture 中要渲染的一部分。如果將 Texture全部輸出,可以設置它為 NULL。
    • dstrect: 指定輸出的空間大小。
  • 銷毀Texture void SDL_DestroyTexture(SDL_Texture* texture)

例子

下面這個例子非常簡單,我這裡就不做特別的說明了。對這個程式看不懂的同學可以看我之前的幾篇 SDL 的相關文章。

#include "SDL.h"    /* Moving Rectangle */  int main(int argc, char *argv[])  {          SDL_Window *window;          SDL_Renderer *renderer;          SDL_Texture *texture;          SDL_Event event;          SDL_Rect r;            if (SDL_Init(SDL_INIT_VIDEO) < 0) {                  SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());                  return 3;          }            window = SDL_CreateWindow("SDL_CreateTexture",                          SDL_WINDOWPOS_UNDEFINED,                          SDL_WINDOWPOS_UNDEFINED,                          1024, 768,                          SDL_WINDOW_RESIZABLE);            r.w = 100;          r.h = 50;            renderer = SDL_CreateRenderer(window, -1, 0);            texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 1024, 768);            while (1) {                  SDL_PollEvent(&event);                  if(event.type == SDL_QUIT)                          break;                  r.x=rand()%500;                  r.y=rand()%500;                    SDL_SetRenderTarget(renderer, texture);                  SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);                  SDL_RenderClear(renderer);                  SDL_RenderDrawRect(renderer,&r);                  SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0x00);                  SDL_RenderFillRect(renderer, &r);                  SDL_SetRenderTarget(renderer, NULL);                  SDL_RenderCopy(renderer, texture, NULL, NULL);                  SDL_RenderPresent(renderer);          }          SDL_DestroyRenderer(renderer);          SDL_Quit();          return 0;  }

小結

本文重點介紹了 SDL_Window、SDL_Render、SDL_Surface以及SDL_Texture之間的關係。搞清楚它們之前的關係對於理解 SDL 渲染起著至關重要的作用。

大家一定要仔細的理解文章中所講的內容,在我後序的文章中,尤其是後面介紹 播放器 相關內容時,都要用到現在所講的這些內容。

希望本文能對你有所幫助,謝謝!