Irrlicht を用いたカラー画像ビューワの例
IRRLICHT は,もともと C 言語ベースの3次元エンジンです. IRRLICHT は,画像(カラー,モノクロ)の描画、2次元グラフィックス、3次元グラフィックス,イベント処理(マウス,キーボード等)の機能をもったゲームエンジンの決定版です. 文字の描画 (unicodeも可), 画像ファイル読み書きの機能もありますし,スライダやボタンなどのGUI部品もあるので,困ることはありません.
このページではIrrlicht を用いたカラー画像ビューワのプログラム例を示す. 単なるカラー画像ビューワを作りたいのではなくて,ウインドウを開いて画像を表示するようなプログラムを C 言語で簡単に作ることが出来る見本として示している.
前準備
前準備
- Windows の場合
- Irrlicht のインストールが終わっていること.
- SDL の最新版 と SDL image のインストールが済んでいること.
- Linux の場合
- Irrlicht のインストールが終わっていること.
- SDL の最新版 と
SDL image のインストールが済んでいること.
- Fedora の場合には「yum install SDL*」のようなコマンドで簡単にインストールできる
- Ubuntu の場合には「sudo apt -y install libsdl-dev libsdl-image1.2-dev」のようなコマンドで簡単にインストールできる
プログラム例
-
RGBのカラー画像ファイルを読みこみ、ウインドウを開いて表示するプログラム.Linux で動作確認済み.Irrlicht と SDL の機能を使っています.
- 1画素の R, G, B 成分は1バイトであること.
- 画像データは隙間無くならんでいること.
- R, G, B の順に並んでいること
RGBのカラー画像ファイルについては,以下のことを仮定している.
なぜ SDL の最新版を使っているのか? 画像ファイルはヘッダが付いていたり,しばしば圧縮されている.画像ファイルの種類もいろいろある.SDL を使うと,こうしたことを気にしなくて済むと考えました.
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#ifdef WIN32
#include<windows.h>
#endif
#include<irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#include "SDL.h"
#include "SDL_image.h"
#pragma comment(lib, "Irrlicht.lib")
const int WMAX = 2048; // the width of an image buffer
const int HMAX = 2048; // the height of an image buffer
static unsigned char tmp_rgb24[3*WMAX*HMAX*2*2]; // buffer. 2の指数乗の大きさに拡張して画像を格納する配列
static video::ITexture* create_slice_texture(int width, int height, unsigned char *r, unsigned char *g, unsigned char *b, video::IVideoDriver* driver)
{
int i,j;
int twidth, theight; //2の指数乗に拡張した画像の大きさ
if(width < 64) twidth=64; //twidth, theightの設定
else if(width < 128) twidth=128;
else if(width < 256) twidth=256;
else if(width < 512) twidth=512;
else if(width < 1024) twidth=1024;
else twidth=2048;
if(height <64) theight=64;
else if(height <128) theight=128;
else if(height <256) theight=256;
else if(height <512) theight=512;
else if(height <1024) theight=1024;
else theight=2048;
// fprintf(stderr, "twidth = %d, theight = %d\n", twidth, theight);
for( i=0; i < height; i++ ) {
for( j=0; j < width; j++ ) {
tmp_rgb24[ i * twidth*3 + (j * 3)] = r[ i * width + j ]; // Blue
tmp_rgb24[ i * twidth*3 + (j * 3) + 1] = g[ i * width + j ]; // Green
tmp_rgb24[ i * twidth*3 + (j * 3) + 2] = b[ i * width + j ]; // Red
}
}
video::IImage* slice_image = driver->createImageFromData(video::ECF_R8G8B8, core::dimension2d<u32>(twidth,theight), tmp_rgb24, false);
video::ITexture* slice_texture = driver->addTexture("tmp_texture", slice_image);
slice_image->drop();
return slice_texture;
}
int main(int argc, char *argv[])
{
SDL_Surface *image;
int width, height, bpp;
int i, j, k;
unsigned char *r;
unsigned char *g;
unsigned char *b;
/* Check command line usage */
if ( ! argv[1] ) {
fprintf(stderr, "Usage: %s <image_file>\n", argv[0]);
return(1);
}
/* Open the image file */
image = IMG_Load(argv[1]);
if ( image == NULL ) {
fprintf(stderr, "Couldn't load %s: %s\n", argv[1], SDL_GetError());
}
k = 0;
width = image->w;
height = image->h;
bpp = image->format->BytesPerPixel;
fprintf( stderr, "bpp = %d\n", bpp );
fprintf( stderr, "width = %d\n", width );
fprintf( stderr, "height = %d\n", height );
r = new unsigned char[width * height];
g = new unsigned char[width * height];
b = new unsigned char[width * height];
for ( i = 0; i < height; i++ ) {
for ( j = 0; j < width; j++ ) {
// 1画素の R, G, B 成分は1バイトであること.画像データは隙間無くならんでいること.R, G, B の順に並んでいることを仮定している.
unsigned char* p = (unsigned char*)image->pixels;
long int pixel_at = k * bpp;
r[k] = p[pixel_at];
g[k] = p[pixel_at + 1];
b[k] = p[pixel_at + 2];
k++;
}
}
/* SDL 処理終了 */
SDL_Quit();
//ウィンドウを開くなど
video::E_DRIVER_TYPE driverType;
#ifdef WIN32
driverType = video::EDT_DIRECT3D9;
#else
/* driverType = video::EDT_OPENGL; */
driverType = video::EDT_SOFTWARE;
/* driverType = video::EDT_SOFTWARE2; */
#endif
static IrrlichtDevice *device = createDevice( driverType,
/* windowSize */ core::dimension2d<u32>(width, height),
/* bits */ 16,
/* fullscreen */ false,
/* stencilbuffer */ false,
/* vsync */ false,
/* IEventReceiver */ 0
);
if (device == 0)
return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* scenemgr = device->getSceneManager();
gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
gui::IGUIFont* font = guienv->getBuiltInFont();
device->setWindowCaption(L"simple viewer");
//表示部分
video::ITexture* slice_texture = create_slice_texture(width, height, r, g, b, driver);
while(device->run() && driver){
if (device->isWindowActive()){
driver->beginScene(true, true, video::SColor(0,120,102,136));
driver->draw2DImage(slice_texture, core::position2d<s32>(/* drawPos_x */ 0, /* drawPos_y */ 0), core::rect<s32>(0,0,width,height), 0, video::SColor(255,255,255,255), true);
driver->endScene();
}
}
driver->removeTexture(slice_texture);
device->drop();
delete (r);
delete (g);
delete (b);
return(0);
}
ビルドの手順
【Linux でのビルドコマンド(例)】
Ubuntu の場合
コマンド例
g++ -I/usr/include/irrlicht -I/usr/include/SDL -I/usr/include/png12 -o a.out hoge.cc -L/usr/lib64 -lSDL_image -lSDL -lpthread -lm -L/usr/local/lib -lIrrlicht -lGL -lGLU -lXext -lX11
Fedora の場合
コマンド例
g++ -I/usr/include/irrlicht -I/usr/include/SDL -I/usr/include/png12 -o a.out hoge.cc -L/usr/lib64 -lSDL_image -lSDL -lpthread -lm -L/usr/local/lib -lIrrlicht -lGL -lGLU -lXxf86vm -lXext -lX11