GLMetaseq.c の中身 渡部修平 メタセコイアで作成した 3D モデルを OpenGL で表示させるためには, 工学ナビ ( が公開している C/C++ 用のライブラリ GLMetaseq があ

Similar documents
(4) モデルの消去 mqodeletemodel( model ); (5) 終了処理 ( プログラム終了時にやってください ) mqocleanup(); 3. 使い方 (2) 連番ファイルを読み込んで表示する場合 (1) 初期化 (ARToolKit の場合,argInit() の後に使用 )

ファイル入出力

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Microsoft Word - Cプログラミング演習(10)

02: 変数と標準入出力

Taro-ファイル処理(公開版).jtd

コンピュータグラフィックスS 演習資料

02: 変数と標準入出力

memo

プログラミング基礎

02: 変数と標準入出力

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

PowerPoint Presentation

PowerPoint Presentation

画像ファイルを扱う これまでに学んだ条件分岐, 繰り返し, 配列, ファイル入出力を使って, 画像を扱うプログラムにチャレンジしてみよう

Microsoft Word - no15.docx

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

スライド 1

Microsoft PowerPoint - prog04.ppt

PowerPoint プレゼンテーション

AquesTalk Win Manual

Microsoft PowerPoint - 14th.ppt [互換モード]

情報処理演習 B8クラス

AquesTalk プログラミングガイド

PowerPoint Presentation

AquesTalk for WinCE プログラミングガイド

Microsoft PowerPoint - 5Chap15.ppt

Microsoft PowerPoint - info_eng3_05ppt.pptx

Microsoft PowerPoint - 09.pptx

Microsoft Word - Cプログラミング演習(12)

スライド 1

ARToolKit プログラムの仕組み 1: ヘッダファイルのインクルード 2: Main 関数 3: Main Loop 関数 4: マウス入力処理関数 5: キーボード入力処理関数 6: 終了処理関数 3: Main Loop 関数 1カメラ画像の取得 2カメラ画像の描画 3マーカの検出と認識

1. 入力した正の整数を降順に並べ換えて出力するプログラムを作成せよ プログラムは個別にコンパイルし make コマンドで実行すること 入力データは 50 以下とし 以下の数が混在しているとする 16 進数 : 先頭 1 文字が x または X( エックスの小文字か大文字 ) 8 進数 : 先頭 1

演算増幅器

1 1. Program 1 OpenCV (OpenCV Sample001) 1 /* 2 - > - > - >VC++ 3 ( ) 4 C:\opencv\build\include 5 ( ) 6 C:\opencv\build\x86\vc10\lib 7 - > - > - > - >

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

Java講座

Taro-ポインタ変数Ⅰ(公開版).j

新・明解C言語 実践編

問 2 ( 型変換 ) 次のプログラムを実行しても正しい結果が得られない 何が間違いかを指摘し 正しく修正せよ ただし int サイズが 2 バイト long サイズが 4 バイトの処理系での演算を仮定する #include <stdio.h> int main( void ) { int a =

AquesTalk2 Win マニュアル&ライセンス規定

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

PowerPoint プレゼンテーション

JavaプログラミングⅠ

第1回 プログラミング演習3 センサーアプリケーション

Fair Curve and Surface Design System Using Tangent Control

Transcription:

GLMetaseq.c の中身 0810960080 渡部修平 メタセコイアで作成した 3D モデルを OpenGL で表示させるためには, 工学ナビ (http://kougakunavi.net/artoolkit.html) が公開している C/C++ 用のライブラリ GLMetaseq があります 作成しているぷろぐらむのプロジェクトに GLMetaseq.h と GLMetaseq.hc を追加し, プログラム中で GLMetaseq.h をインクルードして使用します 以下は GLMeataseq.c のソースです #define GLMETASEQ_C #include "GLMetaseq.h" /* GLMetaseq MIT ライセンス Copyright (c) 2009 Sunao Hashimoto and Keisuke Konishi 以下に定める条件に従い 本ソフトウェアおよび関連文書のファイル ( 以下 ソフトウェア ) の複製を取得するすべての人に対し ソフトウェアを無制限に扱うことを無償で許可します これには ソフトウェアの複製を使用 複写 変更 結合 掲載 頒布 サブライセンス および / または販売する権利 およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます 上記の著作権表示および本許諾表示を ソフトウェアのすべての複製または重要な部分に記載するものとします ソフトウェアは 現状のまま で 明示であるか暗黙であるかを問わず 何らの保証もなく提供されます ここでいう保証とは 商品性 特定の目的への適合性 および権利非侵害についての保証も含みますが それに限定されるものではありません 作者または著作権者は 契約行為 不法行為 またはそれ以外であろうと ソフトウェアに起因または関連し あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求 損害 その他の義務について何らの責任も負わないものとします */ このソース内でのみ有効なグローバル変数 static TEXTURE_POOL l_texpool[max_texture]; // テクスチャプール static int l_texpoolnum; // テクスチャの数 static int l_glmetaseqinitialized = 0; // 初期化フラグ 関数宣言 #ifdef cplusplus extern "C" void endianconverter(void *addr,unsigned int size); void TGAHeaderEndianConverter( STR_TGA_HEAD *tgah ); int IsExtensionSupported( char* sztargetextension ); GLuint mqosettexturepool(char *texfile, char *alpfile, unsigned char alpha ); void mqocleartexturepool(); GLubyte* mqoloadtextureex(char *texfile,char *alpfile,int *tex_size,unsigned char alpha); int mqoloadfile(mqo_object *mqoobj,char *filename,double scale,unsigned char alpha);

MQO_OBJECT* int mqocreatelist(int num); mqocreatelistobject( MQO_OBJECT *obj, int id, char *filename,double scale,unsigned char alpha); void void void void void void void int void void mqocalllistobject(mqo_object object[],int num); mqoclearobject(mqo_object object[],int from,int num); mqodeleteobject(mqo_object * object,int num); mqogetdirectory(const char *path_file, char *path_dir); mqosnormal(glpoint3f A, glpoint3f B, glpoint3f C, glpoint3f *normal); mqoreadmaterial(file *fp, MQO_MATDATA M[]); mqoreadvertex(file *fp, glpoint3f V[]); mqoreadbvertex(file *fp,glpoint3f V[]); mqoreadface(file *fp, MQO_FACE F[]); mqoreadobject(file *fp, MQO_OBJDATA *obj); void mqomakearray(mqo_material *mat, int matpos,mqo_face F[], int fnum,glpoint3f V[], glpoint3f N[], double facet, glcolor4f *mcol, double scale, unsigned char alpha ); glpoint3f *mqovertexnormal(mqo_objdata *obj); void mqomakepolygon(mqo_objdata *readobj, MQO_OBJECT *mqoobj, glpoint3f N[], MQO_MATDATA M[], int n_mat, double scale, unsigned char alpha); void mqomakeobjectsex(mqo_object *mqoobj, MQO_OBJDATA obj[], int n_obj, MQO_MATDATA M[],int n_mat, double scale,unsigned char alpha); #ifdef cplusplus 関数 endianconverter 用途 エンディアン変換 引数 addr アドレス size サイズ 戻値 なし void endianconverter(void *addr,unsigned int size) unsigned int pos; char c; if ( size <= 1 ) return; for ( pos = 0; pos < size/2; pos++ ) c = *(((char *)addr)+pos); *(((char *)addr)+pos) = *(((char *)addr)+(size-1 - pos)); *(((char *)addr)+(size-1 - pos)) = c; 関数 TGAHeaderEndianConverter 用途 TGAのヘッダのエンディアン変換 引数 tgah TGAのヘッダ 戻値 なし void TGAHeaderEndianConverter( STR_TGA_HEAD *tgah ) endianconverter(&tgah->color_map_entry,sizeof(tgah->color_map_entry)); endianconverter(&tgah->x,sizeof(tgah->x)); endianconverter(&tgah->y,sizeof(tgah->y)); endianconverter(&tgah->width,sizeof(tgah->width));

endianconverter(&tgah->height,sizeof(tgah->height)); 関数 IsExtensionSupported 用途 OpenGL の拡張機能がサポートされているかどうか調べる 引数 sztargetextension 拡張機能の名前 戻値 : サポートされている,: されていない int IsExtensionSupported( char* sztargetextension ) const unsigned char *pszextensions = NULL; const unsigned char *pszstart; unsigned char *pszwhere, *pszterminator; // Extension の名前が正しいか調べる (NULL や空白は NG) pszwhere = (unsigned char *) strchr( sztargetextension, ' ' ); if ( pszwhere *sztargetextension == (char)null ) return 0; // Extension の文字列を所得する pszextensions = glgetstring( GL_EXTENSIONS ); // 文字列の中に必要な extension があるか調べる pszstart = pszextensions; for (;;) pszwhere = (unsigned char *) strstr( (const char *) pszstart, sztargetextension ); if (!pszwhere ) break; pszterminator = pszwhere + strlen( sztargetextension ); if ( pszwhere == pszstart *( pszwhere - 1 ) == ' ' ) if ( *pszterminator == ' ' *pszterminator == (char)null ) return 1; pszstart = pszterminator; return 0; 関数 mqoinit 用途 メタセコイアローダの初期化 引数 なし 戻値 なし void mqoinit(void) // テクスチャプール初期化 memset(l_texpool,0,sizeof(l_texpool)); l_texpoolnum = 0; // 頂点バッファのサポートのチェック g_isvbosupported = IsExtensionSupported("GL_ARB_vertex_buffer_object"); // g_isvbosupported = 0; #ifdef WIN32 glgenbuffersarb = NULL; glbindbufferarb = NULL; glbufferdataarb = NULL; gldeletebuffersarb = NULL;

if ( g_isvbosupported ) // printf("opengl : 頂点バッファをサポートしているので使用します \n"); // GL 関数のポインタを所得する glgenbuffersarb = (PFNGLGENBUFFERSARBPROC) wglgetprocaddress("glgenbuffersarb"); glbindbufferarb = (PFNGLBINDBUFFERARBPROC) wglgetprocaddress("glbindbufferarb"); glbufferdataarb = (PFNGLBUFFERDATAARBPROC) wglgetprocaddress("glbufferdataarb"); gldeletebuffersarb = (PFNGLDELETEBUFFERSARBPROC) wglgetprocaddress("gldeletebuffersarb"); // 初期化フラグ l_glmetaseqinitialized = 1; 関数 mqocleanup 用途 メタセコイアローダの終了処理 引数 なし 戻値 なし void mqocleanup(void) mqocleartexturepool(); // テクスチャプールのクリア 関数 mqosettexturepool 用途 テクスチャプールにテクスチャを読み込む 引数 texfile テクスチャファイル名 alpfile アルファファイル名 alpha アルファ 戻値 テクスチャ ID 仕様 テクスチャがまだ読み込まれていなければ読み込み, テクスチャ登録すでに読み込まれていれば登録したものを返す. GLuint mqosettexturepool(char *texfile, char *alpfile, unsigned char alpha ) int pos; GLubyte *image; for ( pos = 0; pos < l_texpoolnum; pos++ ) if ( alpha!= l_texpool[pos].alpha ) continue; if ( texfile!= NULL ) if ( strcmp(texfile,l_texpool[pos].texfile)!= 0 ) continue; if ( alpfile!= NULL ) if ( strcmp(alpfile,l_texpool[pos].alpfile)!= 0 ) continue; break; if ( pos < l_texpoolnum ) // すでに読み込み済み return l_texpool[pos].texture_id; if ( MAX_TEXTURE <= pos ) printf("%s:mqosettexturepool テクスチャ読み込み領域不足 \n", FILE );

return -1; image = mqoloadtextureex(texfile,alpfile,&l_texpool[pos].texsize,alpha); if ( image == NULL ) return -1; if ( texfile!= NULL ) strncpy(l_texpool[pos].texfile,texfile,max_path); if ( alpfile!= NULL ) strncpy(l_texpool[pos].alpfile,alpfile,max_path); l_texpool[pos].alpha = alpha; glpixelstorei(gl_unpack_alignment,4); glpixelstorei(gl_pack_alignment,4); glgentextures(1,&l_texpool[pos].texture_id); glbindtexture(gl_texture_2d,l_texpool[pos].texture_id); // テクスチャを生成 // テクスチャの割り当て gltexparameteri(gl_texture_2d, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gltexparameteri(gl_texture_2d, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glteximage2d(gl_texture_2d, 0, GL_RGBA8, l_texpool[pos].texsize, l_texpool[pos].texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); l_texpoolnum = pos+1; // 登録すれば 読み込んだバッファは不要 free(image); glbindtexture(gl_texture_2d,0); // デフォルトテクスチャの割り当て return l_texpool[pos].texture_id; 関数 mqocleartexturepool() 用途 テクスチャプールの開放 引数 なし 戻値 なし void mqocleartexturepool() int pos; for ( pos = 0; pos < l_texpoolnum; pos++ ) gldeletetextures(1, &l_texpool[pos].texture_id); // テクスチャ情報を削除 memset(l_texpool,0,sizeof(l_texpool)); l_texpoolnum = 0; 関数 mqoloadtextureex 用途 ファイルからテクスチャ画像を作成する 引数 texfile ファイル名 alpfile アルファファイル名 tex_size テクスチャのサイズ ( 一辺の長さ ) を返す 戻値 テクスチャ画像へのポインタ ( 失敗時は NULL) 仕様 bit ビットマップ, および,24,32bitTGA サイズは 一辺がの n 乗の正方形 に限定 libjpeg,libpng( 外部ライブラリ ) が有れば JPEG,PNG の読み込み可能 GLubyte* mqoloadtextureex(char *texfile,char *alpfile,int *tex_size,unsigned char alpha) FILE *fp;

size_t namelen; char ext[4]; char wbuf[3]; int istga; int ispng; int isjpeg; int other; int y,x,size; int fl; char *filename[2]; int width[2]; int sts; STR_TGA_HEAD tgah; GLubyte *pimage, *pread; #if DEF_USE_LIBJPEG struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY jpegimage; #if DEF_USE_LIBPNG unsigned char **pngimage; unsigned long pngwidth, pngheight; int int color_type; pngdepth; filename[0] = texfile; filename[1] = alpfile; width[0] = -1; width[1] = -1; pimage = NULL; fp = NULL; sts = 0; #if DEF_USE_LIBJPEG jpegimage = NULL; #if DEF_USE_LIBPNG pngimage = NULL; size = - 1; for ( fl = 0; fl < 2; fl++ ) // テクスチャ =fl=0 アルファ =fl=1 if ( filename[fl] == NULL ) continue; namelen = strlen(filename[fl]); ext[0] = tolower(filename[fl][namelen-3]); ext[1] = tolower(filename[fl][namelen-2]); ext[2] = tolower(filename[fl][namelen-1]); ext[3] = 0x00; istga = (strcmp(ext,"tga")==0)?1:0; ispng = (strcmp(ext,"png")==0)?1:0; isjpeg = (strcmp(ext,"jpg")==0)?1:0; /* */ if ( (! istga) && (! ispng) &&(! isjpeg) ) filename[fl][namelen-3] = 'b'; filename[fl][namelen-2] = 'm'; filename[fl][namelen-1] = 'p'; /* */ if ( fl == 1 ) // アルファの読み込みは TGAorPNG if (! (istga ispng) ) printf(" アルファのファイルに対応できない %s\n",filename[fl]); break; if ( fp!= NULL ) fclose(fp); if ( (fp=fopen(filename[fl],"rb"))==null ) printf("%s: テクスチャ読み込みエラー [%s]\n", FILE,filename[fl]); continue;

// ヘッダのロード if ( istga ) fread(&tgah,sizeof(str_tga_head),1,fp); #if DEF_IS_LITTLE_ENDIAN #else TGAHeaderEndianConverter(&tgah); size = width[fl] = tgah.width; if ( isjpeg ) #if DEF_USE_LIBJPEG unsigned int i; cinfo.err = jpeg_std_error( &jerr ); jpeg_create_decompress( &cinfo ); // 解凍用情報作成 jpeg_stdio_src( &cinfo, fp ); // 読み込みファイル指定 jpeg_read_header( &cinfo, TRUE ); //jpegヘッダ読み込み jpeg_start_decompress( &cinfo ); // 解凍開始 if ( cinfo.out_color_components == 3 && cinfo.out_color_space == JCS_RGB ) if ( jpegimage!= NULL ) for (i = 0; i < cinfo.output_height; i++) free(jpegimage[i]); // 以下 2 行は2 次元配列を解放します free(jpegimage); // 読み込みデータ配列の作成 jpegimage = (JSAMPARRAY)malloc( sizeof( JSAMPROW ) * cinfo.output_height ); for ( i = 0; i < cinfo.output_height; i++ ) jpegimage[i] = (JSAMPROW)malloc( sizeof( JSAMPLE ) * cinfo.out_color_components * cinfo.output_width ); // 解凍データ読み込み while( cinfo.output_scanline < cinfo.output_height ) jpeg_read_scanlines( &cinfo, jpegimage + cinfo.output_scanline, cinfo.output_height - cinfo.output_scanline ); size = width[fl] = cinfo.output_width; jpeg_finish_decompress( &cinfo ); // 解凍終了 jpeg_destroy_decompress( &cinfo ); // 解凍用情報解放 if (!(cinfo.out_color_components == 3 && cinfo.out_color_space == JCS_RGB) ) printf("jpeg 対応できないフォーマット %s\n",filename[fl]); #else printf(" このテクスチャは対応できないフォーマット %s\n",filename[fl]); continue; if ( ispng ) #if DEF_USE_LIBPNG png_structp png_ptr; png_infop info_ptr; int bit_depth, interlace_type; unsigned int i; int j,k; png_ptr = png_create_read_struct( // png_ptr 構造体を確保 初期化します PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); // info_ptr 構造体を確保 初期化します png_init_io(png_ptr, fp); // libpngにfpを知らせます png_read_info(png_ptr, info_ptr); // PNGファイルのヘッダを読み込みます png_get_ihdr(png_ptr, info_ptr, &pngwidth, &pngheight, // IHDRチャンク情報を取得します &bit_depth, &color_type, &interlace_type, &j,&k); if ( pngimage!= NULL )

す す for (i = 0; i < pngheight; i++) free(pngimage[i]); // 以下 2 行は 2 次元配列を解放しま free(pngimage); pngimage = (png_bytepp)malloc(pngheight * sizeof(png_bytep)); // 以下 3 行は2 次元配列を確保しま i = png_get_rowbytes(png_ptr, info_ptr); pngdepth = i / pngwidth; for (i = 0; i < pngheight; i++) pngimage[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr)); png_read_image(png_ptr, pngimage); // 画像データを読み込みます png_destroy_read_struct( // 2つの構造体のメモリを解放します &png_ptr, &info_ptr, (png_infopp)null); size = width[fl] = pngwidth; #else printf(" このテクスチャは対応できないフォーマット %s\n",filename[fl]); continue; if ( width[fl] == -1 ) // ココまできてサイズが指定されていない = ビットマップ fseek(fp,14+4,seek_set); // 画像幅が格納されている位置までシーク fread(&size,sizeof(int),1,fp); // BiWidthの情報だけ取得 fseek(fp,14+40,seek_set); // 画素データが格納されている位置までシーク #if DEF_IS_LITTLE_ENDIAN #else endianconverter(&size,sizeof(int)); width[fl] = size; if ( width[0]!= -1 && width[1]!= -1 ) if ( width[0]!= width[1] ) sts = -1; break; if ( fl == 1 && istga ) // アルファの読み込みはTGAの8ビットモノクロor32ビットフル if (!( (tgah.depth == 8 && tgah.type == DEF_TGA_TYPE_MONO) (tgah.depth == 32 && tgah.type == DEF_TGA_TYPE_FULL) ) ) break; if ( fl == 1 && ispng ) // アルファの読み込みはPNGのトゥルーカラー +アルファorグレースケール+アルファ #if DEF_USE_LIBPNG if (!( (color_type== 6 ) (color_type== 4 ) ) ) break; // メモリの確保 if ( pimage == NULL ) pimage = (GLubyte*)malloc(sizeof(unsigned char)*size*size*4); if (pimage==null) return NULL; for (y=0; y<size; y++) pread = pimage + (size-1-y)*4*size; for (x=0; x<size; x++) other = 1; if ( fl == 0 )

#if DEF_USE_LIBJPEG #if DEF_USE_LIBPNG #if DEF_USE_LIBPNG fclose(fp); fp = NULL; else if ( isjpeg ) if ( ispng ) pread[0]= jpegimage[size-1-y][x*3]; pread[1]= jpegimage[size-1-y][x*3+1]; pread[2]= jpegimage[size-1-y][x*3+2]; pread[3] = alpha; other = 0; // A if ( color_type == 2 color_type==6 ) pread[0]= pngimage[size-1-y][x*pngdepth]; pread[1]= pngimage[size-1-y][x*pngdepth+1]; pread[2]= pngimage[size-1-y][x*pngdepth+2]; pread[3] = alpha; other = 0; // A if ( color_type == 6 ) pread[3]= pngimage[size-1-y][x*pngdepth+3]; if ( other ) fread(&pread[2],1,1,fp); // B fread(&pread[1],1,1,fp); // G fread(&pread[0],1,1,fp); // R pread[3] = alpha; // A if ( istga && tgah.depth == 32 ) fread(&pread[3],1,1,fp); // A if ( alpha < pread[3] ) pread[3] = alpha; if ( ispng ) if ( sts!= 0 ) if ( pimage!= NULL ) free(pimage); if ( fp!= NULL ) fclose(fp); #if DEF_USE_LIBPNG if ( pngimage!= NULL ) unsigned int uy; if ( color_type == 6 ) // トゥルーカラー + アルファ pread[3]= pngimage[size-1-y][x*pngdepth+3]; if ( color_type == 4 ) // グレースケール + アルファ pread[3]= pngimage[size-1-y][x*pngdepth+1]; if ( alpha < pread[3] ) pread[3] = alpha; if ( istga ) if ( tgah.depth == 32 ) // いらないデータを読み飛ばす fread(wbuf,3,1,fp); // BGR fread(&pread[3],1,1,fp); // A if ( alpha < pread[3] ) pread[3] = alpha; pread+=4; for (uy = 0; uy < pngheight; uy++) free(pngimage[uy]); free(pngimage); // 以下 2 行は 2 次元配列を解放します

#if DEF_USE_LIBJPEG if ( jpegimage!= NULL ) unsigned int uy; for (uy = 0; uy < cinfo.output_height; uy++) free(jpegimage[uy]); free(jpegimage); if ( size < 0 ) if ( pimage!= NULL ) free(pimage); pimage = NULL; *tex_size = size; // 以下 2 行は 2 次元配列を解放します return pimage; 関数 mqoloadfile 用途 メタセコイアファイル(*.mqo) からデータを読み込む 引数 mqoobj MQOオブジェクト filename ファイルのパス scale 拡大率 alpha アルファ 戻値 成功 :/ 失敗 : int mqoloadfile( MQO_OBJECT *mqoobj, char *filename, double scale, unsigned char alpha) FILE *fp; MQO_OBJDATA obj[max_object]; MQO_MATDATA *M = NULL; char buf[size_str]; // 文字列読み込みバッファ char path_dir[size_str]; // ディレクトリのパス char path_tex[size_str]; // テクスチャファイルのパス char path_alp[size_str]; // アルファテクスチャファイルのパス int n_mat = 0; // マテリアル数 int n_obj = 0; // オブジェクト数 int i; // Material と Object の読み込み fp = fopen(filename,"rb"); if (fp==null) return 0; mqoobj->alpha = alpha; memset(obj,0,sizeof(obj)); i = 0; while (!feof(fp) ) fgets(buf,size_str,fp); // Material if (strstr(buf,"material")) sscanf(buf,"material %d", &n_mat); M = (MQO_MATDATA*) calloc( n_mat, sizeof(mqo_matdata) ); mqoreadmaterial(fp,m); // Object if (strstr(buf,"object")) sscanf(buf,"object %s", obj[i].objname); mqoreadobject(fp, &obj[i]);

n_obj = i; fclose(fp); i++; // パスの取得 mqogetdirectory(filename, path_dir); // テクスチャの登録 for (i=0; i<n_mat; i++) if (M[i].useTex) if (strstr(m[i].texfile,":")) strcpy(path_tex, M[i].texFile); // 絶対パスの場合 else sprintf(path_tex,"%s%s",path_dir,m[i].texfile); // 相対パスの場合 if ( M[i].alpFile[0]!= (char)0 ) if (strstr(m[i].texfile,":")) strcpy(path_alp, M[i].alpFile); else else // 絶対パスの場合 sprintf(path_alp,"%s%s",path_dir,m[i].alpfile); // 相対パスの場合 M[i].texName = mqosettexturepool(path_tex,path_alp,alpha); M[i].texName = mqosettexturepool(path_tex,null,alpha); mqomakeobjectsex( mqoobj, obj, n_obj, M, n_mat, scale, alpha ); // オブジェクトのデータの開放 for (i=0; i<n_obj; i++) free(obj[i].v); free(obj[i].f); // マテリアルの開放 free(m); return 1; 関数 mqocreatelist 用途 MQOオブジェクトを指定数確保する 引数 num MQOオブジェクトの数 戻値 MQO オブジェクト MQO_OBJECT* mqocreatelist(int num) MQO_OBJECT *obj; // 初期化されてなかったら初期化 if (! l_glmetaseqinitialized ) mqoinit(); // 領域確保と初期化 obj = (MQO_OBJECT *)malloc(sizeof(mqo_object)*num); memset(obj, 0, sizeof(mqo_object)*num);

return obj; 関数 mqocreatelistobject 用途 メタセコイアファイル (*.mqo) から MQO オブジェクト配列を作成する 引数 mqoobj MQOオブジェクト i 読み込み先番号 (i 番目にMQOファイルを読み込む ) filename ファイルのパス scale 拡大率 alpha アルファ指定 ( 全体のアルファ値を指定 (~)) 戻値 ステータス負 : 異常 0: 正常 int mqocreatelistobject(mqo_object *mqoobj, int i, char *filename, double scale, unsigned char alpha ) int ret; ret = 0; if ( mqoobj == (MQO_OBJECT *)NULL ) return -1; if (! mqoloadfile(&mqoobj[i], filename, scale, alpha)) ret = -1; return ret; 関数 mqocalllistobject 用途 MQOオブジェクトをOpenGLの画面上に呼び出す 引数 mqoobj MQOオブジェクト配列 num 配列番号 (0~) 戻値 なし void mqocalllistobject(mqo_object mqoobj[],int num) MQO_INNER_OBJECT *obj; MQO_MATERIAL *mat; GLfloat matenv[4]; GLint bindgl_texture_2d = 0; GLboolean isgl_texture_2d = GL_FALSE; GLboolean isgl_blend = GL_FALSE; GLint blendgl_src_alpha = 0; GLint intfrontface; int double char dalpha; *base; o, m, offset; if ( mqoobj == NULL) return; glpushmatrix(); // メタセコは頂点の並びが表面からみて右回り glgetintegerv(gl_front_face,&intfrontface); glfrontface(gl_cw); dalpha = (double)mqoobj[num].alpha/(double)255; for ( o=0; o<mqoobj[num].objnum; o++ ) // 内部オブジェクトループ obj = &mqoobj[num].obj[o]; if (! obj->isvisible ) continue; glshademodel(((obj->isshadingflat))?gl_flat:gl_smooth);

for ( m = 0; m < obj->matnum; m++ ) // マテリアルループ mat = &obj->mat[m]; if ( mat->datanum == 0 ) continue; if ( mat->isvalidmaterialinfo ) // マテリアルの情報設定 memcpy(matenv,mat->dif,sizeof(matenv)); matenv[3] *= dalpha; glmaterialfv(gl_front_and_back, GL_DIFFUSE, matenv); memcpy(matenv,mat->amb,sizeof(matenv)); matenv[3] *= dalpha; glmaterialfv(gl_front_and_back, GL_AMBIENT, matenv); memcpy(matenv,mat->spc,sizeof(matenv)); matenv[3] *= dalpha; glmaterialfv(gl_front_and_back, GL_SPECULAR, matenv); memcpy(matenv,mat->emi,sizeof(matenv)); matenv[3] *= dalpha; glmaterialfv(gl_front_and_back, GL_EMISSION, matenv); glmaterialf(gl_front_and_back, GL_SHININESS, mat->power); if ( mat->isusetexture) // テクスチャがある場合 glenableclientstate( GL_VERTEX_ARRAY ); glenableclientstate( GL_NORMAL_ARRAY ); glenableclientstate( GL_TEXTURE_COORD_ARRAY ); isgl_texture_2d = glisenabled(gl_texture_2d); isgl_blend = glisenabled(gl_blend); glgetintegerv(gl_texture_binding_2d,&bindgl_texture_2d); // glgetintegerv(gl_blend_src_alpha,&blendgl_src_alpha); glenable(gl_texture_2d); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); glbindtexture(gl_texture_2d,mat->texture_id); 点バッファを結びつける if ( g_isvbosupported ) // 頂点バッファ使用 base = (char *)NULL; // アドレスはNULLが先頭 glbindbufferarb( GL_ARRAY_BUFFER_ARB, mat->vbo_id ); // 頂 else // 頂点配列の時は アドレスをそのまま入れる base = (char *)mat->vertex_t[0].point; // 頂点配列を設定 offset = (int)( (char *)mat->vertex_t[0].point - (char *)mat->vertex_t[0].point ); glvertexpointer( 3, GL_FLOAT, sizeof(vertex_texuse), base + offset ); // テクスチャ座標配列を設定 offset = (int)((char *)mat->vertex_t[0].uv-(char *)mat->vertex_t[0].point); gltexcoordpointer( 2, GL_FLOAT, sizeof(vertex_texuse), base + offset ); // 法線配列を設定 offset = (int)((char *)mat->vertex_t[0].normal-(char *)mat->vertex_t[0].point); glnormalpointer( GL_FLOAT, sizeof(vertex_texuse), base+offset ); // 色設定 glcolor4f(mat->color[0],mat->color[1],mat->color[2],mat->color[3]); // 描画実行 gldrawarrays( GL_TRIANGLES, 0, mat->datanum ); glbindtexture(gl_texture_2d,bindgl_texture_2d); if( isgl_blend == GL_FALSE ) gldisable(gl_blend);

if( isgl_texture_2d == GL_FALSE ) gldisable(gl_texture_2d); をデフォルトへ if ( g_isvbosupported ) // 頂点バッファ使用 glbindbufferarb( GL_ARRAY_BUFFER_ARB, 0 ); // 頂点バッファ else gldisableclientstate( GL_VERTEX_ARRAY ); gldisableclientstate( GL_NORMAL_ARRAY ); gldisableclientstate( GL_TEXTURE_COORD_ARRAY ); // テクスチャがない場合 glenableclientstate( GL_VERTEX_ARRAY ); glenableclientstate( GL_NORMAL_ARRAY ); //glenableclientstate( GL_COLOR_ARRAY ); isgl_blend = glisenabled(gl_blend); glenable(gl_blend); glblendfunc(gl_src_alpha,gl_one_minus_src_alpha); if ( g_isvbosupported ) // 頂点バッファ使用 base = (char *)NULL; glbindbufferarb( GL_ARRAY_BUFFER_ARB, mat->vbo_id ); else base = (char *)mat->vertex_p[0].point; // 頂点配列を設定 offset = (int)((char *)mat->vertex_p[0].point-(char *)mat->vertex_p[0].point); glvertexpointer( 3, GL_FLOAT, sizeof(vertex_notex), base+offset ); // 法線配列を設定 offset = (int)((char *)mat->vertex_p[0].normal-(char *)mat->vertex_p[0].point); glnormalpointer( GL_FLOAT, sizeof(vertex_notex), base+offset ); // 色設定 glcolor4f(mat->color[0],mat->color[1],mat->color[2],mat->color[3]); //offset = (int)((char *)mat->vertex_p[0].color-(char *)mat->vertex_p[0].point); //glcolorpointer(4,gl_float,sizeof(vertex_notex),base+offset); // 描画実行 gldrawarrays( GL_TRIANGLES, 0, mat->datanum ); をデフォルトへ if( isgl_blend == GL_FALSE ) gldisable(gl_blend); if ( g_isvbosupported ) // 頂点バッファ使用 glbindbufferarb( GL_ARRAY_BUFFER_ARB, 0 ); // 頂点バッファ //gldisableclientstate( GL_COLOR_ARRAY ); gldisableclientstate( GL_VERTEX_ARRAY ); gldisableclientstate( GL_NORMAL_ARRAY ); // メタセコは頂点の並びが表面からみて右回り ( 元の設定にもどす ) glfrontface(intfrontface); glpopmatrix(); 関数 mqogetdirectory

用途 ファイル名を含むパス文字列からディレクトリのパスのみを抽出する 引数 *path_file ファイル名を含むパス文字列 ( 入力 ) *path_dir ファイル名を除いたパス文字列 ( 出力 ) 戻値 なし 仕様 例: "C:/data/file.bmp" "C:/data/" "data/file.mqo" "data/" void mqogetdirectory(const char *path_file, char *path_dir) char *pstr; int len; pstr = MAX( strrchr(path_file,'\\'), strrchr(path_file,'/') ); len = MAX((int)(pStr-path_file)+1,0); strncpy(path_dir,path_file,len); path_dir[len] = (char)0; 関数 mqosnormal 用途 法線ベクトルを求める 引数 A 3 次元座標上の点 A B 3 次元座標上の点 B C 3 次元座標上の点 C *normal ベクトルBAとベクトルBCの法線ベクトル ( 右ねじ方向 ) 戻値 なし 仕様 メタセコイアにおいて面を構成する頂点の番号は, 表示面から見て時計回りに記述してある. つまり, 頂点 A,B,C があったとき, 求めるべき法線は BA と BC の外積によって求められる void mqosnormal(glpoint3f A, glpoint3f B, glpoint3f C, glpoint3f *normal) double norm; glpoint3f vec0,vec1; // ベクトル BA vec0.x = A.x - B.x; vec0.y = A.y - B.y; vec0.z = A.z - B.z; // ベクトル BC vec1.x = C.x - B.x; vec1.y = C.y - B.y; vec1.z = C.z - B.z; // 法線ベクトル normal->x = vec0.y * vec1.z - vec0.z * vec1.y; normal->y = vec0.z * vec1.x - vec0.x * vec1.z; normal->z = vec0.x * vec1.y - vec0.y * vec1.x; // 正規化 norm = normal->x * normal->x + normal->y * normal->y + normal->z * normal->z; norm = sqrt ( norm ); normal->x /= norm; normal->y /= norm; normal->z /= norm;

関数 mqoreadmaterial 用途 マテリアル情報の読み込み 引数 fp ファイルポインタ M マテリアル配列 戻値 なし 仕様 mqocreatemodel(), mqocreatesequence() のサブ関数. void mqoreadmaterial(file *fp, MQO_MATDATA M[]) GLfloat dif, amb, emi, spc; glcolor4f c; char buf[size_str]; char *pstrend, *pstr; int len; int i = 0; while (1) fgets(buf,size_str,fp); if (strstr(buf,"")) break; // 行読み込み pstr = strstr(buf,"col("); // 材質名読み飛ばし sscanf( pstr, "col(%f %f %f %f) dif (%f) amb(%f) emi(%f) spc(%f) power(%f)", &c.r, &c.g, &c.b, &c.a, &dif, &amb, &emi, &spc, &M[i].power ); // 頂点カラー M[i].col = c; // 拡散光 M[i].dif[0] = dif * c.r; M[i].dif[1] = dif * c.g; M[i].dif[2] = dif * c.b; M[i].dif[3] = c.a; // 周囲光 M[i].amb[0] = amb * c.r; M[i].amb[1] = amb * c.g; M[i].amb[2] = amb * c.b; M[i].amb[3] = c.a; // 自己照明 M[i].emi[0] = emi * c.r; M[i].emi[1] = emi * c.g; M[i].emi[2] = emi * c.b; M[i].emi[3] = c.a; // 反射光 M[i].spc[0] = spc * c.r; M[i].spc[1] = spc * c.g; M[i].spc[2] = spc * c.b; M[i].spc[3] = c.a; // tex: 模様マッピング名 if ( (pstr = strstr(buf,"tex("))!= NULL ) M[i].useTex = TRUE; pstrend = strstr(pstr,")")-1; len = pstrend - (pstr+5); strncpy(m[i].texfile,pstr+5,len); M[i].texFile[len] = (char)0; if ( (pstr = strstr(buf,"aplane("))!= NULL )

else pstrend = strstr(pstr,")")-1; len = pstrend - (pstr+8); strncpy(m[i].alpfile,pstr+8,len); M[i].alpFile[len] = (char)0; M[i].alpFile[0] = (char)0; else M[i].useTex = FALSE; M[i].texFile[0] = (char)0; M[i].alpFile[0] = (char)0; i++; 関数 mqoreadvertex 用途 頂点情報の読み込み 引数 fp 現在オープンしているメタセコイアファイルのファイルポインタ V 頂点を格納する配列 戻値 なし 仕様 mqoreadobject() のサブ関数 void mqoreadvertex(file *fp, glpoint3f V[]) char buf[size_str]; int i=0; while (1) fgets(buf,size_str,fp); if (strstr(buf,"")) break; sscanf(buf,"%f %f %f",&v[i].x,&v[i].y,&v[i].z); i++; 関数 mqoreadbvertex 用途 バイナリ形式の頂点情報を読み込む 引数 fp 現在オープンしているメタセコイアファイルのファイルポインタ V 頂点を格納する配列 戻値 頂点数 仕様 mqoreadobject() のサブ関数 int mqoreadbvertex(file *fp, glpoint3f V[]) int n_vertex,i; float *wf; int size; char cw[256]; char *pstr; fgets(cw,sizeof(cw),fp); if ( (pstr = strstr(cw,"vector"))!= NULL )

sscanf(pstr,"vector %d [%d]",&n_vertex,&size);// 頂点数 データサイズを読み込む else return -1; //MQOファイルのバイナリ頂点データはintel 形式 ( リトルエディアン ) wf = (float *)malloc(size); fread(wf,size,1,fp); for ( i = 0; i < n_vertex; i++ ) V[i].x = wf[i*3+0]; V[i].y = wf[i*3+1]; V[i].z = wf[i*3+2]; #if DEF_IS_LITTLE_ENDIAN #else endianconverter((void *)&V[i].x,sizeof(V[i].x)); endianconverter(&v[i].y,sizeof(v[i].y)); endianconverter(&v[i].z,sizeof(v[i].z)); free(wf); // "" まで読み飛ばし char buf[size_str]; while (1) fgets(buf,size_str,fp); if (strstr(buf,"")) break; return n_vertex; 関数 mqoreadface 用途 面情報の読み込み 引数 fp ファイルポインタ F 面配列 戻値 なし 仕様 mqoreadobject() のサブ関数 void mqoreadface(file *fp, MQO_FACE F[]) char buf[size_str]; char *pstr; int i=0; while (1) fgets(buf,size_str,fp); if (strstr(buf,"")) break; // 面を構成する頂点数 sscanf(buf,"%d",&f[i].n); // 頂点 (V) の読み込み if ( (pstr = strstr(buf,"v("))!= NULL ) switch (F[i].n) case 3: // メタセコは頂点の並びが表面からみて右回り // 読み込み時に並べ替える方法もある けど 表面の設定を //glfrontface で変えるほうがスマート? sscanf(pstr,"v(%d %d %d)",&f[i].v[0],&f[i].v[1],&f[i].v[2]); //sscanf(pstr,"v(%d %d %d)",&f[i].v[2],&f[i].v[1],&f[i].v[0]);

case 4: default: break; sscanf(pstr,"v(%d %d %d %d)",&f[i].v[0],&f[i].v[1],&f[i].v[2],&f[i].v[3]); //sscanf(pstr,"v(%d %d %d %d)",&f[i].v[3],&f[i].v[2],&f[i].v[1],&f[i].v[0]); break; break; // マテリアル (M) の読み込み F[i].m = 0; if ( (pstr = strstr(buf,"m("))!= NULL ) sscanf(pstr,"m(%d)",&f[i].m); else // マテリアルが設定されていない面 F[i].m = -1; // UV マップ (UV) の読み込み if ( (pstr = strstr(buf,"uv("))!= NULL ) switch (F[i].n) case 3: // 頂点数 sscanf(pstr,"uv(%f %f %f %f %f %f)", &F[i].uv[0].x, &F[i].uv[0].y, &F[i].uv[1].x, &F[i].uv[1].y, &F[i].uv[2].x, &F[i].uv[2].y ); break; case 4: default: // 頂点数 sscanf(pstr,"uv(%f %f %f %f %f %f %f %f)", &F[i].uv[0].x, &F[i].uv[0].y, &F[i].uv[1].x, &F[i].uv[1].y, &F[i].uv[2].x, &F[i].uv[2].y, &F[i].uv[3].x, &F[i].uv[3].y ); break; break; i++; 関数 mqoreadobject 用途 オブジェクト情報の読み込み 引数 fp ファイルポインタ obj オブジェクト情報 戻値 なし 仕様 この関数で 1 個のオブジェクト情報が読み込まれる. void mqoreadobject(file *fp, MQO_OBJDATA *obj) char buf[size_str]; while (1) fgets(buf,size_str,fp); if (strstr(buf,"")) break;

// visible if (strstr(buf,"visible ")) sscanf(buf," visible %d", &obj->visible); // shading if (strstr(buf,"shading ")) sscanf(buf," shading %d", &obj->shading); // facet if (strstr(buf,"facet ")) sscanf(buf," facet %f", &obj->facet); // vertex if (strstr(buf,"vertex ")) sscanf(buf," vertex %d", &obj->n_vertex); obj->v = (glpoint3f*) calloc( obj->n_vertex, sizeof(glpoint3f) ); mqoreadvertex(fp, obj->v); // BVertex if (strstr(buf,"bvertex")) sscanf(buf," BVertex %d", &obj->n_vertex); obj->v = (glpoint3f*) calloc( obj->n_vertex, sizeof(glpoint3f) ); mqoreadbvertex(fp,obj->v); // face if (strstr(buf,"face ")) sscanf(buf," face %d", &obj->n_face); obj->f = (MQO_FACE*) calloc( obj->n_face, sizeof(mqo_face) ); mqoreadface(fp, obj->f); 関数 mqomakearray 用途 頂点配列の作成 引数 mat マテリアル ( この中に頂点データを含む ) matpos 材質番号 F 面 fnum 面数 V 頂点 N 法線 facet スムージング角 mcol 色 scale スケール alpha アルファ 戻値 なし 仕様 頂点配列はすべて三角にするので 四角は三角 x2 に分割 0 3 0 0 3 1 2 1 2 2 void mqomakearray( MQO_MATERIAL *mat, int matpos, MQO_FACE F[], int fnum,glpoint3f V[], glpoint3f N[], double facet, glcolor4f *mcol, double scale, unsigned char alpha ) int f; int i;

int dpos; double s; glpoint3f normal; // 法線ベクトル dpos = 0; mat->color[0] = mcol->r; mat->color[1] = mcol->g; mat->color[2] = mcol->b; mat->color[3] = mcol->a; if ( mat->isusetexture ) for ( f = 0; f < fnum; f++ ) if ( F[f].m!= matpos ) continue; if ( F[f].n == 3 ) mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&normal); // 法線ベクトルを計算 for ( i = 0; i < 3; i++ ) mat->vertex_t[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_t[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_t[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_t[dpos].uv[0] = F[f].uv[i].x; mat->vertex_t[dpos].uv[1] = F[f].uv[i].y; s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y + normal.z*n[f[f].v[i]].z); if ( facet < s ) // スムージング角 <( 頂点法線と面法線の角度 ) のときは面法線を頂点法線とする mat->vertex_t[dpos].normal[0] = normal.x; mat->vertex_t[dpos].normal[1] = normal.y; mat->vertex_t[dpos].normal[2] = normal.z; normal.z*n[f[f].v[i]].z); else dpos++; //4 頂点 ( 四角 ) は3 頂点 ( 三角 )x2に分割 if ( F[f].n == 4 ) mat->vertex_t[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_t[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_t[dpos].normal[2] = N[F[f].v[i]].z; mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&normal); // 法線ベクトルを計算 for ( i = 0; i < 4; i++ ) if ( i == 3 ) continue; mat->vertex_t[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_t[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_t[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_t[dpos].uv[0] = F[f].uv[i].x; mat->vertex_t[dpos].uv[1] = F[f].uv[i].y; s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y + if ( facet < s ) mat->vertex_t[dpos].normal[0] = normal.x; mat->vertex_t[dpos].normal[1] = normal.y; mat->vertex_t[dpos].normal[2] = normal.z; else mat->vertex_t[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_t[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_t[dpos].normal[2] = N[F[f].v[i]].z; dpos++; mqosnormal(v[f[f].v[0]],v[f[f].v[2]],v[f[f].v[3]],&normal); for ( i = 0; i < 4; i++ ) if ( i == 1 ) continue; mat->vertex_t[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_t[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_t[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_t[dpos].uv[0] = F[f].uv[i].x; mat->vertex_t[dpos].uv[1] = F[f].uv[i].y; // 法線ベクトルを計算

s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y + normal.z*n[f[f].v[i]].z); if ( facet < s ) mat->vertex_t[dpos].normal[0] = normal.x; mat->vertex_t[dpos].normal[1] = normal.y; mat->vertex_t[dpos].normal[2] = normal.z; else mat->vertex_t[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_t[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_t[dpos].normal[2] = N[F[f].v[i]].z; dpos++; else if ( alpha!= 255 ) mat->color[3] = (double)alpha/(double)255; for ( f = 0; f < fnum; f++ ) if ( F[f].m!= matpos ) continue; if ( F[f].n == 3 ) mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&normal); // 法線ベクトルを計算 for ( i = 0; i < 3; i++ ) mat->vertex_p[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_p[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_p[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y +normal.z*n[f[f].v[i]].z); if ( facet < s ) mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; else mat->vertex_p[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_p[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_p[dpos].normal[2] = N[F[f].v[i]].z; dpos++; //4 頂点 ( 四角 ) は3 頂点 ( 三角 )x2に分割 if ( F[f].n == 4 ) mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&normal); // 法線ベクトルを計算 for ( i = 0; i < 4; i++ ) if ( i == 3 ) continue; mat->vertex_p[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_p[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_p[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y + normal.z*n[f[f].v[i]].z); if ( facet < s ) mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; else mat->vertex_p[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_p[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_p[dpos].normal[2] = N[F[f].v[i]].z;

normal.z*n[f[f].v[i]].z); dpos++; mqosnormal(v[f[f].v[0]],v[f[f].v[2]],v[f[f].v[3]],&normal); // 法線ベクトルを計算 for ( i = 0; i < 4; i++ ) if ( i == 1 ) continue; mat->vertex_p[dpos].point[0] = V[F[f].v[i]].x*scale; mat->vertex_p[dpos].point[1] = V[F[f].v[i]].y*scale; mat->vertex_p[dpos].point[2] = V[F[f].v[i]].z*scale; mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; s = acos(normal.x*n[f[f].v[i]].x + normal.y*n[f[f].v[i]].y + if ( facet < s ) mat->vertex_p[dpos].normal[0] = normal.x; mat->vertex_p[dpos].normal[1] = normal.y; mat->vertex_p[dpos].normal[2] = normal.z; else mat->vertex_p[dpos].normal[0] = N[F[f].v[i]].x; mat->vertex_p[dpos].normal[1] = N[F[f].v[i]].y; mat->vertex_p[dpos].normal[2] = N[F[f].v[i]].z; dpos++; 関数 mqovertexnormal 用途 頂点法線の計算 引数 obj オブジェクト情報 戻値 法線配列 仕様 4 頂点の面は三角形に分割して計算戻り値は必ず呼び出し元で解放 (free) すること! glpoint3f * mqovertexnormal(mqo_objdata *obj) int f; int v; int i; double len; glpoint3f fnormal; // 面法線ベクトル MQO_FACE *F; glpoint3f *V; glpoint3f *ret; F = obj->f; V = obj->v; ret = (glpoint3f *)calloc(obj->n_vertex,sizeof(glpoint3f)); // 面の法線を頂点に足し込み for ( f = 0; f < obj->n_face; f++ ) if ( obj->f[f].n == 3 ) mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&fnormal); for ( i = 0; i < 3; i++ ) ret[f[f].v[i]].x += fnormal.x; ret[f[f].v[i]].y += fnormal.y; ret[f[f].v[i]].z += fnormal.z; if ( obj->f[f].n == 4 ) mqosnormal(v[f[f].v[0]],v[f[f].v[1]],v[f[f].v[2]],&fnormal);

