SDL2.0でPNG画像と文字列を表示

SDL2.0でPNG画像と文字列を表示してみます。

BMP画像とPNG画像の描画処理について新しくページを設けました。

文字列の描画処理について新しくページを設けました。

 

Table of Contents

1 SDL

SDLとはSimple DirectMedia Layerの略で、Cで実装されたマルチプラット フォームな描画ライブラリです。Simpleという名がつくように、単純な機能 に絞られておりますが、Windows、OSX、Linuxをサポートしており、SDLを用 いることでマルチプラットフォームなアプリを作成することができます。

 

SDLは1.2系と2.0系が存在し、インターフェースに差異があります。2.0系は 比較的新しい環境で導入されつつあります。 2.0系ではiOSとAndroidがサポートされており、新規にSDLを利用するユーザ は2.0系を選ぶべきでしょう。 SDLのWikiに1.2系から2.0系へ移植する為のガイドがあります。

 

SDL自体は機能が絞られている為、文字列描画等を実現する為には、SDL_ttf 等を利用する必要があります。

 

1.1 SDL_ttf

SDLを用いて文字列描画をサポートするライブラリです。

 

1.2 SDL_image

SDLではサポートしていない画像形式をサポートするライブラリです。PNGや JPEGを用いることができます。

 

1.3 その他

その他にも音源を扱うSDL_mixer等の各種プロジェクトが存在します。

 

2 インストール

 

2.1 osx

SDL 2.0SDL_ttfSDL_imageのdmgパッケージが用意されているので それらを取得してインストールします。 dmgをダブルクリックした後に展開される[パッケージ名].frameworkディレ クトリ一式を/Library/Frameworksディレクトリ配下にコピーします。

 

Install SDL on OSX

2.2 ubuntu

ubuntu 12.04環境ではSDL1.2のパッケージしか入っていない為、SDL2.0をソー スコードからインストールする必要があります。


2.2.1 SDL 2.0

ビルドに必要なパッケージを取得します。ここではSDL1.2に必要なパッケー ジを取得しています。

sudo apt-get build-dep libsdl1.2-dev

SDL2.0のソースコードを取得し、インストールします。

wget https://www.libsdl.org/release/SDL2-2.0.3.tar.gz
tar zxvf SDL2-2.0.3.tar.gz
cd SDL2-2.0.3
./configure
make
sudo make install

/usr/localディレクトリ配下にインストールされます。


2.2.2 SDL_ttf

SDL_ttfの場合は以下の通りです。

sudo apt-get build-dep libsdl-ttf2.0-dev
wget https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.12.tar.gz
tar zxvf SDL2_ttf-2.0.12.tar.gz
cd SDL2_ttf-2.0.12
configure
make
sudo make install

2.2.3 SDL_image

SDL_imageの場合は以下の通りです。

sudo apt-get build-dep libsdl-image1.2-dev
wget https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.0.tar.gz
tar zxvf SDL2_image-2.0.0.tar.gz
cd SDL2_image-2.0.0
./configure
make
sudo make install

3 プログラムのビルド

 

3.1 osx

GCC/Clangに-frameworkオプションでSDL2、SDL2_ttf、SDL2_imageを指定し、 それぞれのインクルードパスを通してやる必要があります(インクルードパ スを指定する必要があるのは設定が不十分な為?)

c++ foo.cpp \
    -framework SDL2 -framework SDL2_ttf -framework SDL2_image \
    -I/Library/Frameworks/SDL2.framework/Headers/ \
    -I/Library/Frameworks/SDL2_image.framework/Headers/ \
    -I/Library/Frameworks/SDL2_ttf.framework/Headers/ foo.cpp

3.2 ubuntu

sdl2-configコマンドでCFLAGSと必要なライブラリのオプションを取得し、 それらをGCCに渡します。ただし、SDL2_ttfとSDL2_imageのライブラリは別 途指定する必要があります。

g++ foo.cpp `sdl2-config --cflags --libs` -lSDL2_ttf -lSDL2_image

3.3 osx / ubuntuで共用できるMakefile

unameコマンドでosxとlinuxのCXXFLAGSを切り替えるMakefileの例は以下の 通りです。

TARGET := $(patsubst %.cpp,%,$(wildcard *.cpp))
UNAME := $(shell uname)

ifeq ($(UNAME),Linux)
CXXFLAGS += $(shell sdl2-config --cflags --libs)
CXXFLAGS += -lSDL2_ttf -lSDL2_image
else
CXXFLAGS += -framework SDL2 -framework SDL2_ttf -framework SDL2_image
CXXFLAGS += -I/Library/Frameworks/SDL2.framework/Headers/
CXXFLAGS += -I/Library/Frameworks/SDL2_image.framework/Headers/
CXXFLAGS += -I/Library/Frameworks/SDL2_ttf.framework/Headers/
endif

