scene 0.0.0.gemkeep → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +138 -0
- data/lib/scene.rb +63 -0
- data/lib/scene/default_scene.rb +88 -0
- metadata +19 -16
data/README.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
## Introduction
|
2
|
+
|
3
|
+
Super Simple Scene is a gem that attempts to make things as easy as possible to get started with OpenGL. It handles all of the messy window setup and provides sensible defaults various things. Under the hood it uses the GLUT windowing system, which is well-known and widely documented. It has been tested in Ruby 1.8.7+ on Mac OSX Snow Leopard.
|
4
|
+
|
5
|
+
<img src='http://i44.tinypic.com/veyp3.png' width="400" height="400" />
|
6
|
+
|
7
|
+
## Getting Started
|
8
|
+
|
9
|
+
**Install the gem:**
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem install scene
|
13
|
+
```
|
14
|
+
|
15
|
+
**Require it in your project:**
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require 'scene'
|
19
|
+
```
|
20
|
+
|
21
|
+
You may need to require 'rubygems' too, if you are running an old version of Ruby.
|
22
|
+
|
23
|
+
**Running the default scene:**
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Scene.display
|
27
|
+
```
|
28
|
+
|
29
|
+
Press H to display help in the terminal.
|
30
|
+
|
31
|
+
**Creating your own scene:**
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class MyScene < Scene
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
end
|
38
|
+
|
39
|
+
def display
|
40
|
+
end
|
41
|
+
|
42
|
+
def timer(elapsed)
|
43
|
+
end
|
44
|
+
|
45
|
+
def keyboard(key, x, y)
|
46
|
+
end
|
47
|
+
|
48
|
+
def mouse(button, state, x, y)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reshape(width, height)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
MyScene.display
|
57
|
+
```
|
58
|
+
|
59
|
+
There is no need to instantiate the class, simply call display and Scene will handle everything for you.
|
60
|
+
|
61
|
+
## Initialize
|
62
|
+
|
63
|
+
Place any code that you wish to run before the first frame is displayed in the initializer. This can include overrides for the default window, or camera settings, e.g.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
def initialize
|
67
|
+
glutReshapeWindow(1000, 1000) # Set the window size to 1000x1000 instead of 800x800
|
68
|
+
glClearColor(1, 1, 1, 1) # Set the window background to white instead of black
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
## Display
|
73
|
+
|
74
|
+
The display method will be called every 10 milliseconds, or thereabouts- depending on your machine. There is no need to clear or swap buffers, Scene will handle that for you. The following will draw a red square:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
def display
|
78
|
+
glColor3f(1, 0, 0)
|
79
|
+
glBegin(GL_POLYGON)
|
80
|
+
glVertex3f(-1, -1, 0)
|
81
|
+
glVertex3f(-1, 1, 0)
|
82
|
+
glVertex3f(1, 1, 0)
|
83
|
+
glVertex3f(1, -1, 0)
|
84
|
+
glEnd
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
The camera is positioned at 0, 0, -4 and is focussed on the origin by default. Feel free to change this in your initializer.
|
89
|
+
|
90
|
+
## Timer
|
91
|
+
|
92
|
+
The timer method is called after each frame is drawn. This is a good place to control animations, for example, you could rotate by x many degrees every time this method is called. Is is given the elapsed time since the previous timer method was called. This allows for building time-accurate animations. It is also a good indication of whether or not your machine is struggling to display the animation if it strays too far from 10ms.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
def timer(elapsed)
|
96
|
+
glRotatef(elapsed * 60, 1, 0, 0) # Rotate in the x-axis at a rate of 60 degrees per second
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
## Keyboard
|
101
|
+
|
102
|
+
The keyboard method is used for responding to keyboard events. It is given the character string and the mouse's x- and y-coordinates at the time of the key-press.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
def keyboard(key, x, y)
|
106
|
+
puts "You pressed #{key} when the mouse was at: #{x}, #{y}"
|
107
|
+
exit(0) if key == 'q'
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
## Mouse
|
112
|
+
|
113
|
+
The mouse method takes a button, state and coordinates. It may be more semantic to use the constant's provided by GLUT, e.g. GLUT_LEFT_BUTTON and GLUT_DOWN.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
def mouse(button, state, x, y)
|
117
|
+
puts "Button: #{button}, State: #{state}, Coordinates: #{x}, #{y}"
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
## Reshape
|
122
|
+
|
123
|
+
The reshape method allows you to specify what happens when the window is resized. Usually you will want to resize the viewport:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
def reshape(width, height)
|
127
|
+
min = [width, height].min
|
128
|
+
x = (width - min) / 2
|
129
|
+
y = (height - min) / 2
|
130
|
+
glViewport(x, y, min, min)
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
## Contribution
|
135
|
+
|
136
|
+
Please feel free to contribute, either through pull requests or feature requests here on Github.
|
137
|
+
|
138
|
+
For news and latest updates, follow me on Twitter ([@cpatuzzo](https://twitter.com/#!/cpatuzzo)).
|
data/lib/scene.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'scene/default_scene'
|
2
|
+
require 'opengl'
|
3
|
+
include Gl, Glu, Glut
|
4
|
+
|
5
|
+
class Scene
|
6
|
+
|
7
|
+
include DefaultScene
|
8
|
+
|
9
|
+
def self.display
|
10
|
+
initialize
|
11
|
+
|
12
|
+
glutDisplayFunc(Proc.new { display_proxy })
|
13
|
+
glutTimerFunc(10, Proc.new { timer_proxy }, 0)
|
14
|
+
glutKeyboardFunc(Proc.new { |key, x, y| keyboard_proxy(key, x, y) })
|
15
|
+
glutMouseFunc(Proc.new { |button, state, x, y| instance.mouse(button, state, x, y) })
|
16
|
+
glutReshapeFunc(Proc.new { |width, height| instance.reshape(width, height) })
|
17
|
+
|
18
|
+
glutMainLoop
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.instance
|
24
|
+
@instance ||= new
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.initialize
|
28
|
+
glutInit
|
29
|
+
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
|
30
|
+
glutInitWindowSize(800, 800)
|
31
|
+
glutCreateWindow('Super Simple Scene')
|
32
|
+
|
33
|
+
glClearColor(0, 0, 0, 0)
|
34
|
+
glEnable(GL_DEPTH_TEST)
|
35
|
+
|
36
|
+
glMatrixMode(GL_PROJECTION)
|
37
|
+
gluPerspective(60, 1, 1, 10)
|
38
|
+
glMatrixMode(GL_MODELVIEW)
|
39
|
+
gluLookAt(0, 0, -4, 0, 0, 1, 0, 1, 0)
|
40
|
+
|
41
|
+
instance # Allow initializer overrides
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.display_proxy
|
45
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
46
|
+
instance.display
|
47
|
+
glutSwapBuffers
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.timer_proxy
|
51
|
+
@time ||= Time.now.to_f
|
52
|
+
elapsed = Time.now.to_f - @time
|
53
|
+
@time = Time.now.to_f
|
54
|
+
instance.timer(elapsed)
|
55
|
+
glutPostRedisplay
|
56
|
+
glutTimerFunc(10, Proc.new { timer_proxy }, 0)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.keyboard_proxy(key, x, y)
|
60
|
+
instance.keyboard(key.chr, x, y)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module DefaultScene
|
2
|
+
|
3
|
+
def display
|
4
|
+
right, left = -1, 1
|
5
|
+
bottom, top = -1, 1
|
6
|
+
front, back = -1, 1
|
7
|
+
|
8
|
+
lbf = [left, bottom, front]
|
9
|
+
lbb = [left, bottom, back]
|
10
|
+
ltf = [left, top, front]
|
11
|
+
ltb = [left, top, back]
|
12
|
+
rbf = [right, bottom, front]
|
13
|
+
rbb = [right, bottom, back]
|
14
|
+
rtf = [right, top, front]
|
15
|
+
rtb = [right, top, back]
|
16
|
+
|
17
|
+
right = [rbf, rbb, rtb, rtf]
|
18
|
+
left = [lbf, ltf, ltb, lbb]
|
19
|
+
bottom = [lbf, lbb, rbb, rbf]
|
20
|
+
top = [ltf, rtf, rtb, ltb]
|
21
|
+
front = [lbf, rbf, rtf, ltf]
|
22
|
+
back = [lbb, ltb, rtb, rbb]
|
23
|
+
|
24
|
+
glLineWidth(5)
|
25
|
+
[right, left, bottom, top, front, back].each do |face|
|
26
|
+
glBegin(GL_POLYGON)
|
27
|
+
face.each do |vertex|
|
28
|
+
color = vertex
|
29
|
+
glColor3f(*color)
|
30
|
+
glVertex3f(*vertex)
|
31
|
+
end
|
32
|
+
glEnd
|
33
|
+
|
34
|
+
if @show_outline
|
35
|
+
@outline ||= [rand, rand, rand]
|
36
|
+
glColor3f(*@outline)
|
37
|
+
glBegin(GL_LINE_LOOP)
|
38
|
+
face.each { |v| glVertex3f(*v) }
|
39
|
+
glEnd
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def timer(elapsed)
|
45
|
+
@show_outline = true if @show_outline.nil?
|
46
|
+
@axes ||= [1, 1, 1]
|
47
|
+
glRotatef(elapsed * 60, *@axes)
|
48
|
+
|
49
|
+
@counter ||= 0
|
50
|
+
@counter += 1
|
51
|
+
if @counter == 100
|
52
|
+
@outline = [rand, rand, rand]
|
53
|
+
@counter = 0
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def keyboard(key, x, y)
|
58
|
+
case key
|
59
|
+
when 'q'
|
60
|
+
exit(0)
|
61
|
+
when 'h'
|
62
|
+
puts
|
63
|
+
puts 'H : Display help'
|
64
|
+
puts 'Q : Quit'
|
65
|
+
puts 'O : Toggle outline'
|
66
|
+
puts 'Left click : Inverse x-rotation'
|
67
|
+
puts 'Middle click : Inverse y-rotation'
|
68
|
+
puts 'Right click : Inverse z-rotation'
|
69
|
+
puts
|
70
|
+
puts 'Visit https://github.com/cpatuzzo/scene for more information'
|
71
|
+
when 'o'
|
72
|
+
@show_outline = !@show_outline
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def mouse(button, state, x, y)
|
77
|
+
return unless state == GLUT_DOWN
|
78
|
+
@axes[button] *= -1
|
79
|
+
end
|
80
|
+
|
81
|
+
def reshape(width, height)
|
82
|
+
min = [width, height].min
|
83
|
+
x = (width - min) / 2
|
84
|
+
y = (height - min) / 2
|
85
|
+
glViewport(x, y, min, min)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scene
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
|
11
|
-
version: 0.0.0.gemkeep
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Christopher Patuzzo
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2012-03-
|
18
|
+
date: 2012-03-03 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: opengl
|
@@ -26,10 +25,14 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
28
|
+
hash: 3953727737
|
30
29
|
segments:
|
31
30
|
- 0
|
32
|
-
|
31
|
+
- 7
|
32
|
+
- 0
|
33
|
+
- pre
|
34
|
+
- 1
|
35
|
+
version: 0.7.0.pre1
|
33
36
|
type: :runtime
|
34
37
|
version_requirements: *id001
|
35
38
|
- !ruby/object:Gem::Dependency
|
@@ -54,8 +57,10 @@ extensions: []
|
|
54
57
|
|
55
58
|
extra_rdoc_files: []
|
56
59
|
|
57
|
-
files:
|
58
|
-
|
60
|
+
files:
|
61
|
+
- README.md
|
62
|
+
- lib/scene/default_scene.rb
|
63
|
+
- lib/scene.rb
|
59
64
|
homepage: https://github.com/cpatuzzo/scene
|
60
65
|
licenses: []
|
61
66
|
|
@@ -76,14 +81,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
82
|
none: false
|
78
83
|
requirements:
|
79
|
-
- - "
|
84
|
+
- - ">="
|
80
85
|
- !ruby/object:Gem::Version
|
81
|
-
hash:
|
86
|
+
hash: 3
|
82
87
|
segments:
|
83
|
-
-
|
84
|
-
|
85
|
-
- 1
|
86
|
-
version: 1.3.1
|
88
|
+
- 0
|
89
|
+
version: "0"
|
87
90
|
requirements: []
|
88
91
|
|
89
92
|
rubyforge_project:
|