for ( i = 0; i < 4; i++ ) if ( i == 3 ) continue; ret[f[f].v[i]].x += fnormal.x; ret[f[f].v[i]].y += fnormal.y; ret[f[f].v[i]].z += fnormal.z; mqosnormal(v[f[f].v[0]],v[f[f].v[2]],v[f[f].v[3]],&fnormal); for ( i = 0; i < 4; i++ ) if ( i == 1 ) continue; ret[f[f].v[i]].x += fnormal.x; ret[f[f].v[i]].y += fnormal.y; ret[f[f].v[i]].z += fnormal.z; // 正規化 for ( v = 0; v < obj->n_vertex; v++ ) if ( ret[v].x == 0 && ret[v].y == 0 && ret[v].z == 0 ) // 面に使われてない点 continue; len = sqrt(ret[v].x*ret[v].x + ret[v].y*ret[v].y + ret[v].z*ret[v].z); if ( len!= 0 ) ret[v].x = ret[v].x/len; ret[v].y = ret[v].y/len; ret[v].z = ret[v].z/len; return ret; 関数 mqomakepolygon 用途 ポリゴンの生成 引数 readobj 読み込んだオブジェクト情報 mqoobj MQOオブジェクト N[] 法線配列 M[] マテリアル配列 n_mat マテリアル数 scale スケール alpha アルファ 戻値 なし void mqomakepolygon(mqo_objdata *readobj, MQO_OBJECT *mqoobj, glpoint3f N[], MQO_MATDATA M[], int n_mat, double scale, unsigned char alpha) MQO_INNER_OBJECT MQO_MATERIAL glcolor4f glcolor4f int int MQO_FACE glpoint3f double *setobj; *material; defcol; *pcol; f, m, *mat_vnum; fnum; *F; *V; facet; setobj = &mqoobj->obj[mqoobj->objnum]; strcpy(setobj->objname,readobj->objname); setobj->isvisible = readobj->visible; setobj->isshadingflat = (readobj->shading == 0); F = readobj->f;