CXXFLAGS += $(EXTRA_CXXFLAGS)

$(TARGET):
  $(CXX) -o $@ $@.cpp $(CXXFLAGS)

all: $(TARGET)

clean:
  rm -rf $(TARGET)

4 サンプル

PNG画像と文字列を表示するサンプルを以下に記載します。別途PNG画像のファ イルとフォントのファイルが必要となります。

#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>

#define SAMPLE_SPRITE "sample.png"
#define SAMPLE_FONT "sazanami-gothic.ttf"
#define SAMPLE_FONT_SIZE (32)
#define SAMPLE_STRING "Sample string"

static SDL_Window *gWindow;
static int gWindowWidth;
static int gWindowHeight;

static SDL_Renderer *gRenderer;

static SDL_RWops *gFontRWops;
static TTF_Font *gFont;
static int gFontWidth;
static int gFontHeight;
static SDL_Color gFontColor = { 255, 255, 0 };

static bool initializeFont()
{
  gFontRWops = SDL_RWFromFile(SAMPLE_FONT, "rb");
  if (gFontRWops == nullptr)
    return false;

  gFont = TTF_OpenFontRW(gFontRWops, 0, SAMPLE_FONT_SIZE);
  if (gFont == nullptr)
    goto err1;

  if (TTF_SizeUTF8(gFont, "a", &gFontWidth, &gFontHeight) < 0)
    goto err2;

  return true;

 err2:
  TTF_CloseFont(gFont);
 err1:
  SDL_RWclose(gFontRWops);
  return false;
}

static void finalizeFont()
{
  TTF_CloseFont(gFont);
  SDL_RWclose(gFontRWops);
}

static bool initialize(int width, int height)
{
  if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    return false;

  if (TTF_Init() < 0)
    goto err1;

  if (SDL_CreateWindowAndRenderer(width, height, 0,
                                  &gWindow, &gRenderer) < 0)
    goto err2;

  if (!initializeFont())
    goto err3;

  SDL_GetWindowSize(gWindow, &gWindowWidth, &gWindowHeight);
  return true;

 err3:
  SDL_DestroyRenderer(gRenderer);
  SDL_DestroyWindow(gWindow);
 err2:
  TTF_Quit();
 err1:
  SDL_Quit();
  return false;
}

static void finalize()
{
  finalizeFont();
  SDL_DestroyRenderer(gRenderer);
  SDL_DestroyWindow(gWindow);
  TTF_Quit();
  SDL_Quit();
}

SDL_Texture *createSprite(const char *spriteName)
{
  SDL_RWops *rwops;
  SDL_Surface *surface;
  SDL_Texture *texture;

  rwops = SDL_RWFromFile(spriteName, "rb");
  if (rwops == nullptr)
    return nullptr;

  surface = IMG_LoadPNG_RW(rwops);
  if (surface == nullptr)
    goto err;

  texture = SDL_CreateTextureFromSurface(gRenderer, surface);
  SDL_FreeSurface(surface);
 err:
  SDL_RWclose(rwops);
  return texture;
}

SDL_Texture *createString(const char *string)
{
  SDL_Surface *surface;
  SDL_Texture *texture;

  surface = TTF_RenderUTF8_Solid(gFont, string, gFontColor);
  if (surface == nullptr) {
    std::cerr << "utf8" << std::endl;
    return nullptr;
  }

  texture = SDL_CreateTextureFromSurface(gRenderer, surface);
  SDL_FreeSurface(surface);
  return texture;
}

int main()
{
  SDL_Texture *sprite, *string;
  int ret = 1;

  if (!initialize(400, 400)) {
    std::cerr << "Initialize error" << std::endl;
    return 1;
  }

  sprite = createSprite(SAMPLE_SPRITE);
  if (sprite == nullptr) {
    std::cerr << "Sprite error" << std::endl;
    goto err1;
  }

  string = createString(SAMPLE_STRING);
  if (string == nullptr) {
    std::cerr << "String error" << std::endl;
    goto err2;
  }

  SDL_RenderClear(gRenderer);
  SDL_RenderCopy(gRenderer, sprite, nullptr, nullptr);
  SDL_RenderCopy(gRenderer, string, nullptr, nullptr);
  SDL_RenderPresent(gRenderer);
  SDL_Delay(10000);
  ret = 0;

  SDL_DestroyTexture(string);
 err2:
  SDL_DestroyTexture(sprite);
 err1:
  finalize();
  return ret;
}
SDL Sample