rbglox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +21 -0
- data/README.md +184 -0
- data/bin/rbglox +85 -0
- data/lib/rbglox.rb +126 -0
- data/lib/rbglox/app.rb +9 -0
- data/lib/rbglox/mesh.rb +36 -0
- data/lib/rbglox/meshcube.rb +99 -0
- data/lib/rbglox/meshquad.rb +29 -0
- data/lib/rbglox/resource.rb +14 -0
- data/lib/rbglox/shader.rb +115 -0
- data/lib/rbglox/texture.rb +52 -0
- data/lib/rbglox/version.rb +3 -0
- data/lib/rbglox/window.rb +172 -0
- data/res/shader.glsl +35 -0
- data/res/texture.tga +0 -0
- data/test/test_rbglox.rb +9 -0
- metadata +131 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
THE MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2011, Mihail Szabolcs
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
rbGLox
|
2
|
+
======
|
3
|
+
rbGLox is a small wrapper over the ruby-opengl, ruby-glfw family by abstracting
|
4
|
+
and providing some high-level interfaces for things like "Textures",
|
5
|
+
"GLSL Shaders", basic "Geometry" and others.
|
6
|
+
|
7
|
+
It's ideal for rapid prototyping new and interesting ideas.
|
8
|
+
|
9
|
+
rbGLox is the sister project of [pyGLox](http://github.com/icebreaker/pyGLox).
|
10
|
+
|
11
|
+
Dependencies
|
12
|
+
------------
|
13
|
+
* [ruby-opengl](https://rubygems.org/gems/ruby-opengl)
|
14
|
+
* [ruby-glfw](https://rubygems.org/gems/ruby-glfw)
|
15
|
+
* [directory-watcher](https://rubygems.org/gems/directory_watcher)
|
16
|
+
|
17
|
+
Getting Started
|
18
|
+
---------------
|
19
|
+
|
20
|
+
### Install
|
21
|
+
|
22
|
+
gem install rbglox
|
23
|
+
|
24
|
+
### Library
|
25
|
+
|
26
|
+
Using rbGLox as a library is a very easy :)
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'rbglox'
|
30
|
+
class DemoApp < RBGLox::App
|
31
|
+
def init
|
32
|
+
@texture = RBGLox::Texture.new 'mosaic.tga'
|
33
|
+
@r = 0.0
|
34
|
+
@cube = RBGLox::MeshCube.new
|
35
|
+
end
|
36
|
+
def update
|
37
|
+
@r += 0.1
|
38
|
+
end
|
39
|
+
def draw
|
40
|
+
glTranslatef 0.0,0.0,-6.0
|
41
|
+
glRotatef @r, 1.0, 1.0, 1.0
|
42
|
+
|
43
|
+
@texture.bind
|
44
|
+
@cube.draw
|
45
|
+
@texture.release
|
46
|
+
end
|
47
|
+
def shutdown
|
48
|
+
@texture.free
|
49
|
+
@cube.free
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
Now let's fire this up :)
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
DemoApp.new do |app|
|
58
|
+
app.title = 'DemoApp'
|
59
|
+
app.exec
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Additional methods you can override:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
resize(h, w)
|
67
|
+
begin_frame
|
68
|
+
end_frame
|
69
|
+
reload(event)
|
70
|
+
```
|
71
|
+
|
72
|
+
#### Semi-automatic resource re-loading
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
DemoApp.new do |app|
|
76
|
+
app.watch = 'data/'
|
77
|
+
app.title = 'DemoApp'
|
78
|
+
app.exec
|
79
|
+
end
|
80
|
+
```
|
81
|
+
If the `watch` variable is not `nil` then the given directory will be watched
|
82
|
+
for any changes. (i.e file modified, file created, etc)
|
83
|
+
|
84
|
+
Every time a change is detected, the `reload(event)` method is called and you can
|
85
|
+
reload your resources.
|
86
|
+
|
87
|
+
The included `RBGLox::Texture` and `RBGLox::Shader` classes have a `reload` method
|
88
|
+
which facilitates this as illustrated in the example below.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
...
|
92
|
+
def reload(event)
|
93
|
+
if event.type == :modified
|
94
|
+
texture1.reload if event.path =~ /myawesometexture.tga$/
|
95
|
+
shader.reload if event.path =~ /myshader.glsl$/
|
96
|
+
...
|
97
|
+
end
|
98
|
+
...
|
99
|
+
end
|
100
|
+
...
|
101
|
+
```
|
102
|
+
|
103
|
+
### Executable
|
104
|
+
|
105
|
+
It is also possible to use rbGLox as a cheap & rudimentary "GLSL" shader editor.
|
106
|
+
|
107
|
+
In order to create a new project do the following:
|
108
|
+
|
109
|
+
mkdir glsl-demo
|
110
|
+
cd glsl-demo
|
111
|
+
rbglox --init
|
112
|
+
|
113
|
+
This will create an empty project with one shader and one texture.
|
114
|
+
|
115
|
+
To launch "editor" just type `rbglox` in the current directory and there you go.
|
116
|
+
|
117
|
+
#### Watcher
|
118
|
+
|
119
|
+
All the resources in the current directory are "watched" for changes and will be
|
120
|
+
reloaded automatically when a change is detected.
|
121
|
+
|
122
|
+
So, if you edit the shaders or the textures they will be reloaded for you without
|
123
|
+
restarting the "editor".
|
124
|
+
|
125
|
+
#### Shaders
|
126
|
+
|
127
|
+
The shader file has the following format:
|
128
|
+
|
129
|
+
[vertex]
|
130
|
+
...
|
131
|
+
[end]
|
132
|
+
|
133
|
+
[fragment]
|
134
|
+
...
|
135
|
+
[end]
|
136
|
+
|
137
|
+
[uniforms]
|
138
|
+
...
|
139
|
+
[end]
|
140
|
+
|
141
|
+
Please consult the generated `default shader` when you start a "new project" for
|
142
|
+
more details.
|
143
|
+
|
144
|
+
The shader must be named `shader.glsl` in order to be used and loaded.
|
145
|
+
|
146
|
+
|
147
|
+
#### Textures
|
148
|
+
|
149
|
+
Only textures in the TGA format are supported and they are going to be loaded
|
150
|
+
in alphabetical order. If there are more than 4 textures, only the first 4
|
151
|
+
will be loaded and assigned to the first 4 available texture units.
|
152
|
+
|
153
|
+
The textures must be named in the following format: `textureN.tga` where `N`
|
154
|
+
is a number ranging from 1 to 4.
|
155
|
+
|
156
|
+
#### Models (a.k.a Meshes)
|
157
|
+
|
158
|
+
You can choose between a Quad, a Cube (a.k.a Box) and a Teapot. The default is
|
159
|
+
the Teapot.
|
160
|
+
|
161
|
+
rbglox --model teapot
|
162
|
+
|
163
|
+
#### Controls
|
164
|
+
|
165
|
+
* Hold down the left mouse button and move the mouse in order to rotate the model.
|
166
|
+
* Use the mouse wheel to zoom in / zoom out the model.
|
167
|
+
|
168
|
+
rbMedia
|
169
|
+
-------
|
170
|
+
The bundled texture is from [lovetextures.com](http://lovetextures.com) .
|
171
|
+
|
172
|
+
Contribute
|
173
|
+
----------
|
174
|
+
* Fork the project.
|
175
|
+
* Make your feature addition or bug fix.
|
176
|
+
* Send me a pull request. Bonus points for topic branches.
|
177
|
+
* Do **not** bump the version number.
|
178
|
+
|
179
|
+
License
|
180
|
+
-------
|
181
|
+
Copyright (c) 2011, Mihail Szabolcs
|
182
|
+
|
183
|
+
rbGLox is provided as-is under the **MIT** license. For more information
|
184
|
+
see *LICENSE* .
|
data/bin/rbglox
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require 'rbglox'
|
6
|
+
require 'optparse'
|
7
|
+
require 'ftools'
|
8
|
+
|
9
|
+
help = <<HELP
|
10
|
+
RBGLox v#{RBGLox::VERSION}
|
11
|
+
|
12
|
+
usage: rbglox [options]
|
13
|
+
|
14
|
+
Examples:
|
15
|
+
rbglox --init
|
16
|
+
rbglox --model=teapot
|
17
|
+
rbglox --title="My GLSL Demo"
|
18
|
+
|
19
|
+
Models:
|
20
|
+
quad, cube, teapot
|
21
|
+
|
22
|
+
Options:
|
23
|
+
HELP
|
24
|
+
|
25
|
+
options =
|
26
|
+
{
|
27
|
+
'model' => 'teapot',
|
28
|
+
'title' => "RBGLox v#{RBGLox::VERSION}"
|
29
|
+
}
|
30
|
+
opts = OptionParser.new do |opts|
|
31
|
+
opts.banner = help
|
32
|
+
|
33
|
+
opts.on('--init', 'create an empty project in the current directory') do
|
34
|
+
options['init'] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on('--model [model]', 'specify sample model') do |model|
|
38
|
+
if ['quad', 'cube', 'box', 'teapot'].include? model
|
39
|
+
options['model'] = model
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on('--title [title]', 'specify window title') do |title|
|
44
|
+
options['title'] = title
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on('--version', 'show version information') do
|
48
|
+
puts RBGLox::VERSION
|
49
|
+
exit 0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
opts.parse!
|
55
|
+
rescue OptionParser::InvalidOption => e
|
56
|
+
puts e.message
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def init(src, dst)
|
61
|
+
puts 'Copying shader ...'
|
62
|
+
File.copy(File.join(src, 'res/shader.glsl'), File.join(dst, 'shader.glsl'))
|
63
|
+
puts 'Copying texture ...'
|
64
|
+
File.copy(File.join(src, 'res/texture.tga'), File.join(dst, 'texture1.tga'))
|
65
|
+
puts 'Now run `rbglox` and enjoy :)'
|
66
|
+
0
|
67
|
+
end
|
68
|
+
|
69
|
+
exit init(File.dirname(File.dirname(__FILE__)), Dir.getwd) unless options['init'].nil?
|
70
|
+
|
71
|
+
unless File.exists?(File.join(Dir.getwd, 'shader.glsl'))
|
72
|
+
puts 'Error. No `shader.glsl` found in the current directory.'
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
|
76
|
+
unless File.exists?(File.join(Dir.getwd, 'texture1.tga'))
|
77
|
+
puts 'Warning. No `texture1.tga` found in the current directory.'
|
78
|
+
end
|
79
|
+
|
80
|
+
ShaderApp.new do |app|
|
81
|
+
app.title = options['title']
|
82
|
+
app.model = options['model']
|
83
|
+
app.watch = Dir.getwd
|
84
|
+
app.exec
|
85
|
+
end
|
data/lib/rbglox.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'gl'
|
2
|
+
require 'glu'
|
3
|
+
require 'glut'
|
4
|
+
require 'glfw'
|
5
|
+
require 'directory_watcher'
|
6
|
+
|
7
|
+
module RBGLox
|
8
|
+
class RBGLoxException < StandardError; end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rbglox/version'
|
12
|
+
require 'rbglox/window'
|
13
|
+
require 'rbglox/resource'
|
14
|
+
require 'rbglox/texture'
|
15
|
+
require 'rbglox/shader'
|
16
|
+
require 'rbglox/mesh'
|
17
|
+
require 'rbglox/meshquad'
|
18
|
+
require 'rbglox/meshcube'
|
19
|
+
require 'rbglox/app'
|
20
|
+
|
21
|
+
class ShaderApp < RBGLox::App
|
22
|
+
attr_accessor :model
|
23
|
+
|
24
|
+
def init
|
25
|
+
@textures = []
|
26
|
+
(1..4).each do |i|
|
27
|
+
filename = File.join watch, "texture#{i}.tga"
|
28
|
+
@textures << RBGLox::Texture.new(filename) if File.exists? filename
|
29
|
+
end
|
30
|
+
|
31
|
+
@shader = RBGLox::Shader.new File.join watch, "shader.glsl"
|
32
|
+
|
33
|
+
@z = -6.0
|
34
|
+
if model == 'quad'
|
35
|
+
@model = RBGLox::MeshQuad.new
|
36
|
+
elsif ['cube', 'box'].include? model
|
37
|
+
@model = RBGLox::MeshCube.new
|
38
|
+
else
|
39
|
+
@model = nil
|
40
|
+
@z = -30.0
|
41
|
+
end
|
42
|
+
|
43
|
+
@lastX = 0
|
44
|
+
@lastY = 0
|
45
|
+
@lastM = 0
|
46
|
+
|
47
|
+
@rotX = 0.0
|
48
|
+
@rotY = 0.0
|
49
|
+
@rotZ = 0.0
|
50
|
+
end
|
51
|
+
|
52
|
+
def update
|
53
|
+
currM = mouse_wheel?
|
54
|
+
|
55
|
+
if currM != 0
|
56
|
+
@z -= (@lastM - currM)
|
57
|
+
@lastM = currM
|
58
|
+
end
|
59
|
+
|
60
|
+
if mouse_left?
|
61
|
+
currX, currY = mouse_pos?
|
62
|
+
|
63
|
+
if @lastX > 0 and @lastY > 0
|
64
|
+
@rotX += (currY - @lastY)
|
65
|
+
@rotY += (currX - @lastX)
|
66
|
+
end
|
67
|
+
|
68
|
+
@lastX = currX
|
69
|
+
@lastY = currY
|
70
|
+
else
|
71
|
+
@lastX = 0
|
72
|
+
@lastY = 0
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def draw
|
78
|
+
glTranslatef(0,0, @z)
|
79
|
+
glRotatef(@rotX, 1.0, 0.0, 0.0)
|
80
|
+
glRotatef(@rotY, 0.0, 1.0, 0.0)
|
81
|
+
glRotatef(@rotZ, 0.0, 0.0, 1.0)
|
82
|
+
|
83
|
+
@textures.each_with_index do |texture, i|
|
84
|
+
texture.bind i
|
85
|
+
end
|
86
|
+
|
87
|
+
@shader.bind
|
88
|
+
@shader['time'] = time.to_f
|
89
|
+
|
90
|
+
if @model.nil?
|
91
|
+
glutSolidTeapot(8.0)
|
92
|
+
else
|
93
|
+
@model.draw
|
94
|
+
end
|
95
|
+
|
96
|
+
@shader.release
|
97
|
+
|
98
|
+
@textures.each_with_index do |texture, i|
|
99
|
+
texture.release i
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def shutdown
|
104
|
+
@textures.each do |texture|
|
105
|
+
texture.free
|
106
|
+
end
|
107
|
+
@shader.free
|
108
|
+
@model.free unless @model.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
def reload(event)
|
112
|
+
if event.type == :modified
|
113
|
+
puts "reloading #{event.path} ..."
|
114
|
+
if event.path =~ /\.glsl$/i
|
115
|
+
@shader.reload
|
116
|
+
elsif event.path =~ /\.tga$/i
|
117
|
+
@textures.each_with_index do |texture, i|
|
118
|
+
if texture.filename == event.path
|
119
|
+
texture.reload i
|
120
|
+
break
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/rbglox/app.rb
ADDED
data/lib/rbglox/mesh.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Semi-abstract Mesh Class
|
2
|
+
class RBGLox::Mesh < RBGLox::Resource
|
3
|
+
include Gl
|
4
|
+
|
5
|
+
# Constructor
|
6
|
+
def initialize(verts, texs, norms, tris)
|
7
|
+
@id = glGenLists 1
|
8
|
+
|
9
|
+
glNewList id, GL_COMPILE
|
10
|
+
glPushClientAttrib GL_CLIENT_VERTEX_ARRAY_BIT
|
11
|
+
glEnableClientState GL_VERTEX_ARRAY
|
12
|
+
glEnableClientState GL_TEXTURE_COORD_ARRAY
|
13
|
+
glEnableClientState GL_NORMAL_ARRAY
|
14
|
+
glVertexPointer 3, GL_FLOAT, 0, verts
|
15
|
+
glNormalPointer GL_FLOAT, 0, norms
|
16
|
+
glTexCoordPointer 2, GL_FLOAT, 0, texs
|
17
|
+
glDrawElements GL_TRIANGLES, tris.size, GL_UNSIGNED_INT, tris
|
18
|
+
glPopClientAttrib
|
19
|
+
glEndList
|
20
|
+
end
|
21
|
+
|
22
|
+
# Draw the mesh by calling the internal display list
|
23
|
+
def draw
|
24
|
+
glCallList id
|
25
|
+
end
|
26
|
+
|
27
|
+
# Reload the mesh
|
28
|
+
def reload
|
29
|
+
# do nothing
|
30
|
+
end
|
31
|
+
|
32
|
+
# Free the mesh by destroying the internal display list
|
33
|
+
def free
|
34
|
+
glDeleteLists id, 1
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# Cube Mesh Class
|
2
|
+
class RBGLox::MeshCube < RBGLox::Mesh
|
3
|
+
# Constructor
|
4
|
+
def initialize(x=1.0, y=1.0, z=1.0, tx=0.0, ty=0.0, tz=0.0)
|
5
|
+
verts = [
|
6
|
+
-x + tx, -y + ty, -z + tz,
|
7
|
+
x + tx, -y + ty, -z + tz,
|
8
|
+
x + tx, y + ty, -z + tz,
|
9
|
+
-x + tx, y + ty, -z + tz,
|
10
|
+
-x + tx, -y + ty, z + tz,
|
11
|
+
-x + tx, y + ty, z + tz,
|
12
|
+
x + tx, y + ty, z + tz,
|
13
|
+
x + tx, -y + ty, z + tz,
|
14
|
+
-x + tx, -y + ty, -z + tz,
|
15
|
+
-x + tx, y + ty, -z + tz,
|
16
|
+
-x + tx, y + ty, z + tz,
|
17
|
+
-x + tx, -y + ty, z + tz,
|
18
|
+
x + tx, -y + ty, -z + tz,
|
19
|
+
x + tx, -y + ty, z + tz,
|
20
|
+
x + tx, y + ty, z + tz,
|
21
|
+
x + tx, y + ty, -z + tz,
|
22
|
+
-x + tx, y + ty, -z + tz,
|
23
|
+
x + tx, y + ty, -z + tz,
|
24
|
+
x + tx, y + ty, z + tz,
|
25
|
+
-x + tx, y + ty, z + tz,
|
26
|
+
-x + tx, -y + ty, -z + tz,
|
27
|
+
-x + tx, -y + ty, z + tz,
|
28
|
+
x + tx, -y + ty, z + tz,
|
29
|
+
x + tx, -y + ty, -z + tz]
|
30
|
+
|
31
|
+
norms = [
|
32
|
+
0, 0, -1,
|
33
|
+
0, 0, -1,
|
34
|
+
0, 0, -1,
|
35
|
+
0, 0, -1,
|
36
|
+
0, 0, 1,
|
37
|
+
0, 0, 1,
|
38
|
+
0, 0, 1,
|
39
|
+
0, 0, 1,
|
40
|
+
-1, 0, 0,
|
41
|
+
-1, 0, 0,
|
42
|
+
-1, 0, 0,
|
43
|
+
-1, 0, 0,
|
44
|
+
1, 0, 0,
|
45
|
+
1, 0, 0,
|
46
|
+
1, 0, 0,
|
47
|
+
1, 0, 0,
|
48
|
+
0, 1, 0,
|
49
|
+
0, 1, 0,
|
50
|
+
0, 1, 0,
|
51
|
+
0, 1, 0,
|
52
|
+
0, -1, 0,
|
53
|
+
0, -1, 0,
|
54
|
+
0, -1, 0,
|
55
|
+
0, -1, 0 ]
|
56
|
+
|
57
|
+
texs = [
|
58
|
+
0, 0, # 0
|
59
|
+
1, 0, # 1
|
60
|
+
1, 1, # 2
|
61
|
+
0, 1, # 3
|
62
|
+
1, 0, # 4
|
63
|
+
1, 1, # 5
|
64
|
+
0, 1, # 6
|
65
|
+
0, 0, # 7
|
66
|
+
1, 0, # 8
|
67
|
+
1, 1, # 9
|
68
|
+
0, 1, # 10
|
69
|
+
0, 0, # 11
|
70
|
+
0, 0, # 12
|
71
|
+
1, 0, # 13
|
72
|
+
1, 1, # 14
|
73
|
+
0, 1, # 15
|
74
|
+
0, 0, # 16
|
75
|
+
1, 0, # 17
|
76
|
+
1, 1, # 18
|
77
|
+
0, 1, # 19
|
78
|
+
0, 1, # 20
|
79
|
+
0, 0, # 21
|
80
|
+
1, 0, # 22
|
81
|
+
1, 1 ] # 23
|
82
|
+
|
83
|
+
tris = [
|
84
|
+
0, 2, 1,
|
85
|
+
0, 3, 2,
|
86
|
+
4, 6, 5,
|
87
|
+
4, 7, 6,
|
88
|
+
8, 10, 9,
|
89
|
+
8, 11, 10,
|
90
|
+
12, 14, 13,
|
91
|
+
12, 15, 14,
|
92
|
+
16, 18, 17,
|
93
|
+
16, 19, 18,
|
94
|
+
20, 22, 21,
|
95
|
+
20, 23, 22 ]
|
96
|
+
|
97
|
+
super verts, texs, norms, tris
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Quad Mesh Class
|
2
|
+
class RBGLox::MeshQuad < RBGLox::Mesh
|
3
|
+
# Constructor
|
4
|
+
def initialize(x=1.0, y=1.0)
|
5
|
+
verts = [
|
6
|
+
-x, -y, 0.0,
|
7
|
+
x, -y, 0.0,
|
8
|
+
x, y, 0.0,
|
9
|
+
-x, y, 0.0 ]
|
10
|
+
|
11
|
+
texs = [
|
12
|
+
0.0, 0.0,
|
13
|
+
1.0, 0.0,
|
14
|
+
1.0, 1.0,
|
15
|
+
0.0, 1.0 ]
|
16
|
+
|
17
|
+
norms = [
|
18
|
+
0.0, 0.0, 1.0,
|
19
|
+
0.0, 0.0, 1.0,
|
20
|
+
0.0, 0.0, 1.0,
|
21
|
+
0.0, 0.0, 1.0 ]
|
22
|
+
|
23
|
+
tris = [
|
24
|
+
3, 2, 1,
|
25
|
+
3, 1, 0 ]
|
26
|
+
|
27
|
+
super verts, texs, norms, tris
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# GLSL Shader Class
|
2
|
+
class RBGLox::Shader < RBGLox::Resource
|
3
|
+
include Gl
|
4
|
+
|
5
|
+
attr_reader :filename, :vertex, :fragment, :uniforms
|
6
|
+
|
7
|
+
# Constructor
|
8
|
+
def initialize(filename)
|
9
|
+
@filename = filename
|
10
|
+
@id = glCreateProgram
|
11
|
+
|
12
|
+
@vertex = glCreateShader GL_VERTEX_SHADER
|
13
|
+
glAttachShader id, vertex
|
14
|
+
|
15
|
+
@fragment = glCreateShader GL_FRAGMENT_SHADER
|
16
|
+
glAttachShader id, fragment
|
17
|
+
|
18
|
+
@uniforms = []
|
19
|
+
|
20
|
+
reload
|
21
|
+
end
|
22
|
+
|
23
|
+
# Set internal GLSL uniforms
|
24
|
+
def []=(name, value)
|
25
|
+
loc = glGetUniformLocation id, name
|
26
|
+
if value.is_a? Float
|
27
|
+
glUniform1f loc, value
|
28
|
+
elsif value.is_a? Integer
|
29
|
+
glUniform1i loc, value
|
30
|
+
elsif value.is_a? Array
|
31
|
+
l = value.size
|
32
|
+
if l == 2
|
33
|
+
glUniform2fv loc, value
|
34
|
+
elsif l == 3:
|
35
|
+
glUniform3fv loc, value
|
36
|
+
elsif l == 4:
|
37
|
+
glUniform4fv loc, value
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise TypeError.new('Uniform type not supported')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Bind the Shader
|
45
|
+
def bind
|
46
|
+
glUseProgram id
|
47
|
+
|
48
|
+
uniforms.each do |k, v|
|
49
|
+
self[k] = v
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Release the Shader
|
54
|
+
def release
|
55
|
+
glUseProgram 0
|
56
|
+
end
|
57
|
+
|
58
|
+
# Reload the Shader
|
59
|
+
def reload
|
60
|
+
content = File.read filename
|
61
|
+
vert, frag, unis = parse content
|
62
|
+
|
63
|
+
glShaderSource vertex, vert
|
64
|
+
glCompileShader vertex
|
65
|
+
log = glGetShaderInfoLog vertex
|
66
|
+
puts log
|
67
|
+
|
68
|
+
return if log =~ /error/i
|
69
|
+
|
70
|
+
glShaderSource fragment, frag
|
71
|
+
glCompileShader fragment
|
72
|
+
log = glGetShaderInfoLog fragment
|
73
|
+
puts log
|
74
|
+
|
75
|
+
return if log =~ /error/i
|
76
|
+
|
77
|
+
glLinkProgram id
|
78
|
+
log = glGetProgramInfoLog id
|
79
|
+
puts log
|
80
|
+
|
81
|
+
return if log =~ /error/i
|
82
|
+
|
83
|
+
@uniforms = unis
|
84
|
+
end
|
85
|
+
|
86
|
+
# Free the Shader
|
87
|
+
def free
|
88
|
+
glDetachShader id, vertex
|
89
|
+
glDeleteShader vertex
|
90
|
+
|
91
|
+
glDetachShader id, fragment
|
92
|
+
glDeleteShader fragment
|
93
|
+
|
94
|
+
glDeleteProgram id
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
# Parse the Shader file and extract the Vertex and Fragment shaders
|
100
|
+
def parse(content)
|
101
|
+
source = []
|
102
|
+
|
103
|
+
matches = content.scan(/\[(vertex|fragment|uniforms)\]\s?(.*?\s?)\s?\[end\]/m)
|
104
|
+
matches.each do |m|
|
105
|
+
if ["vertex", "fragment"].include?(m[0])
|
106
|
+
source.push(m[1])
|
107
|
+
elsif m[0] == "uniforms"
|
108
|
+
source.push(YAML.load(m[1]))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
source
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Texture Class
|
2
|
+
class RBGLox::Texture < RBGLox::Resource
|
3
|
+
include Glfw
|
4
|
+
include Gl
|
5
|
+
|
6
|
+
attr_accessor :filename, :mipmaps
|
7
|
+
|
8
|
+
# Constructor
|
9
|
+
def initialize(filename, mipmaps=false)
|
10
|
+
@filename = filename
|
11
|
+
@mipmaps = mipmaps
|
12
|
+
@id = glGenTextures(1)[0]
|
13
|
+
|
14
|
+
reload
|
15
|
+
end
|
16
|
+
|
17
|
+
# Bind the Texture
|
18
|
+
def bind(unit=0)
|
19
|
+
glActiveTexture(GL_TEXTURE0 + unit)
|
20
|
+
glBindTexture GL_TEXTURE_2D, id
|
21
|
+
end
|
22
|
+
|
23
|
+
# Release the Texture
|
24
|
+
def release(unit=0)
|
25
|
+
glActiveTexture(GL_TEXTURE0 + unit)
|
26
|
+
glBindTexture GL_TEXTURE_2D, 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# Reload the Texture
|
30
|
+
def reload(unit=0)
|
31
|
+
bind unit
|
32
|
+
|
33
|
+
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
|
34
|
+
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
|
35
|
+
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
|
36
|
+
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
|
37
|
+
|
38
|
+
if mipmaps:
|
39
|
+
glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST
|
40
|
+
glfwLoadTexture2D filename, GLFW_BUILD_MIPMAPS_BIT
|
41
|
+
else
|
42
|
+
glfwLoadTexture2D filename, 0
|
43
|
+
end
|
44
|
+
|
45
|
+
release unit
|
46
|
+
end
|
47
|
+
|
48
|
+
# Free the Texture
|
49
|
+
def free
|
50
|
+
glDeleteTextures [id]
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# Semi-abstract Window class
|
2
|
+
class RBGLox::Window
|
3
|
+
include Glfw
|
4
|
+
include Gl
|
5
|
+
include Glu
|
6
|
+
include Glut
|
7
|
+
|
8
|
+
attr_accessor :title, :width, :height, :multisample, :vsync, :watch
|
9
|
+
|
10
|
+
# Constructor
|
11
|
+
def initialize
|
12
|
+
@title = 'rbGLox'
|
13
|
+
@width = 640
|
14
|
+
@height= 480
|
15
|
+
@multisample = 0
|
16
|
+
@vsync = 0
|
17
|
+
@watch = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Closes the currently active open window
|
21
|
+
def close
|
22
|
+
glfwCloseWindow
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns TRUE if the given key is PRESSED, otherwise FALSE
|
26
|
+
def key?(key)
|
27
|
+
glfwGetKey(key) == GLFW_PRESS
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns TRUE if the given mouse button is PRESSED, otherwise FALSE
|
31
|
+
def mouse?(button = GLFW_MOUSE_BUTTON_LEFT)
|
32
|
+
glfwGetMouseButton(button) == GLFW_PRESS
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return TRUE if the left mouse button is PRESSED, otherwise FALSE
|
36
|
+
def mouse_left?
|
37
|
+
mouse?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return TRUE if the right mouse button is PRESSED, otherwise FALSE
|
41
|
+
def mouse_right?
|
42
|
+
mouse? GLFW_MOUSE_BUTTON_RIGHT
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the current mouse position (tuple)
|
46
|
+
def mouse_pos?
|
47
|
+
glfwGetMousePos
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the current mouse wheel delta position
|
51
|
+
def mouse_wheel?
|
52
|
+
glfwGetMouseWheel
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the current tick count
|
56
|
+
def time
|
57
|
+
glfwGetTime
|
58
|
+
end
|
59
|
+
|
60
|
+
# Opens the window and fires up the event loop
|
61
|
+
def exec
|
62
|
+
glutInit
|
63
|
+
|
64
|
+
glfwOpenWindowHint GLFW_WINDOW_NO_RESIZE, true
|
65
|
+
#glfwOpenWindowHint GLFW_FSAA_SAMPLE, multisample
|
66
|
+
|
67
|
+
glfwOpenWindow width, height, 0, 0, 0, 0, 32, 0, GLFW_WINDOW
|
68
|
+
|
69
|
+
glfwSetWindowPos 0, 0
|
70
|
+
glfwSetWindowTitle title
|
71
|
+
glfwEnable GLFW_KEY_REPEAT
|
72
|
+
glfwSwapInterval vsync
|
73
|
+
|
74
|
+
glfwSetWindowSizeCallback lambda { |w, h| resize(w, h) }
|
75
|
+
|
76
|
+
trap('INT') do
|
77
|
+
glfwCloseWindow
|
78
|
+
end
|
79
|
+
|
80
|
+
unless watch.nil?
|
81
|
+
puts "Watching #{watch} for changes ..."
|
82
|
+
dw = DirectoryWatcher.new watch, :glob => "**/*", :pre_load => true, :interval => 1
|
83
|
+
dw.add_observer do |*args|
|
84
|
+
args.each do |event|
|
85
|
+
reload event
|
86
|
+
end
|
87
|
+
end
|
88
|
+
dw.start
|
89
|
+
end
|
90
|
+
|
91
|
+
glClearColor 0.2, 0.2, 0.2, 1
|
92
|
+
glClearDepth 1.0
|
93
|
+
|
94
|
+
glEnable GL_DEPTH_TEST
|
95
|
+
glDepthFunc GL_LEQUAL
|
96
|
+
|
97
|
+
glShadeModel GL_SMOOTH
|
98
|
+
glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST
|
99
|
+
|
100
|
+
glEnable GL_TEXTURE_2D
|
101
|
+
glEnable GL_COLOR_MATERIAL
|
102
|
+
glEnable GL_NORMALIZE
|
103
|
+
|
104
|
+
puts 'init'
|
105
|
+
init
|
106
|
+
|
107
|
+
while true
|
108
|
+
break unless glfwGetWindowParam GLFW_OPENED
|
109
|
+
break if key? GLFW_KEY_ESC
|
110
|
+
|
111
|
+
update
|
112
|
+
|
113
|
+
begin_frame
|
114
|
+
draw
|
115
|
+
end_frame
|
116
|
+
end
|
117
|
+
|
118
|
+
unless watch.nil?
|
119
|
+
dw.stop
|
120
|
+
end
|
121
|
+
|
122
|
+
shutdown
|
123
|
+
puts 'shutdown'
|
124
|
+
end
|
125
|
+
|
126
|
+
# User defined initializations
|
127
|
+
def init
|
128
|
+
end
|
129
|
+
|
130
|
+
# User defined shutdown
|
131
|
+
def shutdown
|
132
|
+
end
|
133
|
+
|
134
|
+
# User defined window resize, sets up viewport and perspective projection
|
135
|
+
def resize(w, h)
|
136
|
+
glViewport 0, 0, w, h
|
137
|
+
|
138
|
+
glMatrixMode GL_PROJECTION
|
139
|
+
glLoadIdentity
|
140
|
+
|
141
|
+
gluPerspective 45.0, w.to_f/h.to_f, 0.1, 1000.0
|
142
|
+
|
143
|
+
glMatrixMode GL_MODELVIEW
|
144
|
+
glLoadIdentity
|
145
|
+
end
|
146
|
+
|
147
|
+
# User defined method called when entering a frame
|
148
|
+
def begin_frame
|
149
|
+
glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
|
150
|
+
glLoadIdentity
|
151
|
+
end
|
152
|
+
|
153
|
+
# User defined method called when leaving the frame
|
154
|
+
def end_frame
|
155
|
+
glfwSwapBuffers
|
156
|
+
end
|
157
|
+
|
158
|
+
# User defined draw method
|
159
|
+
def draw
|
160
|
+
raise NotImplementedError
|
161
|
+
end
|
162
|
+
|
163
|
+
# User defined update method
|
164
|
+
def update
|
165
|
+
# empty
|
166
|
+
end
|
167
|
+
|
168
|
+
# User defined reload event method
|
169
|
+
def reload(event)
|
170
|
+
# empty
|
171
|
+
end
|
172
|
+
end
|
data/res/shader.glsl
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
[vertex]
|
2
|
+
uniform float time;
|
3
|
+
|
4
|
+
void main()
|
5
|
+
{
|
6
|
+
gl_FrontColor = gl_Color;
|
7
|
+
gl_TexCoord[0] = gl_MultiTexCoord0;
|
8
|
+
gl_Position = ftransform();
|
9
|
+
}
|
10
|
+
[end]
|
11
|
+
|
12
|
+
[fragment]
|
13
|
+
uniform float time;
|
14
|
+
uniform float offset;
|
15
|
+
uniform vec2 discardOffset;
|
16
|
+
uniform sampler2D tex0;
|
17
|
+
uniform sampler2D tex1;
|
18
|
+
uniform sampler2D tex2;
|
19
|
+
uniform sampler2D tex3;
|
20
|
+
|
21
|
+
void main()
|
22
|
+
{
|
23
|
+
vec2 st = gl_TexCoord[0].st;
|
24
|
+
|
25
|
+
if(st.t < discardOffset[0] || st.s < discardOffset[1])
|
26
|
+
discard;
|
27
|
+
|
28
|
+
gl_FragColor = texture2D(tex0, st * offset);
|
29
|
+
}
|
30
|
+
[end]
|
31
|
+
|
32
|
+
[uniforms]
|
33
|
+
discardOffset: [0.1, 0.1]
|
34
|
+
offset: 0.3
|
35
|
+
[end]
|
data/res/texture.tga
ADDED
Binary file
|
data/test/test_rbglox.rb
ADDED
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbglox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Mihail Szabolcs
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-19 00:00:00 +03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: ruby-opengl
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 237
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 60
|
33
|
+
- 1
|
34
|
+
version: 0.60.1
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: ruby-glfw
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 57
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 9
|
49
|
+
- 1
|
50
|
+
version: 0.9.1
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: directory_watcher
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 7
|
62
|
+
segments:
|
63
|
+
- 1
|
64
|
+
- 4
|
65
|
+
- 0
|
66
|
+
version: 1.4.0
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
69
|
+
description: rbGLox is a small wrapper over the ruby-opengl, ruby-glfw.
|
70
|
+
email:
|
71
|
+
- szaby@szabster.net
|
72
|
+
executables:
|
73
|
+
- rbglox
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files:
|
77
|
+
- README.md
|
78
|
+
- LICENSE
|
79
|
+
files:
|
80
|
+
- lib/rbglox/window.rb
|
81
|
+
- lib/rbglox/texture.rb
|
82
|
+
- lib/rbglox/resource.rb
|
83
|
+
- lib/rbglox/app.rb
|
84
|
+
- lib/rbglox/mesh.rb
|
85
|
+
- lib/rbglox/meshcube.rb
|
86
|
+
- lib/rbglox/meshquad.rb
|
87
|
+
- lib/rbglox/shader.rb
|
88
|
+
- lib/rbglox/version.rb
|
89
|
+
- lib/rbglox.rb
|
90
|
+
- res/shader.glsl
|
91
|
+
- res/texture.tga
|
92
|
+
- README.md
|
93
|
+
- LICENSE
|
94
|
+
- test/test_rbglox.rb
|
95
|
+
- bin/rbglox
|
96
|
+
has_rdoc: true
|
97
|
+
homepage: http://github.com/icebreaker/rbglox
|
98
|
+
licenses: []
|
99
|
+
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options:
|
102
|
+
- --charset=UTF-8
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
version: "0"
|
123
|
+
requirements: []
|
124
|
+
|
125
|
+
rubyforge_project: rbglox
|
126
|
+
rubygems_version: 1.3.7
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: rbGLox is a small wrapper over the ruby-opengl, ruby-glfw family by abstracting and providing some high-level interfaces for things like "Textures", "GLSL Shaders", basic "Geometry" and others.
|
130
|
+
test_files:
|
131
|
+
- test/test_rbglox.rb
|