メモ
課題22
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#define MODE_ENCODE 0
#define MODE_DECODE 1
const char usage[] = "usage: 22 [ options ]\n -d\t\tdecode input\n -e\t\tencode input ( default )\n -l N\t\tinsert newline every N chunks ( 1 chunk is 3 raw charcters )\n -h\t\tshow this text\n -v\t\tshow version string\n";
const char version[] = "version 1.0\n";
typedef unsigned int BOOL;
/*
* CodeChunk
* The struct which contains 3 charcters and encoded
* charcters for them.
*/
typedef struct {
uint8_t raw[ 3 ];
uint8_t encoded[ 4 ];
} CodeChunk;
void initChunk( CodeChunk *_arg_chunk ) {
memset( (void *)( _arg_chunk->raw ), 0, 3 * sizeof( uint8_t ) );
memset( (void *)( _arg_chunk->encoded ), 0, 4 * sizeof( uint8_t ) );
}
/*
* Returns begin of iterator for raw string
* First argument: target chunk
* Return value: begin of iterator
*/
uint8_t *beginRaw( CodeChunk *_arg_chunk ) {
return _arg_chunk->raw;
}
/*
* Returns end of iterator for raw string
* First argument: target chunk
* Return value: end of iterator
*/
uint8_t *endRaw( CodeChunk *_arg_chunk ) {
return _arg_chunk->raw + 3;
}
/*
* Returns begin of iterator for encoded string
* First argument: target chunk
* Return value: begin of iterator
*/
uint8_t *beginEncoded( CodeChunk *_arg_chunk ) {
return _arg_chunk->encoded;
}
/*
* Returns end of iterator for encoded string
* First argument: target chunk
* Return value: end of iterator
*/
uint8_t *endEncoded( CodeChunk *_arg_chunk ) {
return _arg_chunk->encoded + 4;
}
/*
* Returns begin of reversed iterator for raw string
* First argument: target chunk
* Return value: begin of reversed iterator
* Note: This reversed iterator is not fully functional but
* just a pointer. You have to inverse increment and
* decrement.
*/
uint8_t *rbeginRaw( CodeChunk *_arg_chunk ) {
return _arg_chunk->raw + 2;
}
/*
* Returns end of reversed iterator for raw string
* First argument: target chunk
* Return value: end of reversed iterator
* Note: This reversed iterator is not fully functional but
* just a pointer. You have to inverse increment and
* decrement.
*/
uint8_t *rendRaw( CodeChunk *_arg_chunk ) {
return _arg_chunk->raw - 1;
}
/*
* Returns begin of reversed iterator for encoded string
* First argument: target chunk
* Return value: begin of reversed iterator
* Note: This reversed iterator is not fully functional but
* just a pointer. You have to inverse increment and
* decrement.
*/
uint8_t *rbeginEncoded( CodeChunk *_arg_chunk ) {
return _arg_chunk->encoded + 3;
}
/*
* Returns end of reversed iterator for encoded string
* First argument: target chunk
* Return value: end of reversed iterator
* Note: This reversed iterator is not fully functional but
* just a pointer. You have to inverse increment and
* decrement.
*/
uint8_t *rendEncoded( CodeChunk *_arg_chunk ) {
return _arg_chunk->encoded - 1;
}
/*
* Encodes 8bit 3 charcters into 6bit 4 charcters
* First argument: target chunk
*/
void encodeChunk( CodeChunk *_arg_chunk ) {
uint32_t temp = 0;
uint8_t *iterator;
for( iterator = beginRaw( _arg_chunk ); iterator != endRaw( _arg_chunk ); iterator++ ) {
temp <<= 8;
temp |= (uint32_t)( *iterator );
}
for( iterator = rbeginEncoded( _arg_chunk ); iterator != rendEncoded( _arg_chunk ); iterator-- ) {
*iterator = temp & 0x3F;
if( *iterator < 0x30 )*iterator |= 0x40;
temp >>= 6;
}
}
/*
* Decodes 6bit 4 charcters into 8bit 3 charcters
* First argument: target chunk
*/
void decodeChunk( CodeChunk *_arg_chunk ) {
uint32_t temp = 0;
uint8_t *iterator;
for( iterator = beginEncoded( _arg_chunk ); iterator != endEncoded( _arg_chunk ); iterator++ ) {
temp <<= 6;
temp |= (uint32_t)( *iterator ) & 0x3F;
}
for( iterator = rbeginRaw( _arg_chunk ); iterator != rendRaw( _arg_chunk ); iterator-- ) {
*iterator = temp & 0xFF;
temp >>= 8;
}
}
/*
* Read raw string from the stream.
* First argument: target chunk
* Second argument: stream to read
*/
BOOL readRawFromStream( CodeChunk *_arg_chunk, FILE *_arg_stream ) {
uint8_t *iterator;
for( iterator = beginRaw( _arg_chunk ); iterator != endRaw( _arg_chunk ); iterator++ ) {
if( feof( _arg_stream ) )return 0;
int temp = fgetc( _arg_stream );
*iterator = (uint8_t)temp;
}
return 1;
}
/*
* Write raw string to the stream.
* First argument: target chunk
* Second argument: stream to write
*/
BOOL writeRawToStream( CodeChunk *_arg_chunk, FILE *_arg_stream ) {
uint8_t *iterator;
for( iterator = beginRaw( _arg_chunk ); iterator != endRaw( _arg_chunk ) && *iterator; iterator++ )
fputc( *iterator, _arg_stream );
return *iterator;
}
/*
* Read encoded string from the stream.
* First argument: target chunk
* Second argument: stream to read
*/
BOOL readEncodedFromStream( CodeChunk *_arg_chunk, FILE *_arg_stream ) {
uint8_t *iterator;
for( iterator = beginEncoded( _arg_chunk ); iterator != endEncoded( _arg_chunk ); iterator++ ) {
if( feof( _arg_stream ) )return 0;
int temp;
while( ( temp = fgetc( _arg_stream ) ) == '\n' )
if( feof( _arg_stream ) )return 0;
*iterator = temp;
}
return 1;
}
/*
* Write encoded string to the stream.
* First argument: target chunk
* Second argument: stream to write
*/
BOOL writeEncodedToStream( CodeChunk *_arg_chunk, FILE *_arg_stream ) {
uint8_t *iterator;
for( iterator = beginEncoded( _arg_chunk ); iterator != endEncoded( _arg_chunk ) && *iterator; iterator++ )
fputc( *iterator, _arg_stream );
return *iterator;
}
/*
* main function
*
*/
int main( int argc, char *argv[] ) {
int mode = MODE_ENCODE;
int chunks_per_line = 0;
int opt;
while( ( opt = getopt( argc, argv, "dehl:v" ) ) != -1 ) {
switch( opt ) {
case 'd':
mode = MODE_DECODE;
break;
case 'e':
mode = MODE_ENCODE;
break;
case 'h':
printf( usage );
exit( EXIT_SUCCESS );
case 'l':
if( sscanf( optarg, "%d", &chunks_per_line ) == EOF ) {
printf( "Invalid argument\n" );
exit( EXIT_FAILURE );
}
if( chunks_per_line < 0 ) {
printf( "Invalid argument\n" );
exit( EXIT_FAILURE );
}
break;
case 'v':
printf( version );
exit( EXIT_SUCCESS );
case ':':
printf( "Invalid argument\n" );
exit( EXIT_FAILURE );
}
}
CodeChunk chunk;
FILE *input;
FILE *output;
if( ( input = fdopen( 0, "r" ) ) == NULL ) {
perror( "fdopen( 0, \"r\" )" );
exit( EXIT_FAILURE );
}
if( ( output = fdopen( 1, "w" ) ) == NULL ) {
perror( "fdopen( 1, \"w\" )" );
exit( EXIT_FAILURE );
}
if( mode == MODE_ENCODE ) {
int newline_counter = 0;
while( 1 ) {
initChunk( &chunk );
if( !readRawFromStream( &chunk, input ) )break;
encodeChunk( &chunk );
writeEncodedToStream( &chunk, output );
newline_counter++;
if( chunks_per_line )
if( newline_counter == chunks_per_line ) {
fputc( '\n', output );
newline_counter = 0;
}
}
}
else {
while( 1 ) {
initChunk( &chunk );
if( !readEncodedFromStream( &chunk, input ) )break;
decodeChunk( &chunk );
writeRawToStream( &chunk, output );
}
}
fputc( '\n', output );
fclose( input );
fclose( output );
exit( EXIT_SUCCESS );
}
GL_ARB_multitexture
GL_ARB_multitexture
リアルタイム3Dの一つの時代を築いた拡張。これ自体はそれほど難しくもなく、様々なテクニックの基礎となる拡張なのでOpenGLの入門書から次の1歩を踏み出したい人が手を出すのに向いていると思う。
マルチテクスチャのための拡張なのだが、上のリンクを見ての通りOpenGL1.2.1で標準に取り込まれたということしか書かれていない。この拡張は標準に取り込まれて久しいので以下はOpenGL1.2.1以降のインターフェースについて説明する。
模様の描かれた移動する物体に影を落としたいとする。模様はテクスチャで面に貼りつけるわけだが、影を表現するためにもテクスチャが必要になり、かつこの2つのテクスチャはテクスチャ座標を共有していないため、あらかじめ2枚の画像を合成して1枚のテクスチャにしておくことは出来ない。
簡単に考えられる解法は模様の描かれたテクスチャを貼った物体に沿ってわずかに大きな半透明なガワをかぶせて、そこに影を描くことだ。が、この「わずかに」が想像以上に微妙だ。ガワが薄すぎると物体が小さく表示されたときに計算誤差が目立つ可能性があり、かといってガワを厚くすると視線とほぼ並行な面のテクスチャのずれが目立ってしまう可能性がある。その上頂点数は倍増してしまうし半透明を使うから描画順序にも気を付けなければならない。
GL_ARB_multitextureはこういう表現をしたいときに役に立つ。具体的にはマルチテクスチャ、すなわち1つの面に何枚もテクスチャを貼ることを可能にする。マルチテクスチャに対応したグラフィックデバイスには使用可能なマルチテクスチャの枚数だけテクスチャを処理する装置、テクスチャユニットが搭載されている。テクスチャユニットが何基搭載されているかは実装次第なので、使う前にいくつ使えるか調べておく必要がある。
たった4つとか言われてもめげてはいけない。ノートPC用のGPUとかではよくある話。マルチテクスチャの基本的な使いかたとしては、glActiveTextureでこれから操作するテクスチャユニットを切り替える。
textureにはGL_TEXTUREi ( iはテクスチャユニットの番号 )を指定する。
こんなかんじ。テクスチャ行列、バインドしたテクスチャオブジェクトや読み込んだテクスチャ、glTexParameterで設定したパラメタ、glPixelStore等はテクスチャユニットごとに設定されるのでそれぞれのユニットに対して設定する。デフォルトではGL_TEXTURE0になっている。つまりマルチテクスチャを使わないのと、GL_TEXTURE0しか使わないのは同義である。
GL_TEXTUREiはGL_TEXTURE0から順に値が連番になっていることが保証されていることを覚えておくと少しソースがスマートになるかもしれない。
テクスチャ座標を割り当てるにはglMultiTexCoordを使う。glTexCoordにどのテクスチャユニットについてという情報を付け足しただけで、第一引数にはやはりGL_TEXTUREiを用いる。
マルチテクスチャで複数のテクスチャが割り当てられた面の各フラグメントの色は
といった具合に乗算で合成される。影を重ねる場合は確かに乗算で期待した結果が得られるのだが、もっと複雑な式が表現できればより手の込んだ表現が可能になるため、そんな拡張がほしいところである。それに当たるのがGL_ARB_texture_env_combineだが、これについては別の機会に書こうと思う。
リアルタイム3Dの一つの時代を築いた拡張。これ自体はそれほど難しくもなく、様々なテクニックの基礎となる拡張なのでOpenGLの入門書から次の1歩を踏み出したい人が手を出すのに向いていると思う。
マルチテクスチャのための拡張なのだが、上のリンクを見ての通りOpenGL1.2.1で標準に取り込まれたということしか書かれていない。この拡張は標準に取り込まれて久しいので以下はOpenGL1.2.1以降のインターフェースについて説明する。
模様の描かれた移動する物体に影を落としたいとする。模様はテクスチャで面に貼りつけるわけだが、影を表現するためにもテクスチャが必要になり、かつこの2つのテクスチャはテクスチャ座標を共有していないため、あらかじめ2枚の画像を合成して1枚のテクスチャにしておくことは出来ない。
簡単に考えられる解法は模様の描かれたテクスチャを貼った物体に沿ってわずかに大きな半透明なガワをかぶせて、そこに影を描くことだ。が、この「わずかに」が想像以上に微妙だ。ガワが薄すぎると物体が小さく表示されたときに計算誤差が目立つ可能性があり、かといってガワを厚くすると視線とほぼ並行な面のテクスチャのずれが目立ってしまう可能性がある。その上頂点数は倍増してしまうし半透明を使うから描画順序にも気を付けなければならない。
GL_ARB_multitextureはこういう表現をしたいときに役に立つ。具体的にはマルチテクスチャ、すなわち1つの面に何枚もテクスチャを貼ることを可能にする。マルチテクスチャに対応したグラフィックデバイスには使用可能なマルチテクスチャの枚数だけテクスチャを処理する装置、テクスチャユニットが搭載されている。テクスチャユニットが何基搭載されているかは実装次第なので、使う前にいくつ使えるか調べておく必要がある。
glGetIntegerv( GL_MAX_TEXTURE_UNITS, &texture_units_num );
たった4つとか言われてもめげてはいけない。ノートPC用のGPUとかではよくある話。マルチテクスチャの基本的な使いかたとしては、glActiveTextureでこれから操作するテクスチャユニットを切り替える。
GLAPI void GLAPIENTRY glActiveTexture( GLenum texture );
textureにはGL_TEXTUREi ( iはテクスチャユニットの番号 )を指定する。
glActiveTexture( GL_TEXTURE2 );
こんなかんじ。テクスチャ行列、バインドしたテクスチャオブジェクトや読み込んだテクスチャ、glTexParameterで設定したパラメタ、glPixelStore等はテクスチャユニットごとに設定されるのでそれぞれのユニットに対して設定する。デフォルトではGL_TEXTURE0になっている。つまりマルチテクスチャを使わないのと、GL_TEXTURE0しか使わないのは同義である。
GL_TEXTUREiはGL_TEXTURE0から順に値が連番になっていることが保証されていることを覚えておくと少しソースがスマートになるかもしれない。
テクスチャ座標を割り当てるにはglMultiTexCoordを使う。glTexCoordにどのテクスチャユニットについてという情報を付け足しただけで、第一引数にはやはりGL_TEXTUREiを用いる。
GLAPI void GLAPIENTRY glMultiTexCoord1d( GLenum target, GLdouble s );
GLAPI void GLAPIENTRY glMultiTexCoord1dv( GLenum target, const GLdouble *v );
GLAPI void GLAPIENTRY glMultiTexCoord1f( GLenum target, GLfloat s );
GLAPI void GLAPIENTRY glMultiTexCoord1fv( GLenum target, const GLfloat *v );
GLAPI void GLAPIENTRY glMultiTexCoord1i( GLenum target, GLint s );
GLAPI void GLAPIENTRY glMultiTexCoord1iv( GLenum target, const GLint *v );
GLAPI void GLAPIENTRY glMultiTexCoord1s( GLenum target, GLshort s );
GLAPI void GLAPIENTRY glMultiTexCoord1sv( GLenum target, const GLshort *v );
GLAPI void GLAPIENTRY glMultiTexCoord2d( GLenum target, GLdouble s, GLdouble t );
GLAPI void GLAPIENTRY glMultiTexCoord2dv( GLenum target, const GLdouble *v );
GLAPI void GLAPIENTRY glMultiTexCoord2f( GLenum target, GLfloat s, GLfloat t );
GLAPI void GLAPIENTRY glMultiTexCoord2fv( GLenum target, const GLfloat *v );
GLAPI void GLAPIENTRY glMultiTexCoord2i( GLenum target, GLint s, GLint t );
GLAPI void GLAPIENTRY glMultiTexCoord2iv( GLenum target, const GLint *v );
GLAPI void GLAPIENTRY glMultiTexCoord2s( GLenum target, GLshort s, GLshort t );
GLAPI void GLAPIENTRY glMultiTexCoord2sv( GLenum target, const GLshort *v );
GLAPI void GLAPIENTRY glMultiTexCoord3d( GLenum target, GLdouble s, GLdouble t, GLdouble r );
GLAPI void GLAPIENTRY glMultiTexCoord3dv( GLenum target, const GLdouble *v );
GLAPI void GLAPIENTRY glMultiTexCoord3f( GLenum target, GLfloat s, GLfloat t, GLfloat r );
GLAPI void GLAPIENTRY glMultiTexCoord3fv( GLenum target, const GLfloat *v );
GLAPI void GLAPIENTRY glMultiTexCoord3i( GLenum target, GLint s, GLint t, GLint r );
GLAPI void GLAPIENTRY glMultiTexCoord3iv( GLenum target, const GLint *v );
GLAPI void GLAPIENTRY glMultiTexCoord3s( GLenum target, GLshort s, GLshort t, GLshort r );
GLAPI void GLAPIENTRY glMultiTexCoord3sv( GLenum target, const GLshort *v );
GLAPI void GLAPIENTRY glMultiTexCoord4d( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
GLAPI void GLAPIENTRY glMultiTexCoord4dv( GLenum target, const GLdouble *v );
GLAPI void GLAPIENTRY glMultiTexCoord4f( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
GLAPI void GLAPIENTRY glMultiTexCoord4fv( GLenum target, const GLfloat *v );
GLAPI void GLAPIENTRY glMultiTexCoord4i( GLenum target, GLint s, GLint t, GLint r, GLint q );
GLAPI void GLAPIENTRY glMultiTexCoord4iv( GLenum target, const GLint *v );
GLAPI void GLAPIENTRY glMultiTexCoord4s( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
GLAPI void GLAPIENTRY glMultiTexCoord4sv( GLenum target, const GLshort *v );
マルチテクスチャで複数のテクスチャが割り当てられた面の各フラグメントの色は
フラグメントの色 = 地の色 * TEXTURE0 * TEXTURE1 * ... * TEXTUREn
といった具合に乗算で合成される。影を重ねる場合は確かに乗算で期待した結果が得られるのだが、もっと複雑な式が表現できればより手の込んだ表現が可能になるため、そんな拡張がほしいところである。それに当たるのがGL_ARB_texture_env_combineだが、これについては別の機会に書こうと思う。
続ボードコンピュータ
探せばすごいモノが見付かるもので、
EM-X270 : CompuLab社製のハイエンドLinux/WindowsCEボードコンピュータ
Intel社製XScale PXA270 312MHz又は520MHz( + $12 )
128MB DDR-SDRAM
512MB 内蔵フラッシュメモリ
タッチスクリーン付き3.5インチVGA液晶 ( optional + $77 )
内蔵WiFi 802.11b ( optional + $26 )
内蔵Bluetooth
GPSレシーバ ( optional + $59 )
SDカードスロット
AC97サウンドデバイス
USBホストコントローラ
内蔵バッテリー ( optional + $10 )
slashdot情報
1000枚が基準価格で最小構成の場合$122、1枚だとオプションを加算した後2.5倍した価格になる。
ChangeLog-2.6.23
このデバイスの為のドライバは2.6.23カーネルに取り込まれているらしく、最新のカーネルであればバニラカーネルで動かせる筈。これだけ高機能なボードコンピュータなら普通にPC Linuxの感覚で運用が可能だろう。妥協の無いLinux環境一式を手のひらサイズに詰め込んで持ち歩く、これがいかに魅力的なものであるかはシャープのZaurusがいかにいじられてきたかを見れば明らかだ。が、非常に残念なことに、CompuLabから直接買えるのは法人のみで個人で欲しい場合は代売業者を探すように、となっているがこれを扱っている代売業者はさらっと探した限りでは見付からなかった...
玄人志向あたりこれを一般向けに製品化してくれないかな...
EM-X270 : CompuLab社製のハイエンドLinux/WindowsCEボードコンピュータ
Intel社製XScale PXA270 312MHz又は520MHz( + $12 )
128MB DDR-SDRAM
512MB 内蔵フラッシュメモリ
タッチスクリーン付き3.5インチVGA液晶 ( optional + $77 )
内蔵WiFi 802.11b ( optional + $26 )
内蔵Bluetooth
GPSレシーバ ( optional + $59 )
SDカードスロット
AC97サウンドデバイス
USBホストコントローラ
内蔵バッテリー ( optional + $10 )
slashdot情報
1000枚が基準価格で最小構成の場合$122、1枚だとオプションを加算した後2.5倍した価格になる。
ChangeLog-2.6.23
commit 3d50527bbf1b68e5206263ade414f0d966b00f74
Author: Mike Rapoport
Date: Wed Jul 18 11:31:46 2007 +0100
[ARM] 4475/2: EM-x270 board support
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Author: Mike Rapoport
Date: Wed Jul 18 11:31:46 2007 +0100
[ARM] 4475/2: EM-x270 board support
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
このデバイスの為のドライバは2.6.23カーネルに取り込まれているらしく、最新のカーネルであればバニラカーネルで動かせる筈。これだけ高機能なボードコンピュータなら普通にPC Linuxの感覚で運用が可能だろう。妥協の無いLinux環境一式を手のひらサイズに詰め込んで持ち歩く、これがいかに魅力的なものであるかはシャープのZaurusがいかにいじられてきたかを見れば明らかだ。が、非常に残念なことに、CompuLabから直接買えるのは法人のみで個人で欲しい場合は代売業者を探すように、となっているがこれを扱っている代売業者はさらっと探した限りでは見付からなかった...
玄人志向あたりこれを一般向けに製品化してくれないかな...
ボードコンピュータ
なんだか凄いものを発見した。
TS-7800 : Technologic Systems社製のハイエンドLinuxボードコンピュータ
Marvell社製ARM9 500MHz
128MB DDR-SDRAM
512MB 内蔵フラッシュメモリ
SATA端子2つ
ブート可能マイクロSDスロット
ブート可能SDカードスロット
PC/104スロット
JTAGデバッガ端子
ホストコントローラ付きUSB端子2つ
ギガビットEthernet
消費電力4W
ARM組み込み基盤で500MHzって一体...
ボード単体で$269という価格がにわかには信じがたい。開発キットは別売り$100で、Debianがインストールされた2GBのSDカードが付属する。日本から買えるかなぁ。
TS-7400 : 同じくTechnologic Systems社製のローコストLinuxボードコンピュータ
CIRRUS LOGIC社製ARM9 200MHz
ECC付き32MB DDR-SDRAM
32MB 内蔵フラッシュメモリ
ブート可能SDカードスロット
ホストコントローラ付きUSB端子2つ
100base-TX Ethernet
消費電力1.75W
こちらは機能面ではあまりパッとしないが、お値段$99。組み込みLinux基盤が$100切ったか...
しかし何故か開発キットはTS-7800より高く$200。
TS-7KV : TS-7xxx系ボードコンピュータ用PC/104接続ビデオカード
同時発色数65536色
解像度 640x480
VRAM 8MB
Linux fbdevドライバ付き
Qt/Embedded対応
このメーカーのボードコンピュータのPC/104拡張スロットにはちゃんと取り付けるドライバ付きのデバイスが最初から存在する。それも結構いろいろなカードが存在する。中でも目を引くのがビデオカード、お値段$99。組み込み基盤がまるでPC組み立てのようだ。
電源は5Vだしコレでいいかな。秋月に置いてある時点で素直にiPodに繋ぐために買う人は居ない気がする。
TS-7800 : Technologic Systems社製のハイエンドLinuxボードコンピュータ
Marvell社製ARM9 500MHz
128MB DDR-SDRAM
512MB 内蔵フラッシュメモリ
SATA端子2つ
ブート可能マイクロSDスロット
ブート可能SDカードスロット
PC/104スロット
JTAGデバッガ端子
ホストコントローラ付きUSB端子2つ
ギガビットEthernet
消費電力4W
ARM組み込み基盤で500MHzって一体...
ボード単体で$269という価格がにわかには信じがたい。開発キットは別売り$100で、Debianがインストールされた2GBのSDカードが付属する。日本から買えるかなぁ。
TS-7400 : 同じくTechnologic Systems社製のローコストLinuxボードコンピュータ
CIRRUS LOGIC社製ARM9 200MHz
ECC付き32MB DDR-SDRAM
32MB 内蔵フラッシュメモリ
ブート可能SDカードスロット
ホストコントローラ付きUSB端子2つ
100base-TX Ethernet
消費電力1.75W
こちらは機能面ではあまりパッとしないが、お値段$99。組み込みLinux基盤が$100切ったか...
しかし何故か開発キットはTS-7800より高く$200。
TS-7KV : TS-7xxx系ボードコンピュータ用PC/104接続ビデオカード
同時発色数65536色
解像度 640x480
VRAM 8MB
Linux fbdevドライバ付き
Qt/Embedded対応
このメーカーのボードコンピュータのPC/104拡張スロットにはちゃんと取り付けるドライバ付きのデバイスが最初から存在する。それも結構いろいろなカードが存在する。中でも目を引くのがビデオカード、お値段$99。組み込み基盤がまるでPC組み立てのようだ。
電源は5Vだしコレでいいかな。秋月に置いてある時点で素直にiPodに繋ぐために買う人は居ない気がする。
GL_SGIS_generate_mipmap
GL_SGIS_generate_mipmap
ほんの少し便利で、ほんの少しパフォーマンスも向上するかもしれない、ほんの少し嬉しくなる拡張。
ミップマップとはテクスチャが拡大縮小されてもそれなりの画質を維持できるように、全てリアルタイムで拡大縮小しようとせずにあらかじめ同じ画像を綺麗にサイズ変更したモノをVRAMに持っておく、というもの。このへんはOpenGLの入門書とかにもよく書いてあるからそちらを見てもらうとして、このミップマップ、本来は手作業で作るのだがはっきり言ってめんどくさい。
そこでGLUに以下のような関数が用意されている。
これらの関数を使うと簡単にミップマップを作れるのだが、GLUはあくまで実装に依存しないユーティリティなのでこの関数はCPU側でミップマップを生成してglTexImage[1-3]D関数を呼び出していることになる。このオーバーヘッドに理不尽さを感じる人もいるだろう。
そこで登場するのがGL_SGIS_generate_mipmap拡張だ。この拡張を有効にすると1枚の元画像をグラフィックデバイスに転送するだけで自動的にGPUがミップマップを生成する。上の関数と異なりミップマップ生成のためにCPUリソースを使ったり、似たような画像をいくつも転送するために帯域を余計に消費することは無い。
使いかたは、まずテクスチャを転送する前に拡張を有効にする。この設定はテクスチャターゲット毎に行う必要がある( ここではとりあえずGL_TEXTURE_2D )。
そしておもむろにテクスチャを転送する。
そして拡大縮小時にミップマップを使うようにする。
すると自分で作った覚えの無いミップマップが使用される。このミップマップはハードウェアが対応していればグラフィックデバイス側で生成されるため、CPUの負担も帯域の負担も軽減できる可能性がある。
ちなみにこの拡張はOpenGL1.4で標準仕様に取り込まれたため、これ以降のバージョンを対象にプログラムを書くのであれば拡張の有無のチェック等は不要である。あわせて、末尾にSGISの付かない定数GL_GENERATE_MIPMAPも定義されている。
ほんの少し便利で、ほんの少しパフォーマンスも向上するかもしれない、ほんの少し嬉しくなる拡張。
ミップマップとはテクスチャが拡大縮小されてもそれなりの画質を維持できるように、全てリアルタイムで拡大縮小しようとせずにあらかじめ同じ画像を綺麗にサイズ変更したモノをVRAMに持っておく、というもの。このへんはOpenGLの入門書とかにもよく書いてあるからそちらを見てもらうとして、このミップマップ、本来は手作業で作るのだがはっきり言ってめんどくさい。
そこでGLUに以下のような関数が用意されている。
fadis@Virginia[~] $ cat /usr/include/GL/glu.h |egrep -E "gluBuild[1-3]DMipmaps"
GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
fadis@Virginia[~] $
GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
fadis@Virginia[~] $
これらの関数を使うと簡単にミップマップを作れるのだが、GLUはあくまで実装に依存しないユーティリティなのでこの関数はCPU側でミップマップを生成してglTexImage[1-3]D関数を呼び出していることになる。このオーバーヘッドに理不尽さを感じる人もいるだろう。
そこで登場するのがGL_SGIS_generate_mipmap拡張だ。この拡張を有効にすると1枚の元画像をグラフィックデバイスに転送するだけで自動的にGPUがミップマップを生成する。上の関数と異なりミップマップ生成のためにCPUリソースを使ったり、似たような画像をいくつも転送するために帯域を余計に消費することは無い。
使いかたは、まずテクスチャを転送する前に拡張を有効にする。この設定はテクスチャターゲット毎に行う必要がある( ここではとりあえずGL_TEXTURE_2D )。
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
そしておもむろにテクスチャを転送する。
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, image );
そして拡大縮小時にミップマップを使うようにする。
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
すると自分で作った覚えの無いミップマップが使用される。このミップマップはハードウェアが対応していればグラフィックデバイス側で生成されるため、CPUの負担も帯域の負担も軽減できる可能性がある。
ちなみにこの拡張はOpenGL1.4で標準仕様に取り込まれたため、これ以降のバージョンを対象にプログラムを書くのであれば拡張の有無のチェック等は不要である。あわせて、末尾にSGISの付かない定数GL_GENERATE_MIPMAPも定義されている。