/* =============================================================================== PMDファイル( MikuMikuDance のモデルデータ )の形状を画面に3D表示する =============================================================================== ≪説明≫ ・本ソフトを起動して「ファイル」メニューの「PMDファイルの読み込み...」 を選んで、PMDファイルを開くと、その3D形状が画面に表示されます。 ・表示された3Dモデルの回転/拡大縮小等は、以下の操作で行なえます。 [→] Y軸周りの右回転 [←] Y軸周りの左回転 [↑] X軸周りの右回転 [↓] X軸周りの左回転 [Home] 基準の位置とスケールに戻す [End] 真後ろから見る マウスホイール モデルを拡大/縮小 マウスドラッグ モデルを平行移動 ・各種のPMDファイルは、インターネットでダウンロードできます。 ・PMDファイルが参照するテクスチャーファイルのフォーマットは、 現状、BMPの 24-bit カラー形式のみに対応しています。 ・PMDファイルとテクスチャーファイルは、同じフォルダー内に置いてください。 */ /*****/ // GK Library のモジュールをロードする場合 #include #include #include if( ::Module.Include( "GkLibrary" ) > 0 ) Main( argc, argv ); return; /*****/ /****** // GK Library のソースをインクルードする場合 #include Main( argc, argv ); return; /*****/ //----------------------------------------------------------------------------- /*****/ // デバッグプリント無効化(リリース時) #set pc #comment #set pv #set pi #comment #set pd #comment /*****/ /***** // デバッグプリント有効化(デバッグ時) #set pc print #set pv print #set pi print #set pd /*****/ #set p print //----------------------------------------------------------------------------- /// マクロ定義 /// #set WndTitle "PMDファイル内の形状を描画" // ウィンドウ表題 #set FigXd 640 // 図形描画領域の幅 #set FigYd 480 // 図形描画領域の高さ #set PI 3.1415926535897 #set RAD(a) (#a*(#PI/180)) //----------------------------------------------------------------------------- // OpenGL 関連のマクロ定義 #set GL_AMBIENT 0x1200 #set GL_AUTO_NORMAL 0x0D80 #set GL_BACK 0x0405 #set GL_CCW 0x0901 #set GL_CLAMP 0x2900 #set GL_COLOR_BUFFER_BIT 0x00004000 #set GL_CULL_FACE 0x0B44 #set GL_CW 0x0900 #set GL_DEPTH_BUFFER_BIT 0x00000100 #set GL_DEPTH_TEST 0x0B71 #set GL_DIFFUSE 0x1201 #set GL_FLOAT 0x1406 #set GL_FRONT 0x0404 #set GL_FRONT_AND_BACK 0x0408 #set GL_LIGHT0 0x4000 #set GL_LIGHTING 0x0B50 #set GL_LINEAR 0x2601 #set GL_LINES 0x0001 #set GL_MODELVIEW 0x1700 #set GL_NORMAL_ARRAY 0x8075 #set GL_NORMALIZE 0x0BA1 #set GL_POSITION 0x1203 #set GL_PROJECTION 0x1701 #set GL_REPLACE 0x1E01 #set GL_RGB 0x1907 #set GL_SHININESS 0x1601 #set GL_SPECULAR 0x1202 #set GL_TEXTURE_2D 0x0DE1 #set GL_TEXTURE_COORD_ARRAY 0x8078 #set GL_TEXTURE_ENV 0x2300 #set GL_TEXTURE_ENV_MODE 0x2200 #set GL_TEXTURE_MAG_FILTER 0x2800 #set GL_TEXTURE_MIN_FILTER 0x2801 #set GL_TEXTURE_WRAP_S 0x2802 #set GL_TEXTURE_WRAP_T 0x2803 #set GL_TRIANGLES 0x0004 #set GL_UNSIGNED_BYTE 0x1401 #set GL_UNSIGNED_SHORT 0x1403 #set GL_VERTEX_ARRAY 0x8074 #set PFD_DOUBLEBUFFER 0x00000001 #set PFD_DRAW_TO_WINDOW 0x00000004 #set PFD_MAIN_PLANE 0 #set PFD_SUPPORT_OPENGL 0x00000020 #set PFD_TYPE_RGBA 0 //============================================================================= function Main( argc, argv ) { #pc "開始"; ^DefValue = null; if( ^SetupPMD() != #OK ) goto FIN_3; if( ^SetupOpenGL() != #OK ) goto FIN_2; class ^MainWindow : ::GK.Window {} R = ::GK.Rect( 0, 0, #FigXd, #FigYd ); ::GK.Window.GetAdjRect( R, #TRUE ); ^MainWindow.Construct( #WndTitle, 300, 100, R.Xd, R.Yd ); ^MainWindow.Open(); ::GK.WindowMsgLoop(); FIN_1: delete ^MainWindow; FIN_2: DeleteOpenGL(); FIN_3: #pc "終了"; return; OnError: #p ::ErrorMessage( $err_code, $err_info ), $err_func; goto FIN_1; } //----------------------------------------------------------------------------- function ^MainWindow.OnCreate() { #pc "OnCreate"; // メニューの設定 #set CMD_READ 1001 #set CMD_END 1002 .menu = ::GK.Menu(); .menu.InsertItem( #CMD_READ, "PMDファイルの読み込み..." ); .menu.InsertItem( #CMD_END, "終了" ); .TopMenu = ::GK.TopMenu(); .TopMenu.InsertMenu( .menu, "ファイル" ); .SetMenuBar( .TopMenu ); // OpenGL の初期設定 if( .InitializeOpenGL() != #OK ) { #p "OpenGL 初期設定エラー!"; .Close(); } //.CurScale = -4; // 伸縮度合 .ScaleXo = .ScaleYo = 0; // 伸縮中心(スクリーン座標系) //.MoveDx = .MoveDy = 0.0; // 累積マウスドラッグ量(ワールド座標系) .TmpDx = .TmpDy = 0.0; // 一時マウスドラッグ量(ワールド座標系) .LBtn = 0; // マウスの左ボタン ON/OFF 状態 //( .α, .β, .γ ) = ( 15, -30, 0 ); ( .MoveDx, .MoveDy ) = ( -0.0103553, -10.2076 ); ( .CurScale, .ScaleXo, .ScaleYo ) = ( -20, 192, 23 ); ( .α, .β, .γ ) = ( 15, -180, 0 ); ^glClearColor( 0.0'sfv, 0.3'sfv, 0.3'sfv, 1.0'sfv ); // 背景色 // ^glClearDepth( 1.0 ); ^glEnable( #GL_DEPTH_TEST ); ^glEnable( #GL_CULL_FACE ); // ^glCullFace( #GL_FRONT ); ^glCullFace( #GL_BACK ); // ^glFrontFace( #GL_CW ); // ^glFrontFace( #GL_CCW ); ^glEnable( #GL_NORMALIZE ); // ^glEnable( #GL_AUTO_NORMAL ); ^glEnable( #GL_LIGHT0 ); .Lt0_Pos 'FLOAT(4) = { 0.0, 0.0, 1.0, 0.0 }; .Lt0_Ambient 'FLOAT(4) = { 0.2, 0.2, 0.2, 1.0 }; .Lt0_Diffuse 'FLOAT(4) = { 1.0, 1.0, 1.0, 1.0 }; .Lt0_Specular'FLOAT(4) = { 1.0, 1.0, 1.0, 1.0 }; ^glLightfv( #GL_LIGHT0, #GL_AMBIENT , .Lt0_Ambient ); ^glLightfv( #GL_LIGHT0, #GL_DIFFUSE , .Lt0_Diffuse ); ^glLightfv( #GL_LIGHT0, #GL_SPECULAR, .Lt0_Specular ); .Lt0_α = .Lt0_β = 0; ^glTexParameteri( #GL_TEXTURE_2D, #GL_TEXTURE_WRAP_S, #GL_CLAMP ); ^glTexParameteri( #GL_TEXTURE_2D, #GL_TEXTURE_WRAP_T, #GL_CLAMP ); ^glTexParameteri( #GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR ); ^glTexParameteri( #GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR ); ^glTexEnvi( #GL_TEXTURE_ENV, #GL_TEXTURE_ENV_MODE, #GL_REPLACE ); } //----------------------------------------------------------------------------- function ^MainWindow.OnMenu( id ) { #pc "OnMenu : " : id; switch( id ) { case #CMD_READ: if(( fname = .GetFileNameToOpen( ^PMD_File ) ) != NULL ) { if( ^ReadPMDFile( fname ) != #OK ) .MessageBox( ^PMD_ErrMsg, "PMDファイルの読み込み", #MB_ICONERROR | #MB_OK ); .InvalidateRect(); .SetForeground(); } break; case #CMD_END: .Close(); break; } } //----------------------------------------------------------------------------- function ^MainWindow.OnClose() { #pc "OnClose"; .TerminateOpenGL(); } //----------------------------------------------------------------------------- function ^MainWindow.OnSize() { #pc "OnSize"; ^glViewport( 0, 0, .gc.Xd, .gc.Yd ); ^glMatrixMode( #GL_PROJECTION ); ^glLoadIdentity(); Cx = .gc.Xd'float / #FigXd; Cy = .gc.Yd'float / #FigXd; ^glOrtho( -Cx/2, +Cx/2, -Cy/2, +Cy/2, -100.0, 100.0 ); } //----------------------------------------------------------------------------- function ^MainWindow.OnPaint() { //#pc "OnPaint"; ^glClear( #GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT ); // モデル座標系と光源位置の設定 ^glMatrixMode( #GL_MODELVIEW ); ^glLoadIdentity(); ^glLightfv( #GL_LIGHT0, #GL_POSITION, .Lt0_Pos ); K = ::Math.pow( 2.0, .CurScale * 0.25 ); ^glTranslated( .MoveDx * K, .MoveDy * K, 0.0 ); ^glScaled( K, K, K ); if( .LBtn ) { .TmpDx = .DragDx / K / #FigXd; .TmpDy = .DragDy / K / #FigXd; ^glTranslated( .TmpDx, .TmpDy, 0.0 ); } ^glRotated( .α'float, 1.0, 0.0, 0.0 ); // X 軸まわりに回転(正:反時計方向) ^glRotated( .β'float, 0.0, 1.0, 0.0 ); // Y 軸まわりに回転(正:反時計方向) ^glRotated( .γ'float, 0.0, 0.0, 1.0 ); // Z 軸まわりに回転(正:反時計方向) if( ! ^PMD_File ) // PMDデータ未準備? goto DRAW_COORD; // 座標軸のみ描画 // PMDモデルの描画 ^glEnable( #GL_LIGHTING ); ^glEnableClientState( #GL_VERTEX_ARRAY ); ^glVertexPointer( 3, #GL_FLOAT, ^PMD_VertexSize, ^VertexPtr ); ^glEnableClientState( #GL_NORMAL_ARRAY ); ^glNormalPointer( #GL_FLOAT, ^PMD_VertexSize, ^NormalPtr ); ^glEnableClientState( #GL_TEXTURE_COORD_ARRAY ); ^glTexCoordPointer( 2, #GL_FLOAT, ^PMD_VertexSize, ^TexUV_Ptr ); ^Materials.Seek( 0 ); q := ^PMD_Material; p := null; k = 0; for( i = 0 ; i < ^MaterialCount ; i++ ) { ^Materials.Read( q ); ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_DIFFUSE, q.Diffuse ); ^RGBA'MEMBLK'memcpy( q.Specular'MEMBLK ); ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_SPECULAR, ^RGBA ); ^glMaterialf( #GL_FRONT_AND_BACK, #GL_SHININESS, q.Shininess'sfv ); ^RGBA'MEMBLK'memcpy( q.Ambient'MEMBLK ); ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_AMBIENT, ^RGBA ); if( ^Tex[i]'exist? ) { ^glEnable( #GL_TEXTURE_2D ); p := ^Tex[i]; ^glTexImage2D( #GL_TEXTURE_2D, 0, 3, p.Xd, p.Yd, 0, #GL_RGB, #GL_UNSIGNED_BYTE, p.Pixs ); } n = q.FaceCountX3; ^glDrawElements( #GL_TRIANGLES, n, #GL_UNSIGNED_SHORT, ^Indexes( k )'addr ); k += n; if( p != null ) { ^glDisable( #GL_TEXTURE_2D ); p := null; } } ^glDisableClientState( #GL_TEXTURE_COORD_ARRAY ); ^glDisableClientState( #GL_NORMAL_ARRAY ); ^glDisableClientState( #GL_VERTEX_ARRAY ); // 座標軸を描画 DRAW_COORD: ^glDisable( #GL_LIGHTING ); ^glBegin( #GL_LINES ); DP = 10.0; DM = -1.0; // X 軸(赤) ^glColor3d( 1.0, 0.0, 0.0 ); ^glVertex2d( 0.0, 0.0 ); ^glVertex2d( DP, 0.0 ); ^glColor3d( 0.3, 0.0, 0.0 ); ^glVertex2d( 0.0, 0.0 ); ^glVertex2d( DM, 0.0 ) ; // Y 軸(緑) ^glColor3d( 0.0, 1.0, 0.0 ); ^glVertex2d( 0.0, 0.0 ); ^glVertex2d( 0.0, DP*2.5 ); ^glColor3d( 0.0, 0.3, 0.0 ); ^glVertex2d( 0.0, 0.0 ); ^glVertex2d( 0.0, DM ); // Z 軸(青) ^glColor3d( 0.0, 0.3, 1.0 ); ^glVertex3d( 0.0, 0.0, 0.0 ); ^glVertex3d( 0.0, 0.0, DP ); ^glColor3d( 0.0, 0.1, 0.3 ); ^glVertex3d( 0.0, 0.0, 0.0 ); ^glVertex3d( 0.0, 0.0, DM ); ^glEnd(); FIN: ^glFlush(); //^glFinish(); //^SwapBuffers( .gc.hdc ); } //----------------------------------------------------------------------------- function ^MainWindow.OnKeyDown( vk ) { //#pc "OnKeyDown:", vk'x(4); switch( vk & ~#KCF_REPEAT ) { case #VK_ESCAPE: .Close(); return; case #VK_HOME: ( .MoveDx, .MoveDy ) = ( -0.0103553, -10.2076 ); ( .CurScale, .ScaleXo, .ScaleYo ) = ( -20, 192, 23 ); ( .α, .β, .γ, .Lt0_α, .Lt0_β ) = ( 15, -180, 0, 0, 0 ); goto SET_LT0_POS; case #VK_HOME + #KCF_SHIFT: .MoveDx = .MoveDy = 0.0; .CurScale = -4; .ScaleXo = .ScaleYo = 0; ( .α, .β, .γ ) = ( 15, -30, 0 ); .Lt0_α = .Lt0_β = 0; goto SET_LT0_POS; case #VK_END: .α = .β = .γ = 0; .Lt0_α = .Lt0_β = 0; goto SET_LT0_POS; case #VK_DOWN : .α += 5; break; case #VK_UP : .α -= 5; break; case #VK_LEFT : .β += 5; break; case #VK_RIGHT: .β -= 5; break; case #VK_PRIOR: .γ += 5; break; case #VK_NEXT : .γ -= 5; break; case #VK_DOWN + #KCF_SHIFT: .Lt0_β -= 5; goto SET_LT0_POS; case #VK_UP + #KCF_SHIFT: .Lt0_β += 5; goto SET_LT0_POS; case #VK_LEFT + #KCF_SHIFT: .Lt0_α -= 5; goto SET_LT0_POS; case #VK_RIGHT + #KCF_SHIFT: .Lt0_α += 5; goto SET_LT0_POS; SET_LT0_POS: .Lt0_Pos(0) = ::Math.cos( #RAD( .Lt0_β )) * ::Math.sin( #RAD( .Lt0_α )); .Lt0_Pos(1) = ::Math.sin( #RAD( .Lt0_β )); .Lt0_Pos(2) = ::Math.cos( #RAD( .Lt0_β )) * ::Math.cos( #RAD( .Lt0_α )); #pc ".Lt0_α,β = ": .Lt0_α, .Lt0_β; break; case #VK_SPACE + #KCF_SHIFT: #p ".MoveDx, .MoveDy = ": .MoveDx, .MoveDy; #p ".CurScale, .ScaleXo, .ScaleYo = ": .CurScale, .ScaleXo, .ScaleYo; #p ".α, .β, .γ, .Lt0_α, .Lt0_β = ": .α, .β, .γ, .Lt0_α, .Lt0_β; return; case #VK_SPACE: .GetMousePos( X'new!, Y'new! ); ( X, Y ) = ( X - .gc.Xd / 2, .gc.Yd / 2 - Y ); #p "Mx, My : ": // ワールド座標系での現マウス位置 (X'float / #FigXd)'f(3), (Y'float / #FigXd)'f(3); return; case `V`: case `C`: case `L`: case `O`: case `S`: case `R`: case `P`: default: return; } .InvalidateRect(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnMouseMove( x, y, ks ) { //if( ks == 0 ) // ボタン押下なし? // return; //#pc "OnMouseMove: ", x, y, ks'x; if( ks & #MK_LBUTTON ) { if( .LBtn == 0 ) { ( .DragXo, .DragYo ) = ( x, y ); ( .DragDx, .DragDy ) = ( 0, 0 ); } else ( .DragDx, .DragDy ) = ( x - .DragXo, .DragYo - y ); .LBtn = 1; .InvalidateRect(); } else { if( .LBtn != 0 ) { .MoveDx += .TmpDx; .MoveDy += .TmpDy; } .LBtn = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnMouseButton( x, y, ks ) { // #pc "OnMouseButton: ", x, y, ks'x; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnMouseWheel( x, y, d ) { ( X, Y ) = .ScreenToClient( x, y ); //#pc "OnMouseWheel: ": X, Y, d; .CurScale += d / 120, ( .ScaleXo, .ScaleYo ) = ( X - .gc.Xd / 2, .gc.Yd / 2 - Y ); .InvalidateRect(); } //----------------------------------------------------------------------------- function ^MainWindow.GetFileNameToOpen( fname ) { if( fname ) ::File.GetNamePart( fname, DirName'new! ); else DirName = ::Module.FilePath(); OFN.Title = "PMDファイル"; OFN.FileSpec'USHORT( #MAX_PATH + 4 ); OFN.FileSpec'puts( "" ); OFN.InitialDir = DirName; OFN.Filter'USHORT( 256 ); i = 0; i += OFN.Filter'puts( "PMDファイル(*.pmd)", i ) + 1; i += OFN.Filter'puts( "*.pmd", i ) + 1; OFN.Flags = #OFN_OVERWRITEPROMPT | #OFN_HIDEREADONLY // | #OFN_NOCHANGEDIR | #OFN_ENABLESIZING | #OFN_PATHMUSTEXIST; if( ! .GetOpenFileName( OFN ) ) return null; #pc "PMDファイル名 = ": OFN.FileSpec'gets; return OFN.FileSpec'gets; } //============================================================================= function ^SetupPMD() // PMD関連データ構造等の設定 { 'CharEnc( "Shift-JIS" ); // 基本データ型 ^G_XYZ 'FLOAT( 3 ); ^G_UV 'FLOAT( 2 ); ^G_RGB 'FLOAT( 3 ); ^G_RGBA 'FLOAT( 4 ); // PMDデータ型 ^PMD_Header ::= { .Id 'C(3); .Version 'FLOAT; .ModelName 'UBYTE(20); .Comment 'UBYTE(256); } ^PMD_HeaderSize = PMD_Header'size; ^PMD_Vertex ::= { .P = ^G_XYZ; // 位置 .N = ^G_XYZ; // 法線 .T = ^G_UV; // テクスチャ内の座標 .Bone1 'SHORT; // ボーン1の番号 .Bone2 'SHORT; // ボーン2の番号 .Weight 'BYTE; // ボーン1の影響度 = 0 〜 100 % ( ボーン2の影響度は、100 - .Weight % ) .Edge 'BYTE; // エッジ( =0: 有効(通常), =1: 無効 ) } ^PMD_VertexSize = PMD_Vertex'size; ^PMD_Material ::= { .Diffuse = ^G_RGBA; // 拡散色 .Shininess 'FLOAT; // 光沢度 .Specular = ^G_RGB; // 反射色 .Ambient = ^G_RGB; // 環境色 .Toon 'BYTE; .Edge 'BYTE; .FaceCountX3 'ULONG; // 本材質の面数×3 .TxFileName 'UBYTE(20);// テクスチャファイル名 or スフィアファイル名 } ^PMD_MaterialSize = ^PMD_Material'size; ^PMD_Bone ::= { .Name 'UBYTE(20); // ボーン名 .Up 'SHORT; // 上位ボーン番号( =-1: 無し ) .End 'SHORT; // 末端ボーン番号( = 0: 末端 ) .Type 'BYTE; // 種類 .IK 'SHORT; // 影響されるIKボーンの番号( =0: 無し ) .P = ^G_XYZ; // 位置 } ^PMD_BoneSize = ^PMD_Bone'size; ^PMD_BoneType = { "回転", "回転/移動", "IK", "不明", "IK影響下", "回転影響下", "IK接続先", "非表示", "捻り", "回転運動" }; ^PMD_IK ::= { .ThisBone 'SHORT; // 本IKのボーン番号 .DestBone 'SHORT; // 本IK対象のボーン番号 .nLB 'BYTE; // 本IKの連結ボーン数 .OpRep 'USHORT; // 演算回数 .OpAng 'FLOAT; // 演算1回あたりの制限角度 //... 'SHORT( .nLB ); // 本IKの連結ボーン番号群 } ^PMD_Morph ::= { .Name 'UBYTE(20); // 表情名 .nMV 'ULONG; // 表情を作る頂点数 .Type 'BYTE; // 種類 //... = ^PMD_MorphVertex( .nMV ); // 本表情を作る頂点群 } ^PMD_MorphType = { "基点", "まゆ", "目", "唇", "その他" }; ^PMD_MorphVertex ::= { .Vertex 'ULONG; // 表情の頂点番号 .P = ^G_XYZ; // 基点からの相対位置( 基点の場合は絶対位置 ) } ^PMD_BoneItem ::= { .Bone 'SHORT; // 枠用ボーン番号 .Frame 'BYTE; // 表示枠番号 } ^PMD_RigidBody ::= { .Name 'UBYTE(20); // 名称 .Bone 'SHORT; // 関連ボーン番号( =-1: 無し ) .Group 'BYTE; // グループ .Target 'SHORT; // 対象 .Type 'BYTE; // 種類 .D = ^G_XYZ; // 長さ( Dx, Dy, Dz ) .P = ^G_XYZ; // 位置( Px, Py, Pz ) .R = ^G_XYZ; // 回転( Rx, Ry, Rz ) [rad] .Mass 'FLOAT; // 質量 .DimP 'FLOAT; // 移動減衰量 .DimR 'FLOAT; // 回転減衰量 .Recoil 'FLOAT; // 反発力 .Friction 'FLOAT; // 摩擦力 .OpType 'BYTE; // 演算タイプ } ^PMD_BodyType = { "球", "箱", "カプセル" }; ^PMD_BodyOpType = { "ボーン追従", "物理演算", "ボーン位置合せ" }; ^PMD_Joint ::= { .Name 'UBYTE(20); // 名称 .BodyA 'LONG; // 剛体A .BodyB 'LONG; // 剛体B .P = ^G_XYZ; // 位置 .R = ^G_XYZ; // 回転 .CP1 = ^G_XYZ; // 拘束:移動1 .CP2 = ^G_XYZ; // 拘束:移動2 .CR1 = ^G_XYZ; // 拘束:回転1 [rad] .CR2 = ^G_XYZ; // 拘束:回転2 [rad] .SP = ^G_XYZ; // ばね:移動 .SR = ^G_XYZ; // ばね:回転 [rad] } return #OK; } //----------------------------------------------------------------------------- function ^ReadPMDFile( fname ) { file = ::File.Open( fname, "in" ); // ヘッダー部の読出し ^PMD_Header; file.Read( ^PMD_Header ); q := ^PMD_Header; #p ## ファイル: ${ file.path + file.name } ヘッダー: Id = ${ q.Id } Version = ${ q.Version } ModelName = ${ q.ModelName'MEMBLK'ps } Comment = ${ PMD_Header.Comment'MEMBLK'ps } ##; if( q.Id != "Pmd" || q.Version != 1.0 ) goto ERR_FILE_DATA; // 頂点データの読み出し file.Read( ^VertexCount'ULONG ); // 頂点数 #p ##頂点数 = ${ ^VertexCount }##; #p "頂点配列サイズ = ": bn = ^VertexCount * ^PMD_VertexSize; if( bn > 0x100000 ) goto ERR_FILE_DATA; file.Read( ^Vertexes'UBYTE( bn ) ); // インデックスデータの読み出し file.Read( ^FaceCountX3'ULONG ); // 面数×3(頂点数/面) #p ##面数×3 = ${ ^FaceCountX3 }##; if( ^FaceCountX3 % 3 != 0 || ^FaceCountX3 > 0x100000 / 2 ) goto ERR_FILE_DATA; #p "インデックス配列サイズ = ": file.Read( ^Indexes'USHORT( ^FaceCountX3 ) ); // 材質データの読み出し file.Read( ^MaterialCount'ULONG ); // 材質数 #p ##材質数 = ${ ^MaterialCount }##; if( ^MaterialCount > 1000 ) goto ERR_FILE_DATA; bn = ^MaterialCount * ^PMD_MaterialSize; delete ^Materials; ^Materials = ::Buffer( bn ); #p "材質配列サイズ = ": file.Read( ^Materials'BYTE( bn ) ); ^Materials.Seek( 0 ); q := ^PMD_Material; delete ^Tex; k = 0; for( i = 0 ; i < ^MaterialCount ; i++ ) { ^Materials.Read( q ); if( ! q.TxFileName(0) ) continue; txf_name = file.path + q.TxFileName'MEMBLK'ps; //txf_name = file.path + "eye2.bmp"; #p i, ^MaterialCount, txf_name; Bmp = ::GK.Bitmap(); if( Bmp.Load( txf_name ) == -1 ) { #p "テクスチャーファイル 不在 or 未対応!"; continue; } #pc Bmp.Xd, Bmp.Yd, Bmp.Zd, txf_name; if( Bmp.Zd != 24 ) { #p "テクスチャーファイル 非対応フォーマット!"; continue; } ( Xd, Yd ) = ( Bmp.Xd & -4, Bmp.Yd & -4 ); Pixs'UBYTE( Xd, Yd, 3 ); for( y = 0 ; y < Yd ; y++ ) { J = y * Bmp.Xb; for( x = 0 ; x < Xd ; x++ ) { j = J + x * 3; Pixs( y, x, 0 ) = Bmp.Pixs( j + 2 ); Pixs( y, x, 1 ) = Bmp.Pixs( j + 1 ); Pixs( y, x, 2 ) = Bmp.Pixs( j ); } } ^Tex[i] ::= { .Xd = Xd; .Yd = Yd; .Pixs <- Pixs; } #p i, ^Tex[i].Xd, ^Tex[i].Yd, ^Tex[i].Pixs; delete Bmp; } ^VertexPtr = ^Vertexes'addr; ^NormalPtr = ^VertexPtr + ^G_XYZ'size; ^TexUV_Ptr = ^NormalPtr + ^G_XYZ'size; ^RGBA 'FLOAT( 4 ) = { 0.0, 0.0, 0.0, 1.0 }; file.Close(); ^PMD_File = fname; ^PMD_ErrMsg = null; return #OK; ERR_FILE_DATA: #p ^PMD_ErrMsg = "ファイルの内容が不正です!"; goto RET_NG; OnFileError: #p ^PMD_ErrMsg = ::ErrorMessage( $err_code, $err_info ); goto RET_NG; OnFileEnd: #p ^PMD_ErrMsg = "予期しないファイル終端です!\n"; RET_NG: ^PMD_File = null; return #NG; } //============================================================================= function SetupOpenGL() // OpenGL のAPIを取得(必要分のみ) { #pv ^ChoosePixelFormat = ::GK.Gdi32.GetEntry( "ChoosePixelFormat" ); #pv ^SetPixelFormat = ::GK.Gdi32.GetEntry( "SetPixelFormat" ); #pv ^GetPixelFormat = ::GK.Gdi32.GetEntry( "GetPixelFormat" ); #pv ^DescribePixelFormat = ::GK.Gdi32.GetEntry( "DescribePixelFormat" ); #pv ^SwapBuffers = ::GK.Gdi32.GetEntry( "SwapBuffers" ); #pv ^GetEnhMetaFilePixelFormat = ::GK.Gdi32.GetEntry( "GetEnhMetaFilePixelFormat" ); #pv ^GL = ::DLL.Link( "OPENGL32", "sys" ); if( ^GL == null ) { #p "OPENGL32.DLL not found!"; return #NG; } #pv ^GLU = ::DLL.Link( "GLU32", "sys" ); if( ^GLU == null ) { #p "GLU32.DLL not found!"; return #NG; } #pv ^glBegin = ^GL.GetEntry( "glBegin" ); #pv ^glClear = ^GL.GetEntry( "glClear" ); #pv ^glClearColor = ^GL.GetEntry( "glClearColor" ); #pv ^glClearDepth = ^GL.GetEntry( "glClearDepth" ); #pv ^glColor3d = ^GL.GetEntry( "glColor3d" ); #pv ^glCullFace = ^GL.GetEntry( "glCullFace" ); #pv ^glDisable = ^GL.GetEntry( "glDisable" ); #pv ^glDisableClientState = ^GL.GetEntry( "glDisableClientState" ); #pv ^glDrawElements = ^GL.GetEntry( "glDrawElements" ); #pv ^glEnable = ^GL.GetEntry( "glEnable" ); #pv ^glEnableClientState = ^GL.GetEntry( "glEnableClientState" ); #pv ^glEnd = ^GL.GetEntry( "glEnd" ); #pv ^glFinish = ^GL.GetEntry( "glFinish" ); #pv ^glFlush = ^GL.GetEntry( "glFlush" ); #pv ^glFrontFace = ^GL.GetEntry( "glFrontFace" ); #pv ^glLightfv = ^GL.GetEntry( "glLightfv" ); #pv ^glLoadIdentity = ^GL.GetEntry( "glLoadIdentity" ); #pv ^glMaterialf = ^GL.GetEntry( "glMaterialf" ); #pv ^glMaterialfv = ^GL.GetEntry( "glMaterialfv" ); #pv ^glMatrixMode = ^GL.GetEntry( "glMatrixMode" ); #pv ^glNormalPointer = ^GL.GetEntry( "glNormalPointer" ); #pv ^glOrtho = ^GL.GetEntry( "glOrtho" ); #pv ^glRotated = ^GL.GetEntry( "glRotated" ); #pv ^glScaled = ^GL.GetEntry( "glScaled" ); #pv ^glTexCoordPointer = ^GL.GetEntry( "glTexCoordPointer" ); #pv ^glTexEnvi = ^GL.GetEntry( "glTexEnvi" ); #pv ^glTexImage2D = ^GL.GetEntry( "glTexImage2D" ); #pv ^glTexParameteri = ^GL.GetEntry( "glTexParameteri" ); #pv ^glTranslated = ^GL.GetEntry( "glTranslated" ); #pv ^glVertex2d = ^GL.GetEntry( "glVertex2d" ); #pv ^glVertex3d = ^GL.GetEntry( "glVertex3d" ); #pv ^glVertexPointer = ^GL.GetEntry( "glVertexPointer" ); #pv ^glViewport = ^GL.GetEntry( "glViewport" ); #pv ^wglCreateContext = ^GL.GetEntry( "wglCreateContext" ); #pv ^wglDeleteContext = ^GL.GetEntry( "wglDeleteContext" ); #pv ^wglMakeCurrent = ^GL.GetEntry( "wglMakeCurrent" ); return #OK; } function ^DeleteOpenGL() { delete ^GL; delete ^GLU; } //----------------------------------------------------------------------------- function ^MainWindow.InitializeOpenGL() // OpenGL の初期設定 { #pc "InitializeOpenGL"; PIXELFORMATDESCRIPTOR ::= { .nSize 'USHORT; .nVersion 'USHORT = 1; .dwFlags 'ULONG = #PFD_DRAW_TO_WINDOW | #PFD_SUPPORT_OPENGL // | #PFD_DOUBLEBUFFER ; .iPixelType 'UBYTE = #PFD_TYPE_RGBA; .cColorBits 'UBYTE = 24; // 24-bit color depth .cRedBits 'UBYTE = 0; // color bits ignored .cRedShift 'UBYTE = 0; // 〃 .cGreenBits 'UBYTE = 0; // 〃 .cGreenShift 'UBYTE = 0; // 〃 .cBlueBits 'UBYTE = 0; // 〃 .cBlueShift 'UBYTE = 0; // 〃 .cAlphaBits 'UBYTE = 0; // no alpha buffer .cAlphaShift 'UBYTE = 0; // shift bit ignored .cAccumBits 'UBYTE = 0; // accum bits ignored .cAccumRedBits 'UBYTE = 0; // 〃 .cAccumGreenBits'UBYTE = 0; // 〃 .cAccumBlueBits 'UBYTE = 0; // 〃 .cAccumAlphaBits'UBYTE = 0; // 〃 .cDepthBits 'UBYTE = 32; // 32-bit z-buffer .cStencilBits 'UBYTE = 0; // no stencil buffer .cAuxBuffers 'UBYTE = 0; // no auxiliary buffer .iLayerType 'UBYTE = #PFD_MAIN_PLANE; // main layer .bReserved 'UBYTE = 0; .dwLayerMask 'ULONG = 0; // layer masks ignored .dwVisibleMask 'ULONG = 0; // 〃 .dwDamageMask 'ULONG = 0; // 〃 } PIXELFORMATDESCRIPTOR.nSize = PIXELFORMATDESCRIPTOR'size; pfd = ::Buffer( PIXELFORMATDESCRIPTOR.nSize ); pfd.Write( PIXELFORMATDESCRIPTOR ); pfd.Seek(0); if(( i = ^ChoosePixelFormat( .gc.hdc, pfd )) <= 0 ) return #NG; if( ^SetPixelFormat( .gc.hdc, i, pfd ) == #FALSE ) return #NG; if(( .hRC = ^wglCreateContext( .gc.hdc )) == #NULL ) return #NG; if( ^wglMakeCurrent( .gc.hdc, .hRC ) == #FALSE ) return #NG; return #OK; } //----------------------------------------------------------------------------- function ^MainWindow.TerminateOpenGL() // OpenGL の終了設定 { #pc "TerminateOpenGL"; ^wglMakeCurrent( #NULL, #NULL ); ^wglDeleteContext( .hRC ); } //=============================================================================