fnum = readobj->n_face; V = readobj->v; facet = readobj->facet; // face の中でのマテリアル毎の頂点の数 // M=NULL のとき F[].m = 0 が入ってくる if ( M == NULL ) n_mat = 1; mat_vnum = (int *)malloc(sizeof(int)*n_mat); memset(mat_vnum,0,sizeof(int)*n_mat); for ( f = 0; f < fnum; f++ ) if( F[f].m < 0 ) continue; // マテリアルが設定されていない面 if ( F[f].n == 3 ) mat_vnum[f[f].m] += 3; if ( F[f].n == 4 ) //4 頂点 ( 四角 ) は 3 頂点 ( 三角 )x2 に分割 // 0 3 0 0 3 // // 1 2 1 2 2 // 4 頂点の平面データは // 3 頂点の平面データ x2 個 mat_vnum[f[f].m] += 3*2; if ( setobj->matnum < F[f].m+1 ) setobj->matnum = F[f].m+1; // マテリアル別に頂点配列を作成する setobj->mat = (MQO_MATERIAL *)malloc(sizeof(mqo_material)*setobj->matnum); memset(setobj->mat,0,sizeof(mqo_material)*setobj->matnum); for ( m = 0; m < setobj->matnum; m++ ) material = &setobj->mat[m]; material->datanum = mat_vnum[m]; material->isvalidmaterialinfo = (M!= NULL); if ( mat_vnum[m] <= 0 ) continue; if ( material->isvalidmaterialinfo ) memcpy(material->dif,m[m].dif,sizeof(material->dif)); memcpy(material->amb,m[m].amb,sizeof(material->amb)); memcpy(material->spc,m[m].spc,sizeof(material->spc)); memcpy(material->emi,m[m].emi,sizeof(material->emi)); material->power = M[m].power; material->isusetexture = M[m].useTex; pcol = &M[m].col; else defcol.r = 1.0; defcol.g = 1.0; defcol.b = 1.0; defcol.a = 1.0; material->isusetexture = 0; pcol = &defcol; if ( material->isusetexture ) material->vertex_t = (VERTEX_TEXUSE *)calloc(material->datanum,sizeof(vertex_texuse)); material->texture_id = M[m].texName; else material->vertex_p = (VERTEX_NOTEX *)calloc(material->datanum,sizeof(vertex_notex)); mqomakearray(material,m,f,fnum,v,n,facet,pcol,scale,alpha); if (g_isvbosupported) if ( material->isusetexture ) glgenbuffersarb( 1, &material->vbo_id ); glbindbufferarb( GL_ARRAY_BUFFER_ARB, material->vbo_id ); glbufferdataarb( GL_ARRAY_BUFFER_ARB, material-

