.. index:: 
	single: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); はじめに

===========================================================
RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス)
===========================================================


RingOpenGL と RingFreeGLUT の用法を学びます。


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); サンプルソース (作者)

サンプルソース (作者)
=====================

この C チュートリアルを参考に本章のサンプルを記述しました。

出典元:

(1) http://www.lighthouse3d.com/tutorials/glut-tutorial/

(2) http://www.wikihow.com/Make-a-Cube-in-OpenGL


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); RingOpenGL とは？

RingOpenGL とは？
=================

RingOpenGL は Ring 付属の OpenGL ライブラリのバインディングです。

こちらから OpenGL について学べます : https://www.opengl.org/

RingOpenGL は下記のバージョンに対応しています。

* OpenGL 1.1
* OpenGL 1.2
* OpenGL 1.3
* OpenGL 1.4
* OpenGL 1.5
* OpenGL 2.0
* OpenGL 2.1
* OpenGL 3.0
* OpenGL 3.2
* OpenGL 3.3
* OpenGL 4.0
* OpenGL 4.1
* OpenGL 4.2
* OpenGL 4.3
* OpenGL 4.4
* OpenGL 4.5
* OpenGL 4.6

OpenGL 2.1 の場合は RingOpenGL 2.1 ライブラリを読み込みます。

.. code-block:: ring

	load "opengl21lib.ring"


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); RingFreeGLUT とは？

RingFreeGLUT とは？
===================

RingFreeGLUT は Ring 付属の FreeGLUT ライブラリのバインディングです。

このサイトで FreeGLUT について学べます : http://freeglut.sourceforge.net/

RingFreeGLUT の使用前に freeglut.ring ライブラリを読み込みます。

.. code-block:: ring

	load "freeglut.ring"


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); RingFreeGLUT によるはじめてのウィンドウ

RingFreeGLUT によるはじめてのウィンドウ
=======================================

用例:

.. code-block:: ring 

	load "freeglut.ring"

	func main
		glutInit()
		glutInitDisplayMode(GLUT_SINGLE)
		glutInitWindowSize(800, 600)
		glutInitWindowPosition(100, 10)
		glutCreateWindow("RingFreeGLUT - Test 1")
		glutDisplayFunc(:displayCode)
		glutMainLoop()

	func displaycode

スクリーンショット:

.. image:: freeglutshot1.png
	:alt: RingFreeGLUT


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); RingOpenGL での描画


RingOpenGL での描画
===================

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"


	func main
		glutInit()
		glutInitDisplayMode(GLUT_SINGLE)
		glutInitWindowSize(800, 600)
		glutInitWindowPosition(100, 10)
		glutCreateWindow("RingFreeGLUT - Test 2")
		glutDisplayFunc(:displayCode)
		glutMainLoop()

	func displaycode
		glClear(GL_COLOR_BUFFER_BIT)
		glColor3f(0,255,0)
		glBegin(GL_POLYGON)
        		glVertex3f(0.0, 0.0, 0.0)
		        glVertex3f(0.5, 0.0, 0.0)
		        glVertex3f(0.5, 0.5, 0.0)
	        	glVertex3f(0.0, 0.5, 0.0)
		glEnd()
		glColor3f(255,0,0)
		glBegin(GL_POLYGON)
			glVertex3f(0.0, 0.0, 0.0)
        		glVertex3f(0.5, 0.0, 0.0)
	      		glVertex3f(-0.5,- 1, 0.0)
        		glVertex3f(0.0, -1, 0.0)
		glEnd()
		glColor3f(0,0,255)
		glBegin(GL_POLYGON)
	 	       glVertex3f(0.0, 0.0, 0.0)
        		glVertex3f(-0.5, 0.0, 0.0)
		        glVertex3f(-0.5,- 0.5, 0.0)
        		glVertex3f(0.0, -0.5, 0.0)
		glEnd()

		glFlush()

スクリーンショット:

.. image:: freeglutshot2.png
	:alt: RingFreeGLUT


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); はじめての三角形


はじめての三角形
================

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	func main
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowSize(320,320)
		glutInitWindowPosition(100, 10)
		glutCreateWindow("RingFreeGLUT - Test 3")
		glutDisplayFunc(:renderScene)
		glutMainLoop()

	func renderScene

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
	
		glBegin(GL_TRIANGLES)
			glVertex3f(-0.5,-0.5,0.0)
			glVertex3f(0.5,0.0,0.0)
			glVertex3f(0.0,0.5,0.0)
		glEnd()
	
        	glutSwapBuffers()


スクリーンショット:

.. image:: freeglutshot3.png
	:alt: RingFreeGLUT

.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); ウィンドウの大きさ変更イベント

ウィンドウの大きさ変更イベント
==============================

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 4")

		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)

		glutMainLoop()

	func renderScene

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		glBegin(GL_TRIANGLES)
			glVertex3f(-2,-2,-5.0)
			glVertex3f(2,0.0,-5.0)
			glVertex3f(0.0,2,-5.0)
		glEnd()

		glutSwapBuffers()

	func changesize

		h = glutEventHeight()
		w = glutEventWidth()

			// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if (h = 0)
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45,ratio,1,100)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)

.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); 三角形の回転

三角形の回転
============

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	angle = 0

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 5")

		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutMainLoop()

	func renderScene

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	0.0, 0.0, 10.0,
					0.0, 0.0,  0.0,
					0.0, 1.0,  0.0)

		glRotatef(angle, 0.0, 1.0, 0.0)

		glBegin(GL_TRIANGLES)
			glVertex3f(-2.0,-2.0, 0.0)
			glVertex3f( 2.0, 0.0, 0.0)
			glVertex3f( 0.0, 2.0, 0.0)
		glEnd()

		angle+=0.1

		glutSwapBuffers();

	func changesize

		h = glutEventHeight()
		w = glutEventWidth()

			// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if (h = 0)
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45,ratio,1,100)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)


スクリーンショット:

.. image:: freeglutshot4.png
	:alt: RingFreeGLUT
		

.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); キーボードイベントと配色

キーボードイベントと配色
========================

用例:

