ビジュアル
ウィンドウを作成する前に、ビジュアルについて説明します。
ハードウェアによっては、複数の方法で色を扱うことができる場合があるため、それぞれのカラーの扱い方は「ビジュアル」として定義されています。
各スクリーンにおいて、複数のビジュアルがサポートされています。
主にウィンドウで使用されるデフォルトのビジュアルは、各スクリーンであらかじめ定義されており、DefaultVisual(disp) マクロや DefaultVisualOfScreen(screen) マクロなどで取得できます。
返される値は、Visual 構造体のポインタです。
ハードウェアによっては、複数の方法で色を扱うことができる場合があるため、それぞれのカラーの扱い方は「ビジュアル」として定義されています。
各スクリーンにおいて、複数のビジュアルがサポートされています。
主にウィンドウで使用されるデフォルトのビジュアルは、各スクリーンであらかじめ定義されており、DefaultVisual(disp) マクロや DefaultVisualOfScreen(screen) マクロなどで取得できます。
返される値は、Visual 構造体のポインタです。
プログラム (1)
指定スクリーンでサポートされているビジュアルのリストを取得したい場合は、XGetVisualInfo 関数を使います。
この関数は X11/Xutil.h で定義されているので、インクルードファイルを追加してください。
<03a-visual.c>
デフォルトのスクリーンでサポートされている、ビジュアルのリストを表示します。
※数百個表示される場合があるため、「$ ./exe > out.txt」のように、結果をテキストに出力してから確認してみてください。
うちの環境だと、24bit,32bit の depth で 600 個のリストが表示されました。
これは、OpenGL などと関連付けられたビジュアルが存在するため、内部では、XVisualInfo 構造体では取得できない、より詳細な値が存在するためです。
vinfo_template で指定された値と等しい値を持つ XVisualInfo 構造体のリストを返します。
返されたポインタは、XFree() で解放します。
vinfo_mask は、vinfo_template で使用するメンバのマスクです。
今回の場合、テンプレートの XVisualInfo 構造体の screen メンバに、デフォルトのスクリーン番号を入れて、vinfo_mask に VisualScreenMask を指定することで、指定スクリーン番号に一致するビジュアルを返します。
この関数は X11/Xutil.h で定義されているので、インクルードファイルを追加してください。
<03a-visual.c>
#include <stdio.h> #include <X11/Xlib.h> #include <X11/Xutil.h> const char *class_names[] = { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" }; int main(int argc,char **argv) { Display *d; XVisualInfo *vi,vitmp; int i,cnt; d = XOpenDisplay(NULL); if(!d) return 1; vitmp.screen = DefaultScreen(d); vi = XGetVisualInfo(d, VisualScreenMask, &vitmp, &cnt); if(vi) { for(i = 0; i < cnt; i++) { printf("----[%d]---\n", i); printf("visualid: %lu\n", vi[i].visualid); printf("depth: %d\n", vi[i].depth); printf("class: (%d) %s\n", vi[i].class, class_names[vi[i].class]); printf("red_mask: 0x%lx\n", vi[i].red_mask); printf("green_mask: 0x%lx\n", vi[i].green_mask); printf("blue_mask: 0x%lx\n", vi[i].blue_mask); printf("colormap_size: %d\n", vi[i].colormap_size); printf("bits_per_rgb: %d\n", vi[i].bits_per_rgb); } XFree(vi); } XCloseDisplay(d); return 0; }
デフォルトのスクリーンでサポートされている、ビジュアルのリストを表示します。
※数百個表示される場合があるため、「$ ./exe > out.txt」のように、結果をテキストに出力してから確認してみてください。
うちの環境だと、24bit,32bit の depth で 600 個のリストが表示されました。
これは、OpenGL などと関連付けられたビジュアルが存在するため、内部では、XVisualInfo 構造体では取得できない、より詳細な値が存在するためです。
XGetVisualInfo 関数
XVisualInfo *XGetVisualInfo(Display *display, long vinfo_mask, XVisualInfo *vinfo_template, int *nitems_return);
vinfo_template で指定された値と等しい値を持つ XVisualInfo 構造体のリストを返します。
返されたポインタは、XFree() で解放します。
vinfo_mask は、vinfo_template で使用するメンバのマスクです。
VisualNoMask, VisualAllMask VisualIDMask, VisualScreenMask, VisualDepthMask, VisualClassMask, VisualRedMaskMask VisualGreenMaskMask, VisualBlueMaskMask, VisualColormapSizeMask, VisualBitsPerRGBMask
今回の場合、テンプレートの XVisualInfo 構造体の screen メンバに、デフォルトのスクリーン番号を入れて、vinfo_mask に VisualScreenMask を指定することで、指定スクリーン番号に一致するビジュアルを返します。
XVisualInfo 構造体
typedef struct { Visual *visual; VisualID visualid; int screen; unsigned int depth; int class; unsigned long red_mask; unsigned long green_mask; unsigned long blue_mask; int colormap_size; int bits_per_rgb; } XVisualInfo;
viaual | Visual 構造体のポインタ |
---|---|
visualid | ビジュアルのリソース ID (XID) |
screen | スクリーン番号 |
depth | ビット数 |
class | クラス。 StaticGray (0) : (グレイスケール) ピクセル値はインデックス。カラーマップは固定。 GrayScale (1) : StaticGray と同じだが、カラーマップは変更可能。 StaticColor (2) : (パレットカラー) ピクセル値はインデックス。カラーマップは固定。 PseudoColor (3) : StaticColor と同じだが、カラーマップは変更可能。 TrueColor (4) : ピクセル値は RGB 値をパックしたもの。カラーマップは固定。 DirectColor (5) : TrueColor と同じだが、カラーマップは変更可能。 |
red_mask green_mask blue_mask | (TrueColor, DirectColor 時) ピクセル値から R,G,B 値を取得するためのマスク値 |
colormap_size | 新しく作成されたカラーマップで使用可能な、カラーマップエントリの数。 DirectColor と TrueColor の場合、R,G,B のサイズ (それぞれ 8bit なら 256)。 |
bits_per_rgb | R,G,B の各値のビット数 |
X は古いシステムのため、256 色カラーのモニタにも対応しています。
しかし、現在のモニタは基本的に 24bit か 32bit のフルカラーを使用するので、現状では TrueColor か DirectColor を使用することになります (通常は TrueColor)。
ピクセル値
「ピクセル値」は、X で描画色や背景色を指定する時の色値です。
XImage などのイメージバッファで、各ピクセルの数値を扱うときにも使います。
TrueColor と DirectColor の場合は、1つの整数 (16bit or 32bit) に、R,G,B の3つの値をパックします。
「red_mask = 0xff0000, green_mask = 0xff00, blue_mask = 0xff」の場合は、0xRRGGBB という形の整数値になります。
depth が 24bit,32bit の場合は、0xRRGGBB の形になることが多いですが、それ以外 (0xBBGGRR など) になる場合もあります。
XImage などのイメージバッファで、各ピクセルの数値を扱うときにも使います。
TrueColor と DirectColor の場合は、1つの整数 (16bit or 32bit) に、R,G,B の3つの値をパックします。
「red_mask = 0xff0000, green_mask = 0xff00, blue_mask = 0xff」の場合は、0xRRGGBB という形の整数値になります。
depth が 24bit,32bit の場合は、0xRRGGBB の形になることが多いですが、それ以外 (0xBBGGRR など) になる場合もあります。
GLX でビジュアルの詳細な情報を取得
上記のプログラムで出力された情報を見てみると、visualid を除いて、同じ構成のビジュアルが複数個存在しているのがわかります。
これは、拡張機能 GLX (X で OpenGL を使用するためのもの) によって、ビジュアル内に隠れた値が存在しているためです。
それぞれのビジュアルの詳細な情報を取得したい場合は、GLX を使う必要があります。
これは、拡張機能 GLX (X で OpenGL を使用するためのもの) によって、ビジュアル内に隠れた値が存在しているためです。
それぞれのビジュアルの詳細な情報を取得したい場合は、GLX を使う必要があります。
プログラム (2)
デフォルトのスクリーンで使用可能な、すべての GLXFBConfig (設定の情報) を取得し、そこに X のビジュアル ID が関連付けられている場合は、情報を表示します。
-lGLX で、GLX のライブラリをリンクする必要があります。
Ubuntu/debuan の場合、libglx-dev パッケージが必要です。
<03b-glx.c>
-lGLX で、GLX のライブラリをリンクする必要があります。
Ubuntu/debuan の場合、libglx-dev パッケージが必要です。
$ cc -o run 03b-glx.c -lX11 -lGLX
<03b-glx.c>
#include <stdio.h> #include <X11/Xlib.h> #include <GL/glx.h> int main(int argc,char **argv) { Display *disp; Visual *visual; GLXFBConfig *pcf,cf; int major,minor,i,num,cnt,val,r,g,b,a; disp = XOpenDisplay(NULL); if(!disp) return 1; visual = DefaultVisual(disp, DefaultScreen(disp)); printf("default visual id: %lu\n", XVisualIDFromVisual(visual)); //GLX のバージョン取得 if(!glXQueryVersion(disp, &major, &minor) || (major == 1 && minor < 4)) { printf("unsupported GLX ver 1.4\n"); XCloseDisplay(disp); return 1; } //指定スクリーンで使用可能なすべての GLXFBConfig pcf = glXGetFBConfigs(disp, DefaultScreen(disp), &num); if(pcf) { cnt = 0; for(i = 0; i < num; i++) { cf = pcf[i]; glXGetFBConfigAttrib(disp, cf, GLX_VISUAL_ID, &val); if(val == 0) continue; printf("--- [%d] ---\n", cnt++); printf("visual_id: %d\n", val); glXGetFBConfigAttrib(disp, cf, GLX_BUFFER_SIZE, &val); glXGetFBConfigAttrib(disp, cf, GLX_RED_SIZE, &r); glXGetFBConfigAttrib(disp, cf, GLX_GREEN_SIZE, &g); glXGetFBConfigAttrib(disp, cf, GLX_BLUE_SIZE, &b); glXGetFBConfigAttrib(disp, cf, GLX_ALPHA_SIZE, &a); printf("buffer: %dbit (R:%d, G:%d, B:%d, A:%d)\n", val, r, g, b, a); glXGetFBConfigAttrib(disp, cf, GLX_DEPTH_SIZE, &val); printf("zbuf: %dbit\n", val); glXGetFBConfigAttrib(disp, cf, GLX_STENCIL_SIZE, &val); printf("stencil: %dbit\n", val); } XFree(pcf); } XCloseDisplay(disp); return 0; }
情報の比較
03a-visual.c と 03b-glx.c で、出力された情報を比較してみてください。
おそらく、両方で同じビジュアル ID が存在すると思います (順番は多少異なりますが)。
たとえば、この情報を見てみると、ビジュアル ID は 33 で同じですが、depth と buffer のサイズが一致していません。
GLX における buffer は、アルファ値も含めたカラーバッファのビット数です。この場合は A=8bit であることから、32 bit になっています。
しかし、Xlib におけるレンダリングでは、アルファ値は使用できないため、depth は 24 bit になっています。
zbuf と stencil は、3D で使用されるバッファのビット数です。
他にもいくつか属性がありますが、ここでは表示していません。
おそらく、両方で同じビジュアル ID が存在すると思います (順番は多少異なりますが)。
default visual id: 33 [XVisualInfo] visualid: 33 depth: 24 class: (4) TrueColor red_mask: 0xff0000 green_mask: 0xff00 blue_mask: 0xff colormap_size: 256 bits_per_rgb: 8 [GLX] visual_id: 33 buffer: 32bit (R:8, G:8, B:8, A:8) zbuf: 24bit stencil: 8bit
たとえば、この情報を見てみると、ビジュアル ID は 33 で同じですが、depth と buffer のサイズが一致していません。
GLX における buffer は、アルファ値も含めたカラーバッファのビット数です。この場合は A=8bit であることから、32 bit になっています。
しかし、Xlib におけるレンダリングでは、アルファ値は使用できないため、depth は 24 bit になっています。
zbuf と stencil は、3D で使用されるバッファのビット数です。
他にもいくつか属性がありますが、ここでは表示していません。