>datanum*sizeof(vertex_texuse), material->vertex_t, GL_STATIC_DRAW_ARB ); else glgenbuffersarb( 1, &material->vbo_id ); glbindbufferarb( GL_ARRAY_BUFFER_ARB, material->vbo_id ); glbufferdataarb( GL_ARRAY_BUFFER_ARB, material- >datanum*sizeof(vertex_notex), material->vertex_p, GL_STATIC_DRAW_ARB ); mqoobj->objnum++; if ( MAX_OBJECT <= mqoobj->objnum ) printf("mqo ファイル読み込み : 最大オブジェクト数を超えました [%d]\n",mqoobj->objnum); mqoobj->objnum = MAX_OBJECT-1; free(mat_vnum); 関数 mqomakeobjectsex 用途 オブジェクトのデータからポリゴンモデルを作成する 引数 mqoobj MQOオブジェクト obj オブジェクト配列 n_obj オブジェクトの個数 M マテリアル配列 n_mat マテリアルの個数 scale 拡大率 alpha アルファ 戻値 なし void mqomakeobjectsex( MQO_OBJECT *mqoobj, MQO_OBJDATA obj[], int n_obj, MQO_MATDATA M[],int n_mat, double scale,unsigned char alpha) int i; glpoint3f *N; for (i=0; i<n_obj; i++) N = mqovertexnormal(&obj[i]); mqomakepolygon( &obj[i], mqoobj, N, M,n_mat, scale, alpha); free(n); 関数 mqocreatemodel 用途 MQOファイルからMQOモデルを作成する 引数 filename MQOファイル scale 拡大率 (.0でそのまま) 戻値 MQO_MODEL(MQO モデル ) MQO_MODEL mqocreatemodel(char *filename, double scale)