.. code-block:: ring
		
		
	load "freeglut.ring"
	load "opengl21lib.ring"

	angle = 0

	red=1.0  
	blue=1.0 
	green=1.0

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 6")

		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		// これは新しいエントリーです。
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:processSpecialKeys)

		glutMainLoop()

	func renderScene

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	0.0, 0.0, 10.0,
					0.0, 0.0,  0.0,
					0.0, 1.0,  0.0)

		glRotatef(angle, 0.0, 1.0, 0.0)


		glColor3f(red,green,blue);

		glBegin(GL_TRIANGLES)
			glVertex3f(-2.0,-2.0, 0.0)
			glVertex3f( 2.0, 0.0, 0.0)
			glVertex3f( 0.0, 2.0, 0.0)
		glEnd()

		angle+=0.1

		glutSwapBuffers();

	func changesize

		h = glutEventHeight()
		w = glutEventWidth()

			// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if (h = 0)
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45,ratio,1,100)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)

	func processNormalKeys
		key = GLUTEventKey()
		if key = 27
			shutdown()
		ok

	func processSpecialKeys

		key = GLUTEventKey()

		switch key  
			on GLUT_KEY_F1
					red = 1.0
					green = 0.0
					blue = 0.0
			on GLUT_KEY_F2 
					red = 0.0
					green = 1.0
					blue = 0.0
			on GLUT_KEY_F3
					red = 0.0
					green = 0.0
					blue = 1.0
		off

スクリーンショット:

.. image:: freeglutshot5.png
	:alt: RingFreeGLUT
		

		
.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); カメラ

カメラ
======

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	// カメラ方向の回転角度
	angle=0.0
	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0
	lz=-1.0
	// カメラの XZ 位置
	x=0.0
	z=5.0

	func drawSnowMan

		glColor3f(1.0, 1.0, 1.0)

	// 体の描画
		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

	// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

	// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)

		glPopMatrix()

	// 鼻の描画
		glColor3f(1.0, 0.5 , 0.5)
		glutSolidCone(0.08,0.5,10,2)


	func changeSize
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0  / h 

			// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

			// 行列のリセット
		glLoadIdentity()


		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0);

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)


	func processNormalKeys
		key = glutEventKey()

		if key = 27
			shutdown()
		ok



	func renderScene

		// 配色と深度バッファの消去

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	x, 1.0, z,
				x+lx, 1.0,  z+lz,
				0.0, 1.0,  0.0)

			// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

			// 36 体の雪だるまを描画
		for i = -3 to 2
			for  j=-3 to 2
				glPushMatrix()
				glTranslatef(i*10.0,0,j * 10.0)			
				drawSnowMan()
				glPopMatrix()
			next
		next
		glutSwapBuffers()




	func processSpecialKeys 

		key = glutEventKey()

		fraction = 0.1

		switch key 
			on GLUT_KEY_LEFT 
				angle -= 0.01
				lx = sin(angle)
				lz = -cos(angle)
			on GLUT_KEY_RIGHT 
				angle += 0.01
				lx = sin(angle)
				lz = -cos(angle)
			on GLUT_KEY_UP 
				x += lx * fraction
				z += lz * fraction
			on GLUT_KEY_DOWN 
				x -= lx * fraction
				z -= lz * fraction
		off


	func main

		// GLUT の初期化とウィンドウの作成

		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)

		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 7")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:processSpecialKeys)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()

スクリーンショット:

.. image:: freeglutshot6.png
	:alt: RingFreeGLUT

その他の用例:

.. code-block:: ring 

	load "freeglut.ring"
	load "opengl21lib.ring"

	// カメラ方向の回転角度
	angle = 0.0

	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0 lz=-1.0

	// カメラの XZ 位置
	x=0.0 z=5.0
	// キーの状態
	// キーを押していない時は変数は 0 です。
	deltaAngle = 0.0
	deltaMove = 0

	func changeSize 
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)


	func drawSnowMan

		glColor3f(1.0, 1.0, 1.0)

	// 体の描画

		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

	// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

	// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)
		glPopMatrix()

	// 鼻の描画
		glColor3f(1.0, 0.5 , 0.5)
		glRotatef(0.0,1.0, 0.0, 0.0)
		glutSolidCone(0.08,0.5,10,2)


	func computePos deltaMove

		x += deltaMove * lx * 0.1
		z += deltaMove * lz * 0.1


	func computeDir deltaAngle

		angle += deltaAngle
		lx = sin(angle)
		lz = -cos(angle)

	func renderScene

		if deltaMove
			computePos(deltaMove)
		ok

		if deltaAngle
			computeDir(deltaAngle)
		ok

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	x, 1.0, z,
					x+lx, 1.0,  z+lz,
					0.0, 1.0,  0.0)

	// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

	// 36 体の雪だるまを描画

		for i = -3 to 2
			for j=-3 to 2
				glPushMatrix()
				glTranslatef(i*10.0,0,j * 10.0)
				drawSnowMan()
				glPopMatrix()
			next
		next
		glutSwapBuffers()


	func pressKey 
		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY()

		switch key
			on GLUT_KEY_LEFT 
				 deltaAngle = -0.01 
			on GLUT_KEY_RIGHT 
				 deltaAngle = 0.01 
			on GLUT_KEY_UP 
				 deltaMove = 0.5 
			on GLUT_KEY_DOWN 
				deltaMove = -0.5  
		off

	func releaseKey

		key = glutEventKey()

		switch key
			on GLUT_KEY_LEFT  
				deltaAngle = 0.0
			on GLUT_KEY_RIGHT  
				deltaAngle = 0.0
			on GLUT_KEY_UP  
				deltaMove = 0
			on GLUT_KEY_DOWN  
				deltaMove = 0
		off

	func main 

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 8")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutSpecialFunc(:pressKey)

		// これは新しいエントリーです。
		glutIgnoreKeyRepeat(1)
		glutSpecialUpFunc(:releaseKey)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()
	 
	 
.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); マウスイベント

マウスイベント
==============

用例:

