/* =============================================================================== CubeSpin.mc : OpenGL の確認 --- 自転する立方体を表示する =============================================================================== Copyright (C) 2010 Masahiko Watanabe Edition History: Ver.1.00 2010.11.27( GK Library: Rev.2010.11.20 使用 ) -----------------------------------------------------------------------------*/ /*****/ // 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 pc print //#set pv print #set p print //----------------------------------------------------------------------------- /// マクロ定義 /// #set WndTitle "OpenGL 入門: 自転する立方体" // ウィンドウ表題 #set WndXo // ウィンドウの左端位置(空白はデフォールト位置) #set WndYo // ウィンドウの上端位置(空白はデフォールト位置) #set FigXd 480 // 図形描画領域の幅 #set FigYd 480 // 図形描画領域の高さ #set VF_Timer 101 // 画面更新タイマー識別値 #set VF_Rate 30 // 画面更新回数/秒 //----------------------------------------------------------------------------- // OpenGL 関連のマクロ定義 #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 #set GL_AMBIENT 0x1200 #set GL_COLOR_BUFFER_BIT 0x00004000 #set GL_CULL_FACE 0x0B44 #set GL_DEPTH_BUFFER_BIT 0x00000100 #set GL_DEPTH_TEST 0x0B71 #set GL_DIFFUSE 0x1201 #set GL_FALSE 0 #set GL_FRONT 0x0404 #set GL_FRONT_AND_BACK 0x0408 #set GL_LIGHT0 0x4000 #set GL_LIGHT_MODEL_AMBIENT 0x0B53 #set GL_LIGHT_MODEL_TWO_SIDE 0x0B52 #set GL_LIGHTING 0x0B50 #set GL_MODELVIEW 0x1700 #set GL_POSITION 0x1203 #set GL_PROJECTION 0x1701 #set GL_QUADS 0x0007 #set GL_SHININESS 0x1601 #set GL_SPECULAR 0x1202 //============================================================================= function Main( argc, argv ) { #pc "開始"; ^DefValue = null; if( SetupOpenGL() == #OK ) { class ^MainWindow : ::GK.Window {} R = ::GK.Rect( 0, 0, #FigXd, #FigYd ); ::GK.Window.GetAdjRect( R ); ^MainWindow.Construct( #WndTitle, #WndXo, #WndYo, R.Xd, R.Yd ); ^MainWindow.Open(); ^MainWindow.StartTimer( #VF_Timer, 1000 / #VF_Rate ); ::GK.WindowMsgLoop(); delete ^MainWindow; } DeleteOpenGL(); #pc "終了"; } //----------------------------------------------------------------------------- function ^MainWindow.OnCreate() { #pc "OnCreate"; if( .InizOpenGL() != #OK ) { print "OpenGL 初期設定エラー!"; .Close(); } .InizFigData(); // 描画データの設定 .InizLighting( ); // 光源の初期設定 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnDestroy() { #pc "OnDestroy"; .StopTimer( #VF_Timer ); .TermOpenGL(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnSize() { #pc "OnSize", .gc.Xd, .gc.Yd, .Min?(); if( .gc.Xd <= 0 || .gc.Yd <= 0 ) return; .FigRect = ::GK.Rect( 0, 0, .gc.Xd, .gc.Yd ); .ResizeFigArea(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnPaint() { #pc "OnPaint"; .GetHotRect( R'STRUCT ); if( ! .FigRect.Out?( R ) ) .DrawFigArea(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.OnTimer( id ) { //#pc "OnTimer: ", id; if( id == #VF_Timer ) { .DrawFigArea(); .Angle = ( .Angle + 1.0 ) % 360.0; } } //----------------------------------------------------------------------------- function ^MainWindow.InizOpenGL() // OpenGL の初期設定 { #pc "InizOpenGL"; 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.TermOpenGL() // OpenGL の終了設定 { #pc "TermOpenGL"; ^wglMakeCurrent( #NULL, #NULL ); ^wglDeleteContext( .hRC ); } //----------------------------------------------------------------------------- function ^MainWindow.InizFigData() { .Cube ::= { .Vertex'DOUBLE( 8, 3 ) = // 立方体の各頂点 { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } }; .Face'BYTE( 6, 4 ) = // 立方体の各面を構成する頂点のインデックス { { 0, 1, 2, 3 }, { 1, 5, 6, 2 }, { 5, 4, 7, 6 }, { 4, 0, 3, 7 }, { 4, 5, 1, 0 }, { 3, 2, 6, 7 } }; .Normal'DOUBLE( 6, 3 ); // 立方体の各面の法線ベクトル CalcNormal( .Vertex, .Face, .Normal ); // 立方体の材質 .Ambient 'FLOAT(4) = { 0.20, 0.50, 0.50, 1.0 }; // 環境光反射係数 .Diffuse 'FLOAT(4) = { 0.40, 1.00, 1.00, 1.0 }; // 拡散光反射係数 .Specular'FLOAT(4) = { 0.10, 0.30, 0.30, 1.0 }; // 鏡面光反射係数 .Shininess = 20.0; // 鏡面係数 } .LightPos'FLOAT( 4 ) = { 0.0, 0.0, 10.0, 1.0 }; .Angle = 0.0; // 立方体の回転角度(単位:°) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function CalcNormal( V, F, N ) // 各面の法線ベクトルを計算する { m = F'count( 1 ); // 面数 for( i = 0 ; i < m ; i++ ) { P0 = F( i, 0 ); P1 = F( i, 1 ); P2 = F( i, 2 ); Ax = V( P2, 0 ) - V( P0, 0 ); Ay = V( P2, 1 ) - V( P0, 1 ); Az = V( P2, 2 ) - V( P0, 2 ); Bx = V( P1, 0 ) - V( P0, 0 ); By = V( P1, 1 ) - V( P0, 1 ); Bz = V( P1, 2 ) - V( P0, 2 ); X = Ay * Bz - Az * By; Y = Az * Bx - Ax * Bz; Z = Ax * By - Ay * Bx; D = ::Math.sqrt( X*X + Y*Y + Z*Z ); N( i, 0 ) = X / D; N( i, 1 ) = Y / D; N( i, 2 ) = Z / D; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.ResizeFigArea() { ^glViewport( 0, 0, .gc.Xd, .gc.Yd ); ^glMatrixMode( #GL_PROJECTION ); ^glLoadIdentity(); ^gluPerspective( 15.0, .gc.Xd'float / .gc.Yd, 1.0, 100.0 ); ^gluLookAt( 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.DrawFigArea() { ^glClearColor( 0.0'sfv, 0.2'sfv, 0.5'sfv, 1.0'sfv ); // 背景色 ^glClearDepth( 1.0 ); ^glClear( #GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT ); ^glEnable( #GL_DEPTH_TEST ); ^glEnable( #GL_CULL_FACE ); ^glCullFace( #GL_FRONT ); // 立方体の素材を指定 ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_AMBIENT , .Cube.Ambient ); ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_DIFFUSE , .Cube.Diffuse ); ^glMaterialfv( #GL_FRONT_AND_BACK, #GL_SPECULAR, .Cube.Specular ); ^glMaterialf( #GL_FRONT_AND_BACK, #GL_SHININESS, .Cube.Shininess'sfv ); // 立方体を自転させる変換行列を設定 ^glMatrixMode( #GL_MODELVIEW ); ^glPushMatrix(); ^glLoadIdentity(); ^glRotated( .Angle, 1.0, 0.0, 0.0 ); // X軸周りに回転 ^glRotated( .Angle, 0.0, 1.0, 0.0 ); // Y軸周りに回転 ^glRotated( .Angle, 0.0, 0.0, 1.0 ); // Z軸周りに回転 ^glTranslated( -0.5, -0.5, -0.5 ); // 立方体の中心を原点に移動 // 立方体の各面を描画 ^glBegin( #GL_QUADS ); for( j = 0; j < 6 ; j++ ) { ^glNormal3dv( .Cube.Normal( j, 0 )'addr ); for( i = 0 ; i < 4 ; i++ ) { ^glVertex3dv( .Cube.Vertex( .Cube.Face( j, i ), 0 )'addr ); } } ^glEnd(); ^glPopMatrix(); ^glFinish(); ^SwapBuffers( .gc.hdc ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function ^MainWindow.InizLighting() // 光源の初期設定 { ^glEnable( #GL_LIGHTING ); // 共通光 BaseAmbient'FLOAT(4) = { 0.2, 0.2, 0.2, 1.0 }; // 環境光係数 ^glLightModelfv( #GL_LIGHT_MODEL_AMBIENT, BaseAmbient ); //^glLightModeli( #GL_LIGHT_MODEL_TWO_SIDE, #GL_FALSE ); // 光源0の設定 ^glEnable( #GL_LIGHT0 ); Position'FLOAT(4) = { 0.0, 1.0, 1.0, 0.0 }; // 方向(ベクトル) ^glLightfv( #GL_LIGHT0 , #GL_POSITION, Position ); Ambient 'FLOAT(4) = { 0.8, 0.8, 0.8, 1.0 }; // 環境光係数 Diffuse 'FLOAT(4) = { 0.8, 0.8, 0.8, 1.0 }; // 拡散光係数 Specular'FLOAT(4) = { 0.8, 0.8, 0.8, 1.0 }; // 鏡面光係数 ^glLightfv( #GL_LIGHT0 , #GL_AMBIENT , Ambient ); ^glLightfv( #GL_LIGHT0 , #GL_DIFFUSE , Diffuse ); ^glLightfv( #GL_LIGHT0 , #GL_SPECULAR, Specular ); } //============================================================================= 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 ^glCullFace = ^GL.GetEntry( "glCullFace" ); #pv ^glEnable = ^GL.GetEntry( "glEnable" ); #pv ^glEnd = ^GL.GetEntry( "glEnd" ); #pv ^glFinish = ^GL.GetEntry( "glFinish" ); #pv ^glLightfv = ^GL.GetEntry( "glLightfv" ); #pv ^glLightModelfv = ^GL.GetEntry( "glLightModelfv" ); #pv ^glLightModeli = ^GL.GetEntry( "glLightModeli" ); #pv ^glLoadIdentity = ^GL.GetEntry( "glLoadIdentity" ); #pv ^glMaterialf = ^GL.GetEntry( "glMaterialf" ); #pv ^glMaterialfv = ^GL.GetEntry( "glMaterialfv" ); #pv ^glMatrixMode = ^GL.GetEntry( "glMatrixMode" ); #pv ^glNormal3dv = ^GL.GetEntry( "glNormal3dv" ); #pv ^glPopMatrix = ^GL.GetEntry( "glPopMatrix" ); #pv ^glPushMatrix = ^GL.GetEntry( "glPushMatrix" ); #pv ^glRotated = ^GL.GetEntry( "glRotated" ); #pv ^glTranslated = ^GL.GetEntry( "glTranslated" ); #pv ^gluLookAt = ^GLU.GetEntry( "gluLookAt" ); #pv ^gluPerspective = ^GLU.GetEntry( "gluPerspective" ); #pv ^glVertex3dv = ^GL.GetEntry( "glVertex3dv" ); #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; } //-----------------------------------------------------------------------------