MQO_MODEL ret; ret = mqocreatelist(1); if ( mqocreatelistobject(ret,1-1,filename,scale,(unsigned char)255) < 0 ) mqodeleteobject(ret,1); ret = NULL; return ret; 関数 mqocreatesequenceex 用途 連番のMQOファイルからMQOシーケンスを作成する 引数 format ファイル名の書式 n_file ファイル数 scale 拡大率 (.0でそのまま) fade_inout 0: そのまま正 : フェードイン負 : フェードアウト絶対値は効果をかけるフレーム数 alpha アルファ 戻値 MQO_SEQUENCE(MQO シーケンス ) 備考 連番はから開始 MQO_SEQUENCE mqocreatesequenceex(const char *format, int n_file, double scale, int fade_inout, unsigned char alpha) MQO_SEQUENCE retseq; int iret; int seq; char filename[size_str]; short setalpha; short calalpha; int frames; retseq.n_frame = 0; if ( format == NULL ) return retseq; calalpha = alpha; frames = abs(fade_inout); frames = MAX(frames,n_file); setalpha = (fade_inout<=0)?alpha:0; retseq.model = mqocreatelist(n_file); for ( seq = 0; seq < frames; seq++ ) if ( seq < n_file ) sprintf(filename,format,seq); if ( (fade_inout!= 0) && ((frames-1) == seq) ) setalpha = (fade_inout<0)?0:calalpha; iret = mqocreatelistobject(retseq.model,seq,filename,scale,(unsigned char)setalpha); if ( iret == - 1 ) seq--; mqoclearobject(retseq.model,seq,n_file-seq); break; if ( fade_inout!= 0 ) if ( fade_inout<0 ) if ( (n_file-seq) <= (-1*fade_inout) ) setalpha -= (calalpha/(-1*fade_inout)); if ( setalpha < 0 ) setalpha = 0; else setalpha += (calalpha/fade_inout);