.. code-block:: ring 

	load "freeglut.ring"
	load "opengl21lib.ring"

	// カメラ方向の回転角度
	angle = 0.0

	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0 lz=-1.0

	// カメラの XZ 位置
	x=0.0  z=5.0

	// キーの状態
	// キーを押していない時は変数は 0 です。
	deltaAngle = 0.0
	deltaMove = 0.0
	xOrigin = -1

	func changeSize
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)


	func drawSnowMan

		glColor3f(1.0, 1.0, 1.0)

		// 体の描画
		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

		// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

		// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)
		glPopMatrix()

		// 鼻の描画
		glColor3f(1.0, 0.5 , 0.5)
		glRotatef(0.0,1.0, 0.0, 0.0)
		glutSolidCone(0.08,0.5,10,2)


	func computePos deltaMove

		x += deltaMove * lx * 0.1
		z += deltaMove * lz * 0.1

	func renderScene

		if deltaMove
			computePos(deltaMove)
		ok

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	x, 1.0, z,
				x+lx, 1.0,  z+lz,
				0.0, 1.0,  0.0)

		// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

		// 36 体の雪だるまを描画

		for i = -3 to 2
			for  j=-3 to 2
						 glPushMatrix()
						 glTranslatef(i*10.0,0,j * 10.0)
						 drawSnowMan()
						 glPopMatrix()
			 next
		next
		glutSwapBuffers()

	func processNormalKeys

		key  = glutEventKey()

			if key = 27
				 shutdown()
			ok


	func pressKey
		key  = glutEventKey()

		   switch key
				 on GLUT_KEY_UP
					deltaMove = 0.5 
				 on GLUT_KEY_DOWN
					 deltaMove = -0.5 
		   off


	func releaseKey 
		key  = glutEventKey()
			switch key
				 on GLUT_KEY_UP 
					deltaMove = 0
				 on GLUT_KEY_DOWN 
					deltaMove = 0
			off


	func mouseMove
		xx = glutEventX()
		yy = glutEventY()
			// これは左ボタンを押したときのみ true になります。
			if xOrigin >= 0

			// deltaAngle の更新
			deltaAngle = (xx - xOrigin) * 0.001

			// カメラ方向の更新
			lx = sin(angle + deltaAngle)
			lz = -cos(angle + deltaAngle)
		ok
		
		

	func mouseButton

		button  = glutEventButton()
		state = glutEventState()
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ動作開始になります。
		if button = GLUT_LEFT_BUTTON
			// ボタンを離したとき
			if state = GLUT_UP
				angle += deltaAngle
				xOrigin = -1		
			else  
				// state = GLUT_DOWN
				xOrigin = xx
			ok
			fflush(stdout)
		ok


	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 9")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutIgnoreKeyRepeat(1)
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:pressKey)
		glutSpecialUpFunc(:releaseKey)

		 // ここには二つの新しい関数があります。
		glutMouseFunc(:mouseButton)
		glutMotionFunc(:mouseMove)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); メニューイベント

メニューイベント
================

用例:

.. code-block:: ring 
		
		
	load "freeglut.ring"
	load "opengl21lib.ring"

	// カメラ方向の回転角度
	angle = 0.0

	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0 lz=-1.0

	// カメラの XZ 位置
	x=0.0  z=5.0

	// キーの状態
	// キーを押していない時は変数は 0 です。
	deltaAngle = 0.0
	deltaMove = 0
	xOrigin = -1

	// メニューを定義するための定数


	// RingFreeGLUT では - メニューの項目ごとに異なる ID を指定してください。
	C_RED = 1
	C_GREEN = 2
	C_BLUE  = 3
	C_ORANGE = 4

	C_FILL = 5
	C_LINE = 6

	C_SHRINK = 7
	C_NORMAL = 8

	// ポップアップメニューの定義
	fillMenu= 0  
	shrinkMenu= 0
	mainMenu=0 
	colorMenu=0

	// 鼻の配色
	red = 1.0  blue=0.5  green=0.5

	// 雪だるまの大きさ
	scale = 1.0

	// メニューの状態
	menuFlag = 0

	func changeSize
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)

	func drawSnowMan

		glScalef(scale, scale, scale)
		glColor3f(1.0, 1.0, 1.0)

	// 体の描画
		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

	// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

	// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)
		glPopMatrix()

	// 鼻の描画
		glColor3f(red, green, blue)
		glRotatef(0.0,1.0, 0.0, 0.0)
		glutSolidCone(0.08,0.5,10,2)

		glColor3f(1.0, 1.0, 1.0)


	func computePos deltaMove

		x += deltaMove * lx * 0.1
		z += deltaMove * lz * 0.1


	func renderScene

		if deltaMove
			computePos(deltaMove)
		ok

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()
		// カメラの設定
		gluLookAt(	x, 1.0, z,
				x+lx, 1.0,  z+lz,
				0.0, 1.0,  0.0)

	// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

	// 36 体の雪だるまを描画

		for  i = -3 to 2
			for  j = -3 to 2
				glPushMatrix()
				glTranslatef(i*10.0, 0.0, j * 10.0)
				drawSnowMan()
				glPopMatrix()
			next
		next
		glutSwapBuffers()


	// -----------------------------------
	//             キーボード
	// -----------------------------------

	func processNormalKeys
		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY()

		glutSetMenu(mainMenu)
		switch key
			on 27
				glutDestroyMenu(mainMenu)
				glutDestroyMenu(fillMenu)
				glutDestroyMenu(colorMenu)
				glutDestroyMenu(shrinkMenu)
				shutdown()

			on 's'
				if not menuFlag
				  glutChangeToSubMenu(2,"Shrink",shrinkMenu)
				ok
			on 'c'
				if not menuFlag
					glutChangeToSubMenu(2,"Color",colorMenu)
				ok
		off
		if key = 27
			shutdown()
		ok


	func pressKey 

		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY()

		switch key
			on GLUT_KEY_UP 
				 deltaMove = 0.5
			on GLUT_KEY_DOWN 
				deltaMove = -0.5
		off


	func releaseKey

		key = glutEventKey()

		switch key
			on GLUT_KEY_UP 
				deltaMove = 0 
			on GLUT_KEY_DOWN
				deltaMove = 0  
		off


	// -----------------------------------
	//             マウス
	// -----------------------------------

	func mouseMove
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ true になります。
		if xOrigin >= 0

			// deltaAngle の更新
			deltaAngle = (xx - xOrigin) * 0.001

			// カメラ方向の更新
			lx = sin(angle + deltaAngle)
			lz = -cos(angle + deltaAngle)
		ok


	func mouseButton

		button = glutEventButton()
		state = glutEventState()
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ動作開始になります。
		if button = GLUT_LEFT_BUTTON
			// ボタンを離したとき
			if state = GLUT_UP
				angle += deltaAngle
				xOrigin = -1
			else  
				// state = GLUT_DOWN
				xOrigin = xx
			ok
		ok


	// -----------------------------------
	//             メニュー
	// -----------------------------------

	func processMenuStatus

		status = glutEventStatus()
		xx = glutEventX()
		yy = glutEventY()

		if  status = GLUT_MENU_IN_USE
			menuFlag = 1
		else
			menuFlag = 0
		ok


	func processMainMenu

		// ここにはなにもありません。
		// 動作は全てサブメニューから行います。


	func processFillMenu

		option = glutEventValue()

		switch option

			on C_FILL
				 glPolygonMode(GL_FRONT, GL_FILL) 
			on C_LINE
				 glPolygonMode(GL_FRONT, GL_LINE) 
		off


	func processShrinkMenu

		option = glutEventValue()

		switch option

			on C_SHRINK
				scale = 0.5
			on C_NORMAL
				 scale = 1.0
		off


	func processColorMenu

		option = glutEventValue()

		switch option
			on C_RED 
				red = 1.0
				green = 0.0
				blue = 0.0
			on C_GREEN 
				red = 0.0
				green = 1.0
				blue = 0.0
			on C_BLUE 
				red = 0.0
				green = 0.0
				blue = 1.0
			on C_ORANGE 
				red = 1.0
				green = 0.5
				blue = 0.5
		off


	func createPopupMenus

		shrinkMenu = glutCreateMenu(:processShrinkMenu)

		glutAddMenuEntry("Shrink",C_SHRINK)
		glutAddMenuEntry("NORMAL",C_NORMAL)

		fillMenu = glutCreateMenu(:processFillMenu)

		glutAddMenuEntry("Fill",C_FILL)
		glutAddMenuEntry("Line",C_LINE)

		colorMenu = glutCreateMenu(:processColorMenu)
		glutAddMenuEntry("Red",C_RED)
		glutAddMenuEntry("Blue",C_BLUE)
		glutAddMenuEntry("Green",C_GREEN)
		glutAddMenuEntry("Orange",C_ORANGE)

		mainMenu = glutCreateMenu(:processMainMenu)

		glutAddSubMenu("Polygon Mode", fillMenu)
		glutAddSubMenu("Color", colorMenu)
		 // 右ボタンでメニューへ接続
		glutAttachMenu(GLUT_RIGHT_BUTTON)

		// これでアクティブなメニューであるかどうか検知できるようにします。
		glutMenuStatusFunc(:processMenuStatus)


	// -----------------------------------
	//             メイン
	// -----------------------------------

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 10")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutIgnoreKeyRepeat(1)
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:pressKey)
		glutSpecialUpFunc(:releaseKey)

		 // ここには二つの新しい関数があります。
		glutMouseFunc(:mouseButton)
		glutMotionFunc(:mouseMove)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)
		glEnable(GL_CULL_FACE)

		// メニューの初期化
		createPopupMenus()

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()

