rbglox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|