File: tutorial.txt

package info (click to toggle)
ruby-opengl 0.60.1%2Bdfsg2-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 2,044 kB
  • ctags: 4,889
  • sloc: ansic: 24,676; ruby: 9,400; sh: 12; makefile: 10
file content (469 lines) | stat: -rw-r--r-- 15,489 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
Usage Tutorial
==============
This page should serve as tutorial and also as reference to Ruby bindings for OpenGL
language. It is assumed that you have basic understanding of both OpenGL and Ruby.

If you are new to OpenGL, you can start by visiting [OpenGL homepage](http://www.opengl.org)
, reading the [OpenGL Programming Guide](http://opengl.org/documentation/books/#the_opengl_programming_guide_the_official_guide_to_learning_opengl_version) (also known as Red Book) or going to [NeHe's tutorials page](http://nehe.gamedev.net/).

If you are new to Ruby, [the ruby-lang website](http://www.ruby-lang.org/en/documentation/) contains lots of
documentation and manuals for Ruby.

Table of Contents
==============
Basics:
* [Naming Conventions](#naming_conventions)<br/>
* [Function parameters](#function_parameters)<br/>
* [Return values](#return_values)<br/>
* [Matrices](#matrices)<br/>
* [Textures and other raw data](#textures)<br/>
* [Error Checking](#error_checking)<br/>
* [Examples](#examples)<br/>

Advanced stuff:
* [OpenGL version and Extensions](#extensions)<br/>
* [Selection and Feedback queries](#selection_feedback)<br/>
* [Vertex Arrays](#vertex_arrays)<br/>
* [Buffer Objects](#buffer_objects)<br/>
* [GLUT, SDL, GLFW..](#glut_sdl)<br/>
* [GLUT callbacks](#glut_callbacks)<br/>
* [Internals](#internals)<br/>

API reference:
* TODO

<a name="naming_conventions"></a>
Naming conventions
------------------

The bindings contains three modules:
* 'Gl' - OpenGL functions itself
* 'Glu' - OpenGL Utility Library API - higher-level drawing routines, NURBS etc.
* 'Glut' - OpenGL Utility Toolkit - low level functions such as creating OpenGL
  context, opening window or handling user input

You can import all three modules by calling

	{{ruby}}
	require 'opengl'

You can also load the modules separately by using:

	{{ruby}}
	require 'gl'
	require 'glu'
	require 'glut'

The functions and constants are named the same as their C counterparts:

	{{ruby}}
	require 'opengl'
	...
	Gl.glFooBar( Gl::GL_FOO_BAR )
	Glu.gluFooBar( Glu::GLU_FOO_BAR )
	Glut.glutFooBar( Glut::GLUT_FOO_BAR )

This is the 'full' syntax, usefull when you are expecting name clashes
with other modules, or just want to be formal ;) More often, you will
want to use the 'C-style' syntax, which you can accomplish by using 'include'
to export the module functions and constants to global namespace:

	{{ruby}}
	require 'opengl'
	include Gl,Glu,Glut
	...
	glFooBar( GL_FOO_BAR )
	gluFooBar( GLU_FOO_BAR )
	glutFooBar( GLUT_FOO_BAR )

Finally, you can use the 'old' syntax:

	{{ruby}}
	require 'opengl'
	...
	# Note the missing prefixes in functions and constants
	# and also capitalization of module names
	GL.FooBar( GL::FOO_BAR )
	GLU.FooBar( GLU::FOO_BAR )
	GLUT.FooBar( GLUT::FOO_BAR )

This syntax was used by previous ruby-opengl versions; some people also
consider it as being more in the spirit of OO programming. It has one
downside though - due to Ruby's naming scheme, you cannot use constants
which begins with number, e.g. GL_2D would under this syntax be (GL::)2D
which is illegal.

All three variants of syntax will continue to be supported in future,
so it's up to you which one you choose to use.

The rest of this tutorial will use the C syntax.

Calling syntax
--------------
<a name="function_parameters"></a>
Function parameters
--------------
For most types the ruby syntax follows the C API. If needed, ruby will do
automatic parameter conversion to required type if possible. Example:

	{{ruby}}
	glVertex3f( 1.0, 1.0, 1.0 )  # matches C syntax
	glVertex3f( 1, 1, 1 )        # equivalent to the above
	glVertex3f( "string", 1, 1 ) # raises TypeError exception
		
Arrays are passed/received as Ruby arrays:

	{{ruby}}
	vertex = [ 1, 1, 1 ]
	glVertex3fv( vertex )

For functions with multiple parameter-number variations (glVertex,glColor,...)
we define 'overloaded' functions, as in:

	{{ruby}}
	glVertexf( 1, 1 )       # will call glVertex2f()
	glVertexf( 1, 1, 1 )    # will call glVertex3f()
	glVertexf( 1, 1, 1, 1 ) # will call glVertex4f()
	glVertexi( 1, 1 )       # will call glVertex2i()
	...
	# and so on

<a name="return_values"></a>
Return values
-------------
In C, OpenGL functions rarely return values directly, instead you pass in pointer to
preallocated buffer and they will fill it with values; sometimes you have to even query
how big buffer you'll need to allocate. Ruby does this all for you, returning either single
value or array:

	{{ruby}}
	glColor4f( 1.0, 1.0, 1.0, 1.0 )
	...
	color =	glGetDoublev(GL_CURRENT_COLOR)
	p color # will be [1.0,1.0,1.0,1.0]

<a name="matrices"></a>
Matrices
-------------
Matrices are passed and received as ruby array, or as ruby Matrix objects:

	{{ruby}}
	matrix_a = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
	matrix_b = [ [  0, 1, 2, 3 ],
	             [  4, 5, 6, 7 ],
	             [  8, 9,10,11 ],
	             [ 12,13,14,15 ] ]
	matrix_c = Matrix.rows( [ [  0, 1, 2, 3 ],
	                          [  4, 5, 6, 7 ],
	                          [  8, 9,10,11 ],
	                          [ 12,13,14,15 ] ] )
	...
	glLoadMatrixf(matrix_a)
	glLoadMatrixf(matrix_b) 
	glLoadMatrixf(matrix_c) # same result

You may also create your own matrix class and pass it this way, provided that it
is convertible to array (has 'to_a' method).

Note that as OpenGL uses column-major
notation for matrices, you may need to call transpose() when working with
row-major matrices or arrays in ruby.

<a name="textures"></a>
Textures and other raw data
-------------
Data for textures, arrays, buffers etc. can be specified either as ruby arrays or directly as raw packed strings -
strings that contains their direct memory representation (just like C arrays). If you need to convert between
ruby arrays and these strings, use ruby Array#pack() and String#unpack() functions.
Example:

	{{ruby}}
	# create texture, 2x2 pixels,
	# 3 components (R,G,B) for each pixel as floats
	texture = [
	           1.0, 0.0, 0.0, # 1st pixel, red
	           0.0, 1.0, 0.0, # 2nd pixel, green
	           0.0, 0.0, 1.0, # 3rd pixel, blue
	           1.0, 1.0, 1.0  # 4th pixel, white
	          ]
	# convert it to string
	# f = native float representation
	# * = convert all values in the array the same way
	data = texture.pack("f*")
	...
	glTexImage2D(
	  GL_TEXTURE_2D, # target
	  0,             # mipmap level,
	  GL_RGB8,       # internal format
	  2, 2,          # width, height
	  0,             # border = no
	  GL_RGB,        # components per each pixel
	  GL_FLOAT,      # component type - floats
	  data           # the packed data
	)

Reverse works just the same:

	{{ruby}}
	...
	data = glGetTexImage( # returns the packed data as string
	  GL_TEXTURE_2D, # target
	  0,             # mipmap level
	  GL_RGB,        # components per pixel
	  GL_FLOAT       # component type
	)
	# now convert it to ruby array
	texture = data.unpack("f*")
	...

For storage, packed strings are more memory efficient than ruby arrays, but
cannot be easily changed or manipulated.

<a name="error_checking"></a>
Error Checking
--------------
Starting with version 0.60.0, ruby-opengl performs automatic checking of OpenGL and GLU errors.
Functions:

	{{ruby}}
	Gl.enable_error_checking
	Gl.disable_error_checking
	Gl.is_error_checking_enabled? # true/false

When the checking is enabled (default), glGetError() is executed after each OpenGL call, and should error
occur, Gl::Error exception is raised:

	{{ruby}}
	Gl.enable_error_checking
	...
	begin 
	  ...
	  glEnable(GL_TRUE) # will raise exception
	  ...
	rescue Gl::Error => err
		# err.id contains the OpenGL error ID
		if (err.id == GL_INVALID_ENUM)
			puts "Oh noes! You used invalid enum!"
			...
		end
		...
	end

Some GLU functions may also throw Glu::Error - the handling is the same as above.

It is usually good idea to leave error checking on for all your code, as OpenGL errors have habit to pop-up in
unexpected places. For now there is no measurable performance hit for error checking, although this may depend
on your graphic drivers implementation.

<a name="examples"></a>
The Examples
-----------

Various examples are in 'examples' directory of the bindings. To run them, manually pass them to `ruby` like:

    ruby some_sample.rb

On windows, you may want to use 'rubyw' instead, which displays the standard output window
as some examples use the console for usage info etc.

If you get 'opengl not found' error, and you installed ruby-opengl from gems, your
shell or ruby installation is probably not configured to use the gems; in that case type:

    ruby -rubygems some_sample.rb

The `README` file in the `examples` directory contains some notes on the examples.

<a name="extensions"></a>
OpenGL Version and Extensions 
-----------
To query for available OpenGL version or OpenGL extension, use Gl.is_available? function:

	{{ruby}}
	# true if OpenGL version is 2.0 or later is available
	Gl.is_available?(2.0)
	...
	# returns true if GL_ARB_shadow is available on this system
	Gl.is_available?("GL_ARB_shadow")
	
For list of what extensions are supported in ruby-opengl see this [page](extensions.html)

The extensions' function names once again follows the C API. Some extensions were over time
promoted to ARB or even to OpenGL core, retaining their function names just with suffix changed
or removed. However sometimes the functions semantics was changed in the process, so to avoid
confusion, ruby-opengl bindings will strictly adhere to the C naming, e.g. :

	{{ruby}}
	# will call the function from GL_ARB_transpose_matrix extension
	glLoadTransposeMatrixfARB(matrix)
	...
	# will call the function from OpenGL 1.3
	glLoadTransposeMatrixf(matrix)

<b>Note:</b> ruby-opengl is compiled against OpenGL 1.1, and all functions and enums from later
versions of OpenGL and from extensions are loaded dynamically at runtime. That means that all
of OpenGL 2.1 and supported extensions are available even if the ruby-opengl bindings are
compiled on platform which lacks proper libraries or headers (like for example Windows without
installed graphic drivers). This should ease binary-only distribution and application packaging.


<a name="selection_feedback"></a>
Selection/Feedback queries
-----------
Querying selection and feedback is different from C. Example:

	{{ruby}}
	# this will create selection buffer 512*sizeof(GLuint) long
	buf = glselectbuffer(512)
	# enter feedback mode
	glRenderMode(GL_SELECT) 
	... # draw something here	
	# return to render mode
	count = glRenderMode(GL_RENDER)
	# at this point the buf string is freezed and contains
	# the selection data, which you can recover with unpack
	# function
	data = buf.unpack("I*") # I for unsigned integer
	# also, next call to glRenderMode(GL_SELECT) will overwrite
	# the 'buf' buffer with new data

The feedback query follows the same pattern, only the data are stored
as floats.

<a name="vertex_arrays"></a>
Vertex Arrays
-----------
In current state, vertex arrays are not very efficient in ruby-opengl, as it is not possible to change
the array content once it is specified, and there is overhead for converting between ruby and C representation
of numbers. Using display lists for static and immediate mode for dynamic objects is recommended instead.

You can specify the data the same way as [texture data](#textures). Example:

	{{ruby}}
	normals = [0,1,0, 1,0,0, 1,1,1]
	glNormalPointer(GL_FLOAT,0,normals)
	...
	glEnable(GL_NORMAL_ARRAY)
	glDrawArrays(...)
	...

This applies to all *pointer functions. glGetPointerv will return reference to the frozen string
previously specified.

<a name="buffer_objects"></a>
Buffer Objects
-----------
Once again, in current state buffer objects (VBOs in particular) are not very efficient in ruby-opengl.
Unlike textures and vertex arrays, the data for buffers *must* be prepacked by using .pack() function,
as buffers does not retain information about the storage type. Mapping of the buffer afterwards is read-only. 

Like in C, buffer binding affects some functions in way that if particular buffer is bound, the related
functions (for example glTexImage) take integer offset in place of data string argument. This is also true
for getter functions (e.g. glGetTexImage) - instead of returning the data string, they take offset as they're
last argument (so in ruby they take one extra argument), and will write the data in the bound buffer as expected.

VBO example:

	{{ruby}}
	# specify 3 vertices, 2*float each
	data = [0,0, 0,1, 1,1].pack("f*")
	...
	# generate buffer name
	buffers = glGenBuffers(1)
	# bind to the name to ARRAY buffer for vertex array
	glBindBuffer(GL_ARRAY_BUFFER,buffers[0])
	# here the data is specified, size is n*sizeof(float)
	# note that you don't get to specify type, as buffers
	# operate on byte level
	glBufferData(GL_ARRAY_BUFFER,6*4,data,GL_DYNAMIC_DRAW)
	...
	# here instead of specyfing the data, you pass '0' (or
	# positive integer) as offset to the bound buffer
	glVertexPointer(2,GL_FLOAT,0,0)
	...
	glEnableClientState(GL_VERTEX_ARRAY)
	...

<a name="glut_sdl"></a>
GLUT, SDL, GLFW..
---------
When it comes to low-level task like GL window creation, input and event handling, the first choice is GLUT,
as it is readilly available alongside OpenGL. However both GLUT itself and its implementations
have their drawbacks, and for that and other reasons there are number of replacement libraries.
You can use any of them with ruby-opengl (as long as there are ruby bindings for them).

Here is example for [SDL](http://www.kmc.gr.jp/~ohai/index.en.html):

	{{ruby}}
	require 'opengl'
	require 'sdl'
	# init
	SDL.init(SDL::INIT_VIDEO)
	SDL.setGLAttr(SDL::GL_DOUBLEBUFFER,1)
	SDL.setVideoMode(512,512,32,SDL::OPENGL)
	...
	Gl.glVertex3f(1.0,0.0,0.0)
	...
	SDL.GLSwapBuffers()
	...

and another example for [GLFW](http://ruby-glfw.rubyforge.org/):

	{{ruby}}
	require 'opengl'
	require 'glfw'
	# init
	Glfw.glfwOpenWindow( 500,500, 0,0,0,0, 32,0, Glfw::GLFW_WINDOW )
	...
	Gl.glVertex3f(1.0,0.0,0.0)
	...
	Glfw.glfwSwapBuffers()
	...

<a name="glut_callbacks"></a>
GLUT callbacks
--------------

The GLUT callback functions are specified as Proc objects, which you can
either create with lambda as:

	{{ruby}}
	reshape = lambda do |w, h|
	  ...
	end
	...
	glutReshapeFunc( reshape )

or by conversion from normal functions:

	{{ruby}}
	def reshape(w,h)
	  ...
	end
	...
	glutReshapeFunc( method("reshape").to_proc )
    
Note: An older notation you'll see instead of `lambda` is `proc`. The
PickAxe v2 notes that `proc` is "mildly deprecated" in favor of `lambda`.
You'll also sometimes see `Proc.new` used in place of either. Pages 359-360 of
PickAxe v2 describe the differences between using `lambda` and `Proc.new`,
but for our purposes either will be fine.

<a name="internals"></a>
Internals
---------

The directory structure follows current Ruby standards, with a few
extra directories added.

* `doc/` -- Contains documentation for the project (from which this
  website is generated).
* `examples/` -- Example programs.
* `ext/` -- Contains subdirectories, one for each of the three extension
  modules (gl, glu, glut). Herein are the files needed to compile the extension
  modules.
* `lib/` -- Files that the user is meant to `require` in their own code.
* `test/` -- Contains automatic testsuite for the bindings
* `utils` -- Some utility scripts used to help generate code, documentation
  and website.
* `website` -- After running `rake gen_website` this directory will contain
  the ruby-opengl website.