スクリーンショット:

.. image:: freeglutshot7.png
	:alt: RingFreeGLUT


.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); フォントの用法

フォントの用法
==============

用例:

.. code-block:: ring 
		
	load "freeglut.ring"
	load "opengl21lib.ring"


	// カメラ方向の回転角度
	angle = 0.0

	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0 lz=-1.0

	// カメラの XZ 位置
	x=0.0  z=5.0

	// キーの状態
	// キーを押していない時は変数は 0 です。
	deltaAngle = 0.0
	deltaMove = 0
	xOrigin = -1

	// メニューを定義するための定数
	C_RED  = 1
	C_GREEN = 2
	C_BLUE = 3
	C_ORANGE = 4

	C_FILL = 5
	C_LINE = 6

	// ポップアップメニューの定義
	fillMenu=NULL
	fontMenu=NULL
	mainMenu=NULL
	colorMenu=NULL

	// 鼻の配色
	red = 1.0
	blue=0.5
	green=0.5

	// 雪だるまの大きさ
	scale = 1.0

	// メニューの状態
	menuFlag = 0

	// デフォルトのフォント
	font = GLUT_BITMAP_TIMES_ROMAN_24

	C_INT_GLUT_BITMAP_8_BY_13 = 7
	C_INT_GLUT_BITMAP_9_BY_15 = 8
	C_INT_GLUT_BITMAP_TIMES_ROMAN_10  = 9
	C_INT_GLUT_BITMAP_TIMES_ROMAN_24  = 10
	C_INT_GLUT_BITMAP_HELVETICA_10  = 11
	C_INT_GLUT_BITMAP_HELVETICA_12  = 12
	C_INT_GLUT_BITMAP_HELVETICA_18  = 13

	func changeSize
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)

	func drawSnowMan

		glScalef(scale, scale, scale)
		glColor3f(1.0, 1.0, 1.0)

	// 体の描画
		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

	// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

	// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)
		glPopMatrix()

	// 鼻の描画
		glColor3f(red, green, blue)
		glRotatef(0.0,1.0, 0.0, 0.0)
		glutSolidCone(0.08,0.5,10,2)

		glColor3f(1.0, 1.0, 1.0)

	func renderBitmapString x,y,z,font,string
		glRasterPos3f(x, y,z)
		for c in string
			glutBitmapCharacter(font,ascii(c))
		next


	func computePos deltaMove

		x += deltaMove * lx * 0.1
		z += deltaMove * lz * 0.1


	func renderScene

		if  deltaMove
			computePos(deltaMove)
		ok

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()

		// カメラの設定
		gluLookAt(	x, 1.0, z,
				x+lx, 1.0,  z+lz,
				0.0, 1.0,  0.0)

		// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

	// 36 体の雪だるまを描画
		for i = -3 to 2
			for j = -3 to 2
				glPushMatrix()
				glTranslatef(i*10.0, 0.0, j * 10.0)
				drawSnowMan()
				number = (i+3)*6+(j+3)
				renderBitmapString(0.0, 0.5, 0.0,font ,""+number)
				glPopMatrix()
			next
		next

		glutSwapBuffers()


	// -----------------------------------
	//             キーボード
	// -----------------------------------

	func processNormalKeys
		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY() 

		switch key
			on 27
				glutDestroyMenu(mainMenu)
				glutDestroyMenu(fillMenu)
				glutDestroyMenu(colorMenu)
				glutDestroyMenu(fontMenu)
				Shutdown()
		off


	func pressKey 

		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY()

		switch key
			on GLUT_KEY_UP 
				 deltaMove = 0.5
			on GLUT_KEY_DOWN 
				deltaMove = -0.5
		off


	func releaseKey

		key = glutEventKey()

		switch key
			on GLUT_KEY_UP 
				deltaMove = 0 
			on GLUT_KEY_DOWN
				deltaMove = 0  
		off


	// -----------------------------------
	//             マウス
	// -----------------------------------

	func mouseMove
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ true になります。
		if xOrigin >= 0

			// deltaAngle の更新
			deltaAngle = (xx - xOrigin) * 0.001

			// カメラ方向の更新
			lx = sin(angle + deltaAngle)
			lz = -cos(angle + deltaAngle)
		ok


	func mouseButton

		button = glutEventButton()
		state = glutEventState()
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ動作開始になります。
		if button = GLUT_LEFT_BUTTON
			// ボタンを離したとき
			if state = GLUT_UP
				angle += deltaAngle
				xOrigin = -1
			else  
				// state = GLUT_DOWN
				xOrigin = xx
			ok
		ok


	// -----------------------------------
	//             メニュー
	// -----------------------------------

	func processMenuStatus

		status = glutEventStatus()

		if status = GLUT_MENU_IN_USE
			menuFlag = 1
		else
			menuFlag = 0
		ok


	func processMainMenu 

		// ここにはなにもありません。
		// 動作は全てサブメニューから行います。


	func processFillMenu

		option = glutEventValue()

		switch option

			on C_FILL
				glPolygonMode(GL_FRONT, GL_FILL)
			on C_LINE
				 glPolygonMode(GL_FRONT, GL_LINE)
		off


	func processFontMenu 

		option = glutEventValue()

		switch (option) {
			on C_INT_GLUT_BITMAP_8_BY_13
				font = GLUT_BITMAP_8_BY_13
			on C_INT_GLUT_BITMAP_9_BY_15
				font = GLUT_BITMAP_9_BY_15
			on C_INT_GLUT_BITMAP_TIMES_ROMAN_10
				font = GLUT_BITMAP_TIMES_ROMAN_10
			on C_INT_GLUT_BITMAP_TIMES_ROMAN_24
				font = GLUT_BITMAP_TIMES_ROMAN_24
			on C_INT_GLUT_BITMAP_HELVETICA_10
				font = GLUT_BITMAP_HELVETICA_10
			on C_INT_GLUT_BITMAP_HELVETICA_12
				font = GLUT_BITMAP_HELVETICA_12
			on C_INT_GLUT_BITMAP_HELVETICA_18
				font = GLUT_BITMAP_HELVETICA_18
		off
	 
	func processColorMenu

		option = glutEventValue()

		switch option 
			on C_RED 
				red = 1.0
				green = 0.0
				blue = 0.0
			on C_GREEN 
				red = 0.0
				green = 1.0
				blue = 0.0
			on C_BLUE 
				red = 0.0
				green = 0.0
				blue = 1.0
			on C_ORANGE 
				red = 1.0
				green = 0.5
				blue = 0.5
		off


	func createPopupMenus

		fontMenu = glutCreateMenu(:processFontMenu)

		glutAddMenuEntry("BITMAP_8_BY_13 ",C_INT_GLUT_BITMAP_8_BY_13 )
		glutAddMenuEntry("BITMAP_9_BY_15",C_INT_GLUT_BITMAP_9_BY_15 )
		glutAddMenuEntry("BITMAP_TIMES_ROMAN_10 ",C_INT_GLUT_BITMAP_TIMES_ROMAN_10  )
		glutAddMenuEntry("BITMAP_TIMES_ROMAN_24",C_INT_GLUT_BITMAP_TIMES_ROMAN_24  )
		glutAddMenuEntry("BITMAP_HELVETICA_10 ",C_INT_GLUT_BITMAP_HELVETICA_10  )
		glutAddMenuEntry("BITMAP_HELVETICA_12",C_INT_GLUT_BITMAP_HELVETICA_12  )
		glutAddMenuEntry("BITMAP_HELVETICA_18",C_INT_GLUT_BITMAP_HELVETICA_18  )

		fillMenu = glutCreateMenu(:processFillMenu)

		glutAddMenuEntry("Fill",C_FILL)
		glutAddMenuEntry("Line",C_LINE)

		colorMenu = glutCreateMenu(:processColorMenu)
		glutAddMenuEntry("Red",C_RED);
		glutAddMenuEntry("Blue",C_BLUE);
		glutAddMenuEntry("Green",C_GREEN);
		glutAddMenuEntry("Orange",C_ORANGE);

		mainMenu = glutCreateMenu(:processMainMenu)

		glutAddSubMenu("Polygon Mode", fillMenu)
		glutAddSubMenu("Color", colorMenu)
		glutAddSubMenu("Font",fontMenu)
		 // 右ボタンでメニューへ接続
		glutAttachMenu(GLUT_RIGHT_BUTTON)

		// これでアクティブなメニューであるかどうか検知できるようにします。
		glutMenuStatusFunc(:processMenuStatus)


	// -----------------------------------
	//             メイン
	// -----------------------------------

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test 11")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutIgnoreKeyRepeat(1)
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:pressKey)
		glutSpecialUpFunc(:releaseKey)

		 // ここには二つの新しい関数があります。
		glutMouseFunc(:mouseButton)
		glutMotionFunc(:mouseMove)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)
		glEnable(GL_CULL_FACE)

		// メニューの初期化
		createPopupMenus()

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()