retseq.n_frame = seq; return retseq; if ( calalpha < setalpha ) setalpha = calalpha; 関数 mqocreatesequence 用途 連番のMQOファイルからMQOシーケンスを作成する 引数 format ファイル名のフォーマット n_file ファイル数 scale 拡大率 (.0でそのまま) 戻値 MQO_SEQUENCE(MQO シーケンス ) 備考 連番はから開始 MQO_SEQUENCE mqocreatesequence(const char *format, int n_file, double scale) return mqocreatesequenceex(format, n_file, scale, 0, (unsigned char)255); 関数 mqocallmodel 用途 MQOモデルをOpenGLの画面上に呼び出す 引数 model MQOモデル 戻値 なし void mqocallmodel(mqo_model model) mqocalllistobject(model, 0); 関数 mqocallsequence 用途 MQOシーケンスをOpenGLの画面に呼び出す 引数 seq MQOシーケンス i フレーム番号 戻値 なし 仕様 MQO シーケンスの中から指定したフレーム番号のモデルを呼び出す void mqocallsequence(mqo_sequence seq, int i) if ( i>=0 && i<seq.n_frame ) mqocalllistobject(seq.model,i); 関数 mqoclearobject 用途 MQOオブジェクトのクリア 引数 object MQOオブジェクト配列