スクリーンショット:

.. image:: freeglutshot8.png
	:alt: RingFreeGLUT

	
.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); 一秒あたりのフレーム数

一秒あたりのフレーム数
======================

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	// カメラ方向の回転角度
	angle = 0.0

	// 実際のベクトルはカメラ方向を表しています。
	lx=0.0 lz=-1.0

	// カメラの XZ 位置
	x=0.0  z=5.0

	// キーの状態
	// キーを押していない時は変数は 0 です。
	deltaAngle = 0.0
	deltaMove = 0
	xOrigin = -1

	// メニューを定義するための定数
	C_RED  = 1
	C_GREEN = 2
	C_BLUE = 3
	C_ORANGE = 4

	C_FILL = 5
	C_LINE = 6

	// ポップアップメニューの定義
	fillMenu=NULL
	fontMenu=NULL
	mainMenu=NULL
	colorMenu=NULL

	// 鼻の配色
	red = 1.0
	blue=0.5
	green=0.5

	// 雪だるまの大きさ
	scale = 1.0

	// メニューの状態
	menuFlag = 0

	// デフォルトのフォント
	font = GLUT_BITMAP_TIMES_ROMAN_24

	C_INT_GLUT_BITMAP_8_BY_13 = 7
	C_INT_GLUT_BITMAP_9_BY_15 = 8
	C_INT_GLUT_BITMAP_TIMES_ROMAN_10  = 9
	C_INT_GLUT_BITMAP_TIMES_ROMAN_24  = 10
	C_INT_GLUT_BITMAP_HELVETICA_10  = 11
	C_INT_GLUT_BITMAP_HELVETICA_12  = 12
	C_INT_GLUT_BITMAP_HELVETICA_18  = 13

	// ウィンドウの幅と高さ
	h = 0
	w = 0

	// 一秒あたりのフレーム数を計算するための変数
	frame=0
	time=0
	timebase=0
	s = ""

	func changeSize
		w = glutEventWidth()
		h = glutEventHeight()

		// ウィンドウの大きさが小さすぎる場合に、ゼロ除算エラーになるのを防ぎます。
		// (幅 0 のウィンドウは作成できません)
		if h = 0
			h = 1
		ok

		ratio =  w * 1.0 / h

		// 投射行列の使用
		glMatrixMode(GL_PROJECTION)

		// 行列のリセット
		glLoadIdentity()

		// ウィンドウ全体のビューポートを設定します。
		glViewport(0, 0, w, h)

		 // 正しい遠近法の設定
		gluPerspective(45.0, ratio, 0.1, 100.0)

		// Modelview の復帰
		glMatrixMode(GL_MODELVIEW)

	func drawSnowMan

		glScalef(scale, scale, scale)
		glColor3f(1.0, 1.0, 1.0)

	// 体の描画
		glTranslatef(0.0 ,0.75, 0.0)
		glutSolidSphere(0.75,20,20)

	// 頭の描画
		glTranslatef(0.0, 1.0, 0.0)
		glutSolidSphere(0.25,20,20)

	// 目の描画
		glPushMatrix()
		glColor3f(0.0,0.0,0.0)
		glTranslatef(0.05, 0.10, 0.18)
		glutSolidSphere(0.05,10,10)
		glTranslatef(-0.1, 0.0, 0.0)
		glutSolidSphere(0.05,10,10)
		glPopMatrix()

	// 鼻の描画
		glColor3f(red, green, blue)
		glRotatef(0.0,1.0, 0.0, 0.0)
		glutSolidCone(0.08,0.5,10,2)

		glColor3f(1.0, 1.0, 1.0)

	func renderBitmapString x,y,z,font,string
		glRasterPos3f(x, y,z)
		for c in string
			glutBitmapCharacter(font,ascii(c))
		next

	func renderStrokeFontString x,y,z,font,string
		glPushMatrix()
		glTranslatef(x, y,z)
		glScalef(0.002, 0.002, 0.002)
		for c in string
			glutStrokeCharacter(font, Ascii(c));
		next
		glPopMatrix()


	func restorePerspectiveProjection

		glMatrixMode(GL_PROJECTION)
		// 以前の投射行列へ復帰
		glPopMatrix()

		// Modelview モードの復帰
		glMatrixMode(GL_MODELVIEW)


	func setOrthographicProjection

		// 投射モードの切り替え
		glMatrixMode(GL_PROJECTION)

		// 透視図の設定を有する
		// 以前の行列を保存します。
		glPushMatrix()

		// 行列のリセット
		glLoadIdentity()

		// 2D 正投射の設定
		gluOrtho2D(0, w, h, 0)

		// modelview モードへ復帰切り替え
		glMatrixMode(GL_MODELVIEW)



	func computePos deltaMove

		x += deltaMove * lx * 0.1
		z += deltaMove * lz * 0.1


	func renderScene

		if  deltaMove
			computePos(deltaMove)
		ok

		// 配色と深度バッファの消去
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		// 変換のリセット
		glLoadIdentity()

		// カメラの設定
		gluLookAt(	x, 1.0, z,
				x+lx, 1.0,  z+lz,
				0.0, 1.0,  0.0)

		// 地面の描画

		glColor3f(0.9, 0.9, 0.9)
		glBegin(GL_QUADS)
			glVertex3f(-100.0, 0.0, -100.0)
			glVertex3f(-100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0,  100.0)
			glVertex3f( 100.0, 0.0, -100.0)
		glEnd()

	// 9 体の雪だるまを描画
		for i = -3 to -1
			for j = -3 to -1
				glPushMatrix()
				glTranslatef(i*10.0, 0.0, j * 10.0)
				drawSnowMan()
				number = (i+3)*3+(j+3)
				renderBitmapString(0.0, 0.5, 0.0,font ,""+number)
				glPopMatrix()
			next
		next

		// 一秒あたりのフレーム数を計算するためのコード
		frame++

		time=glutGet(GLUT_ELAPSED_TIME)
		if time - timebase > 1000 
			s = "RingFreeGLUT - FPS: " + (frame*1000.0/(time-timebase))
			timebase = time
			frame = 0
		ok

		// ビットマップフォントで文字列 (fps) を表示するためのコード
		setOrthographicProjection()

		glPushMatrix()
		glLoadIdentity()
		renderBitmapString(5,30,0,GLUT_BITMAP_HELVETICA_18,s)
		glPopMatrix()

		restorePerspectiveProjection()

		glutSwapBuffers()


	// -----------------------------------
	//             キーボード
	// -----------------------------------

	func processNormalKeys
		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY() 

		switch key
			on 27
				glutDestroyMenu(mainMenu)
				glutDestroyMenu(fillMenu)
				glutDestroyMenu(colorMenu)
				glutDestroyMenu(fontMenu)
				Shutdown()
		off


	func pressKey 

		key = glutEventKey()
		xx = glutEventX()
		yy = glutEventY()

		switch key
			on GLUT_KEY_UP 
				 deltaMove = 0.5
			on GLUT_KEY_DOWN 
				deltaMove = -0.5
		off


	func releaseKey

		key = glutEventKey()

		switch key
			on GLUT_KEY_UP 
				deltaMove = 0 
			on GLUT_KEY_DOWN
				deltaMove = 0  
		off


	// -----------------------------------
	//             マウス
	// -----------------------------------

	func mouseMove
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ true になります。
		if xOrigin >= 0

			// deltaAngle の更新
			deltaAngle = (xx - xOrigin) * 0.001

			// カメラ方向の更新
			lx = sin(angle + deltaAngle)
			lz = -cos(angle + deltaAngle)
		ok


	func mouseButton

		button = glutEventButton()
		state = glutEventState()
		xx = glutEventX()
		yy = glutEventY()

		// これは左ボタンを押したときのみ動作開始になります。
		if button = GLUT_LEFT_BUTTON
			// ボタンを離したとき
			if state = GLUT_UP
				angle += deltaAngle
				xOrigin = -1
			else  
				// state = GLUT_DOWN
				xOrigin = xx
			ok
		ok


	// -----------------------------------
	//             メニュー
	// -----------------------------------

	func processMenuStatus

		status = glutEventStatus()

		if status = GLUT_MENU_IN_USE
			menuFlag = 1
		else
			menuFlag = 0
		ok


	func processMainMenu 

		// ここにはなにもありません。
		// 動作は全てサブメニューから行います。


	func processFillMenu

		option = glutEventValue()

		switch option

			on C_FILL
				glPolygonMode(GL_FRONT, GL_FILL)
			on C_LINE
				 glPolygonMode(GL_FRONT, GL_LINE)
		off


	func processFontMenu 

		option = glutEventValue()

		switch (option) {
			on C_INT_GLUT_BITMAP_8_BY_13
				font = GLUT_BITMAP_8_BY_13
			on C_INT_GLUT_BITMAP_9_BY_15
				font = GLUT_BITMAP_9_BY_15
			on C_INT_GLUT_BITMAP_TIMES_ROMAN_10
				font = GLUT_BITMAP_TIMES_ROMAN_10
			on C_INT_GLUT_BITMAP_TIMES_ROMAN_24
				font = GLUT_BITMAP_TIMES_ROMAN_24
			on C_INT_GLUT_BITMAP_HELVETICA_10
				font = GLUT_BITMAP_HELVETICA_10
			on C_INT_GLUT_BITMAP_HELVETICA_12
				font = GLUT_BITMAP_HELVETICA_12
			on C_INT_GLUT_BITMAP_HELVETICA_18
				font = GLUT_BITMAP_HELVETICA_18
		off
	 
	func processColorMenu

		option = glutEventValue()

		switch option 
			on C_RED 
				red = 1.0
				green = 0.0
				blue = 0.0
			on C_GREEN 
				red = 0.0
				green = 1.0
				blue = 0.0
			on C_BLUE 
				red = 0.0
				green = 0.0
				blue = 1.0
			on C_ORANGE 
				red = 1.0
				green = 0.5
				blue = 0.5
		off


	func createPopupMenus

		fontMenu = glutCreateMenu(:processFontMenu)

		glutAddMenuEntry("BITMAP_8_BY_13 ",C_INT_GLUT_BITMAP_8_BY_13 )
		glutAddMenuEntry("BITMAP_9_BY_15",C_INT_GLUT_BITMAP_9_BY_15 )
		glutAddMenuEntry("BITMAP_TIMES_ROMAN_10 ",C_INT_GLUT_BITMAP_TIMES_ROMAN_10  )
		glutAddMenuEntry("BITMAP_TIMES_ROMAN_24",C_INT_GLUT_BITMAP_TIMES_ROMAN_24  )
		glutAddMenuEntry("BITMAP_HELVETICA_10 ",C_INT_GLUT_BITMAP_HELVETICA_10  )
		glutAddMenuEntry("BITMAP_HELVETICA_12",C_INT_GLUT_BITMAP_HELVETICA_12  )
		glutAddMenuEntry("BITMAP_HELVETICA_18",C_INT_GLUT_BITMAP_HELVETICA_18  )

		fillMenu = glutCreateMenu(:processFillMenu)

		glutAddMenuEntry("Fill",C_FILL)
		glutAddMenuEntry("Line",C_LINE)

		colorMenu = glutCreateMenu(:processColorMenu)
		glutAddMenuEntry("Red",C_RED);
		glutAddMenuEntry("Blue",C_BLUE);
		glutAddMenuEntry("Green",C_GREEN);
		glutAddMenuEntry("Orange",C_ORANGE);

		mainMenu = glutCreateMenu(:processMainMenu)

		glutAddSubMenu("Polygon Mode", fillMenu)
		glutAddSubMenu("Color", colorMenu)
		glutAddSubMenu("Font",fontMenu)
		 // 右ボタンでメニューへ接続
		glutAttachMenu(GLUT_RIGHT_BUTTON)

		// これでアクティブなメニューであるかどうか検知できるようにします。
		glutMenuStatusFunc(:processMenuStatus)


	// -----------------------------------
	//             メイン
	// -----------------------------------

	func main

		// GLUT の初期化とウィンドウの作成
		glutInit()
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA)
		glutInitWindowPosition(100,100)
		glutInitWindowSize(320,320)
		glutCreateWindow("RingFreeGLUT - Test - 9 SnowMan")

		// コールバックの登録
		glutDisplayFunc(:renderScene)
		glutReshapeFunc(:changeSize)
		glutIdleFunc(:renderScene)

		glutIgnoreKeyRepeat(1)
		glutKeyboardFunc(:processNormalKeys)
		glutSpecialFunc(:pressKey)
		glutSpecialUpFunc(:releaseKey)

		 // ここには二つの新しい関数があります。
		glutMouseFunc(:mouseButton)
		glutMotionFunc(:mouseMove)

		// OpenGL の初期化
		glEnable(GL_DEPTH_TEST)
		glEnable(GL_CULL_FACE)

		// メニューの初期化
		createPopupMenus()

		// GLUT のイベント処理サイクルへ入ります。
		glutMainLoop()


スクリーンショット:

一枚目のスクリーンショット:

.. image:: ring15freeglut.png
	:alt: RingFreeGLUT


二枚目のスクリーンショット:

.. image:: ring15freeglut2.png
	:alt: RingFreeGLUT

.. index:: 
	pair: RingOpenGL と RingFreeGLUT の用法 (3D グラフィックス); RingOpenGL と RingFreeGLUT による立方体の作例

RingOpenGL と RingFreeGLUT による立方体の作例
=============================================

用例:

.. code-block:: ring

	load "freeglut.ring"
	load "opengl21lib.ring"

	// ----------------------------------------------------------
	// グローバル変数
	// ----------------------------------------------------------
	rotate_y=0 
	rotate_x=0
	 
	// ----------------------------------------------------------
	// display() コールバック関数
	// ----------------------------------------------------------
	func display
	 
	  // 画面と Z バッファの消去
	  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
	 
	  // 変換のリセット
	  glLoadIdentity()
	 
	  // rotate_x および rotate_y のユーザによる変更をリセットします。
	  glRotatef( rotate_x, 1.0, 0.0, 0.0 )
	  glRotatef( rotate_y, 0.0, 1.0, 0.0 )
	 
	  // 多色面 - 前
	  glBegin(GL_POLYGON)
	 
	  glColor3f( 1.0, 0.0, 0.0 )     glVertex3f(  0.5, -0.5, -0.5 )      # P1 is red
	  glColor3f( 0.0, 1.0, 0.0 )     glVertex3f(  0.5,  0.5, -0.5 )      # P2 is green
	  glColor3f( 0.0, 0.0, 1.0 )     glVertex3f( -0.5,  0.5, -0.5 )      # P3 is blue
	  glColor3f( 1.0, 0.0, 1.0 )     glVertex3f( -0.5, -0.5, -0.5 )      # P4 is purple
	 
	  glEnd()
	 
	  // 白面 - 後
	  glBegin(GL_POLYGON)
	  glColor3f(   1.0,  1.0, 1.0 )
	  glVertex3f(  0.5, -0.5, 0.5 )
	  glVertex3f(  0.5,  0.5, 0.5 )
	  glVertex3f( -0.5,  0.5, 0.5 )
	  glVertex3f( -0.5, -0.5, 0.5 )
	  glEnd()
	 
	  // 紫面 - 右
	  glBegin(GL_POLYGON)
	  glColor3f(  1.0,  0.0,  1.0 )
	  glVertex3f( 0.5, -0.5, -0.5 )
	  glVertex3f( 0.5,  0.5, -0.5 )
	  glVertex3f( 0.5,  0.5,  0.5 )
	  glVertex3f( 0.5, -0.5,  0.5 )
	  glEnd()
	 
	  // 緑面 - 左
	  glBegin(GL_POLYGON)
	  glColor3f(   0.0,  1.0,  0.0 )
	  glVertex3f( -0.5, -0.5,  0.5 )
	  glVertex3f( -0.5,  0.5,  0.5 )
	  glVertex3f( -0.5,  0.5, -0.5 )
	  glVertex3f( -0.5, -0.5, -0.5 )
	  glEnd()
	 
	  // 青面 - 上
	  glBegin(GL_POLYGON)
	  glColor3f(   0.0,  0.0,  1.0 )
	  glVertex3f(  0.5,  0.5,  0.5 )
	  glVertex3f(  0.5,  0.5, -0.5 )
	  glVertex3f( -0.5,  0.5, -0.5 )
	  glVertex3f( -0.5,  0.5,  0.5 )
	  glEnd()
	 
	  // 赤面 - 下
	  glBegin(GL_POLYGON)
	  glColor3f(   1.0,  0.0,  0.0 )
	  glVertex3f(  0.5, -0.5, -0.5 )
	  glVertex3f(  0.5, -0.5,  0.5 )
	  glVertex3f( -0.5, -0.5,  0.5 )
	  glVertex3f( -0.5, -0.5, -0.5 )
	  glEnd()
	 
	  glFlush()
	  glutSwapBuffers()
	 
	 
	// ----------------------------------------------------------
	// specialKeys() コールバック関数
	// ----------------------------------------------------------
	func specialKeys

		key = glutEventKey()
	 
	  // 右矢印 - 回転を五度増分します。
		switch Key

		on GLUT_KEY_RIGHT
			rotate_y += 5
	 
		// 左矢印 - 回転を五度減分します。
		on GLUT_KEY_LEFT
			rotate_y -= 5
	 
		on GLUT_KEY_UP
			rotate_x += 5
	 
		on GLUT_KEY_DOWN
			rotate_x -= 5
	 
		off

	  //  更新の要求
	  glutPostRedisplay()
	 

	 
	// ----------------------------------------------------------
	// main() 関数
	// ----------------------------------------------------------
	func main
	 
	  // GLUT の初期化とユーザ仮引数の処理
	  glutInit()
	 
	  // トゥルーカラーのウィンドウのために Z-バッファによるダブルバッファを要求します。
	  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
	 
	  // ウィンドウの作成
	  glutCreateWindow("Awesome Cube")
	 
	  // Z バッファの深度テストを有効にします。
	  glEnable(GL_DEPTH_TEST)
	 
	  // コールバック関数
	  glutDisplayFunc(:display)
	  glutSpecialFunc(:specialKeys)
	 
	  // イベントに関する GLUT への制御を渡します。
	  glutMainLoop()
	 
	  // OS へ戻ります。


スクリーンショット:

.. image:: ring15opengl.png
	:alt: RingOpenGL