from num 削除開始番号 (~) 削除する個数 戻値 なし void mqoclearobject( MQO_OBJECT object[], int from, int num ) int loop, o, m; MQO_INNER_OBJECT *obj; MQO_MATERIAL *mat; if ( object == NULL ) return; for ( loop = from; loop < from + num; loop++ ) for ( o = 0; o < (object+from)->objnum; o++ ) obj = &(object+loop)->obj[o]; for ( m = 0; m < obj->matnum; m++ ) mat = &obj->mat[m]; if ( mat->datanum <= 0 ) continue; if ( g_isvbosupported ) // 頂点バッファの削除 gldeletebuffersarb( 1, &mat->vbo_id ); // 頂点配列の削除 if ( mat->isusetexture ) if ( mat->vertex_t!= NULL ) free(mat->vertex_t); mat->vertex_t = NULL; else if ( mat->vertex_p!= NULL ) free(mat->vertex_p); mat->vertex_p = NULL; if ( obj->mat!= NULL ) free(obj->mat); obj->mat = NULL; obj->matnum = 0; 関数 mqodeleteobject 用途 MQOオブジェクトを削除する 引数 object MQOオブジェクト配列 num 削除する個数 戻値 なし void mqodeleteobject(mqo_object object[], int num) mqoclearobject(object,0,num); free(object);

関数 mqodeletemodel 用途 MQOモデルを削除する 引数 model MQOモデル 戻値 なし 備考 削除処理を行った変数を再利用する可能性がある場合はこの関数の実行後に NULL を代入しておくこと void mqodeletemodel(mqo_model model) mqodeleteobject(model,1); 関数 mqodeletesequence 用途 MQOシーケンスを削除する 引数 seq MQOシーケンス 備考 削除処理を行った変数を再利用する可能性がある場合はこの関数の実行後に NULL を代入しておくこと void mqodeletesequence(mqo_sequence seq) mqodeleteobject( seq.model, seq.n_frame );