mittsu 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +18 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +1158 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -1
- data/LICENSE.txt +1 -1
- data/README.md +173 -7
- data/circle.yml +20 -0
- data/install-glfw-3.1.2.sh +14 -0
- data/lib/mittsu.rb +0 -2
- data/lib/mittsu/extras/image_utils.rb +59 -55
- data/lib/mittsu/renderers/glfw_window.rb +17 -2
- data/lib/mittsu/renderers/opengl_renderer.rb +1 -1
- data/lib/mittsu/renderers/shaders/shader_lib.rb +4 -4
- data/lib/mittsu/version.rb +1 -1
- data/mittsu.gemspec +11 -5
- metadata +53 -71
- data/.travis.yml +0 -3
- data/examples/01_-_Default1noCulling.png +0 -0
- data/examples/01_scene_example.rb +0 -14
- data/examples/02_box_mesh_example.rb +0 -30
- data/examples/02_sphere_mesh_example.rb +0 -30
- data/examples/03_complex_object_example.rb +0 -52
- data/examples/04_ambient_light_example.rb +0 -33
- data/examples/04_dir_light_example.rb +0 -36
- data/examples/04_hemi_light_example.rb +0 -30
- data/examples/04_point_light_example.rb +0 -50
- data/examples/04_spot_light_example.rb +0 -44
- data/examples/05_earth_example.rb +0 -42
- data/examples/05_earth_moon_example.rb +0 -46
- data/examples/05_texture_example.rb +0 -32
- data/examples/06_cube_texture_example.rb +0 -36
- data/examples/06_skybox_example.rb +0 -60
- data/examples/07_earth_normal_example.rb +0 -36
- data/examples/08_shadow_example.rb +0 -87
- data/examples/09_line_example.rb +0 -52
- data/examples/10_obj_loader_example.rb +0 -68
- data/examples/11_character_input_example.rb +0 -18
- data/examples/11_continuous_keyboard_input_example.rb +0 -35
- data/examples/11_keyboard_input_example.rb +0 -43
- data/examples/12_mouse_click_example.rb +0 -38
- data/examples/12_mouse_motion_example.rb +0 -35
- data/examples/12_mouse_scroll_example.rb +0 -36
- data/examples/12_orbit_zoom_example.rb +0 -68
- data/examples/13_joystick_example.rb +0 -80
- data/examples/cubemap/tron_bk.png +0 -0
- data/examples/cubemap/tron_dn.png +0 -0
- data/examples/cubemap/tron_ft.png +0 -0
- data/examples/cubemap/tron_lf.png +0 -0
- data/examples/cubemap/tron_rt.png +0 -0
- data/examples/cubemap/tron_up.png +0 -0
- data/examples/earth.png +0 -0
- data/examples/earth_normal.png +0 -0
- data/examples/example_helper.rb +0 -2
- data/examples/male-02-1noCulling.png +0 -0
- data/examples/male02.mtl +0 -54
- data/examples/male02.obj +0 -13888
- data/examples/moon.png +0 -0
- data/examples/orig_02_-_Defaul1noCulling.png +0 -0
- data/examples/texture.png +0 -0
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p353
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,27 @@
|
|
1
1
|
# Mittsu
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/mittsu) [](https://gemnasium.com/jellymann/mittsu) [](https://circleci.com/gh/jellymann/mittsu/tree/master) [](https://codeclimate.com/github/jellymann/mittsu/coverage) [](https://codeclimate.com/github/jellymann/mittsu)
|
4
4
|
|
5
|
-
|
5
|
+
3D Graphics Library for Ruby
|
6
|
+
|
7
|
+
Mittsu makes 3D graphics easier by providing an abstraction over OpenGL, and is based heavily off of [THREE.js](http://threejs.org). No more weird pointers and wondering about the difference between a VAO and a VBO (besides the letter). Simply think of something awesome and make it!
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
11
|
+
Install the prerequisites:
|
12
|
+
|
13
|
+
Mittsu depends on Ruby 2.x, OpenGL 3.3+, GLFW 3.1.x and ImageMagick 6.4.9+
|
14
|
+
|
15
|
+
```bash
|
16
|
+
# OSX
|
17
|
+
$ brew intall glfw3 imagemagick
|
18
|
+
|
19
|
+
# Ubuntu
|
20
|
+
$ sudo apt-get install libglfw3-dev libmagickwand-dev
|
21
|
+
```
|
22
|
+
|
23
|
+
**NOTE**: On Ubuntu, you may need to install `libgl1-mesa-dev` for the OpenGL dependency.
|
24
|
+
|
9
25
|
Add this line to your application's Gemfile:
|
10
26
|
|
11
27
|
```ruby
|
@@ -22,18 +38,168 @@ Or install it yourself as:
|
|
22
38
|
|
23
39
|
## Usage
|
24
40
|
|
25
|
-
|
41
|
+
### tl;dr
|
42
|
+
|
43
|
+
Copy-Paste and Run:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'mittsu'
|
47
|
+
|
48
|
+
SCREEN_WIDTH = 800
|
49
|
+
SCREEN_HEIGHT = 600
|
50
|
+
ASPECT = SCREEN_WIDTH.to_f / SCREEN_HEIGHT.to_f
|
26
51
|
|
27
|
-
|
52
|
+
renderer = Mittsu::OpenGLRenderer.new width: SCREEN_WIDTH, height: SCREEN_HEIGHT, title: 'Hello, World!'
|
53
|
+
|
54
|
+
scene = Mittsu::Scene.new
|
55
|
+
|
56
|
+
camera = Mittsu::PerspectiveCamera.new(75.0, ASPECT, 0.1, 1000.0)
|
57
|
+
camera.position.z = 5.0
|
58
|
+
|
59
|
+
box = Mittsu::Mesh.new(
|
60
|
+
Mittsu::BoxGeometry.new(1.0, 1.0, 1.0),
|
61
|
+
Mittsu::MeshBasicMaterial.new(color: 0x00ff00)
|
62
|
+
)
|
63
|
+
|
64
|
+
scene.add(box)
|
65
|
+
|
66
|
+
renderer.window.run do
|
67
|
+
box.rotation.x += 0.1
|
68
|
+
box.rotation.y += 0.1
|
69
|
+
|
70
|
+
renderer.render(scene, camera)
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### Step by Step
|
75
|
+
|
76
|
+
First, we need to require Mittsu in order to use it:
|
77
|
+
```ruby
|
78
|
+
require 'mittsu'
|
79
|
+
```
|
28
80
|
|
29
|
-
|
81
|
+
Then, we'll define some constants to help us with setting up our 3D environment:
|
82
|
+
```ruby
|
83
|
+
SCREEN_WIDTH = 800
|
84
|
+
SCREEN_HEIGHT = 600
|
85
|
+
ASPECT = SCREEN_WIDTH.to_f / SCREEN_HEIGHT.to_f
|
86
|
+
```
|
87
|
+
|
88
|
+
The aspect ratio will be used for setting up the camera later.
|
89
|
+
|
90
|
+
Once we have all that we can create the canvas we will use to draw our graphics onto. In Mittsu this is called a renderer. It provides a window and an OpenGL context:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
renderer = Mittsu::OpenGLRenderer.new width: SCREEN_WIDTH, height: SCREEN_HEIGHT, title: 'Hello, World!'
|
94
|
+
```
|
95
|
+
This will give us an 800x600 window with the title `Hello, World!`.
|
96
|
+
|
97
|
+
Now that we have our canvas, let's start setting up the scene we wish to draw onto it:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
scene = Mittsu::Scene.new
|
101
|
+
```
|
102
|
+
|
103
|
+
A scene is like a stage where all our 3D objects live and animate.
|
104
|
+
|
105
|
+
We can't draw a 3D scene without knowing where we're looking:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
camera = Mittsu::PerspectiveCamera.new(75.0, ASPECT, 0.1, 1000.0)
|
109
|
+
```
|
110
|
+
|
111
|
+
This camera has a 75° field-of-view (FOV), the aspect ratio of the window (which we defined earlier), and shows everything between a distance of 0.1 to 1000.0 away from the camera.
|
112
|
+
|
113
|
+
The camera starts off at the origin `[0,0,0]` and faces the negative Z-axis. We'll position it somewhere along the positive Z-axis so that it is looking at the center of the scene from a short distance:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
camera.position.z = 5.0
|
117
|
+
```
|
30
118
|
|
31
|
-
|
119
|
+
Our scene isn't going to be very exciting if there is nothing in it, so we'll create a box:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
box = Mittsu::Mesh.new(
|
123
|
+
Mittsu::BoxGeometry.new(1.0, 1.0, 1.0),
|
124
|
+
Mittsu::MeshBasicMaterial.new(color: 0x00ff00)
|
125
|
+
)
|
126
|
+
```
|
127
|
+
|
128
|
+
A `Mesh` in Mittsu is the combination of a `Geometry` (the shape of the object) and a `Material` (the "look" of the object). Here we've created a 1x1x1 box that is colored green.
|
129
|
+
|
130
|
+
Box in hand, we make it part of our scene:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
scene.add(box)
|
134
|
+
```
|
135
|
+
|
136
|
+
Here comes the fun part... the render loop!
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
renderer.window.run do
|
140
|
+
```
|
141
|
+
|
142
|
+
The given block is called every frame. This is where you can tell the renderer what scene to draw, and do any updates to the objects in your scene.
|
143
|
+
|
144
|
+
Just to make things a bit more interesting, we'll make the box rotate around its X and Y axes, so that it spins like crazy.
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
box.rotation.x += 0.1
|
148
|
+
box.rotation.y += 0.1
|
149
|
+
```
|
150
|
+
|
151
|
+
Last but not least, we tell the renderer to draw our scene this frame, which will tell the graphics processor to draw our green box with its updated rotation.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
renderer.render(scene, camera)
|
155
|
+
```
|
156
|
+
|
157
|
+
Easy peasy! :)
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
|
164
|
+
### More Resources
|
165
|
+
|
166
|
+
Mittsu follows a similar structure to THREE.js, so you can generally use [the same documentation](http://threejs.org/docs/) for a description of the various classes and how they work.
|
167
|
+
|
168
|
+
If you just want to see what Mittsu can do and how to do it, take a peek inside the `examples` folder.
|
169
|
+
|
170
|
+
## Where you can help
|
171
|
+
|
172
|
+
1. Testing!
|
173
|
+
|
174
|
+
Currently the only unit tests are for most of the maths library, otherwise the library is tested by running the examples and checking that they look correct.
|
175
|
+
|
176
|
+
2. Refactoring!
|
177
|
+
|
178
|
+
The code is unfortunately still a mess. Mittsu started out as a direct port of THREE.js, and JavaScript to Ruby is not an exact science.
|
179
|
+
|
180
|
+
3. Find Bugs!
|
181
|
+
|
182
|
+
Mittsu is still very young, and there are plenty of small bugs and glitches that need to be ironed out. If you find a bug, create an issue so we can track it and squash it.
|
183
|
+
|
184
|
+
4. Add all the features!
|
185
|
+
|
186
|
+
Some of the things I'd like to see ported from THREE.js include:
|
187
|
+
|
188
|
+
* Picking (clicking on 3D objects in a scene)
|
189
|
+
* Bone structure/animation (e.g. for character movements)
|
190
|
+
* Lens Flares! (for JJ Abrams)
|
191
|
+
* All the Extras and Helpers (who doesn't need extra help?)
|
192
|
+
|
193
|
+
5. Write documentation!
|
194
|
+
|
195
|
+
You can use the same docs as THREE.js for now, but I would like to provide Mittsu-specific documentation so devs don't have to keep replacing `new THREE.Thing()` with `Mittsu::Thing.new`.
|
32
196
|
|
33
197
|
## Contributing
|
34
198
|
|
35
|
-
1. Fork it ( https://github.com/
|
199
|
+
1. Fork it ( https://github.com/jellymann/mittsu/fork )
|
36
200
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
201
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
202
|
4. Push to the branch (`git push origin my-new-feature`)
|
39
203
|
5. Create a new Pull Request
|
204
|
+
|
205
|
+
Thank you for helping me help you help us all. ;)
|
data/circle.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
## Customize the test machine
|
2
|
+
machine:
|
3
|
+
|
4
|
+
# Version of ruby to use
|
5
|
+
ruby:
|
6
|
+
version:
|
7
|
+
2.0.0
|
8
|
+
|
9
|
+
## Customize dependencies
|
10
|
+
dependencies:
|
11
|
+
cache_directories:
|
12
|
+
- glfw-3.1.2
|
13
|
+
pre:
|
14
|
+
- sudo apt-get update; sudo apt-get install cmake xorg-dev libgl1-mesa-dev
|
15
|
+
- bash ./install-glfw-3.1.2.sh
|
16
|
+
|
17
|
+
test:
|
18
|
+
post:
|
19
|
+
- mkdir -p $CIRCLE_TEST_REPORTS/minitest/
|
20
|
+
- cp -r test/reports/*.xml $CIRCLE_TEST_REPORTS/minitest/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
set -x
|
2
|
+
set -e
|
3
|
+
if [ ! -e glfw-3.1.2/include/GLFW/glfw3.h ]; then
|
4
|
+
wget https://github.com/glfw/glfw/releases/download/3.1.2/glfw-3.1.2.zip
|
5
|
+
unzip glfw-3.1.2.zip;
|
6
|
+
fi
|
7
|
+
cd glfw-3.1.2
|
8
|
+
if [ ! -e src/libglfw3.so ]; then
|
9
|
+
cmake -D BUILD_SHARED_LIBS=ON .
|
10
|
+
make;
|
11
|
+
fi
|
12
|
+
if [ ! -e /usr/local/lib/libglfw.so ]; then
|
13
|
+
sudo make install;
|
14
|
+
fi
|
data/lib/mittsu.rb
CHANGED
@@ -1,80 +1,84 @@
|
|
1
1
|
module Mittsu
|
2
2
|
module ImageUtils
|
3
|
-
|
4
|
-
|
3
|
+
class << self
|
4
|
+
def load_texture(url, mapping = Texture::DEFAULT_MAPPING)
|
5
|
+
loader = ImageLoader.new
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
Texture.new(nil, mapping).tap do |texture|
|
8
|
+
image = loader.load(url, flip: true)
|
9
|
+
texture.image = image
|
10
|
+
texture.needs_update = true
|
10
11
|
|
11
|
-
|
12
|
+
texture.source_file = url
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
def load_texture_cube(array, mapping = Texture::DEFAULT_MAPPING)
|
17
|
+
images = HashArray.new
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
loader = ImageLoader.new
|
20
|
+
CubeTexture.new(images, mapping).tap do |texture|
|
21
|
+
loaded = 0
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
array.length.times do |i|
|
24
|
+
texture.images[i] = loader.load(array[i])
|
25
|
+
loaded += 1
|
26
|
+
if loaded == 6
|
27
|
+
texture.needs_update = true
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
30
|
-
end
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
def get_normal_map(image, depth)
|
34
|
+
# adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
# depth |= 1
|
37
|
+
#
|
38
|
+
# width = image.width
|
39
|
+
# height = image.height
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
# TODO: original version uses browser features ...
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
def generate_data_texture(width, height, color)
|
45
|
+
size = width * height
|
46
|
+
data = Array.new(3 * size) # Uint8Array
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
r = (color.r * 255).floor
|
49
|
+
g = (color.g * 255).floor
|
50
|
+
b = (color.b * 255).floor
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
size.times do |i|
|
53
|
+
data[i * 3] = r
|
54
|
+
data[i * 3 + 1] = g
|
55
|
+
data[i * 3 + 2] = b
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
texture = DataTexture.new(data, width, height, RGBFormat)
|
59
|
+
texture.needs_update = true
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
texture
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
[
|
65
|
-
a[1] * b[2] - a[2] * b[1],
|
66
|
-
a[2] * b[0] - a[0] * b[2],
|
67
|
-
a[0] * b[1] - a[1] * b[0]
|
68
|
-
]
|
69
|
-
end
|
64
|
+
private
|
70
65
|
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
def cross(a, b)
|
67
|
+
[
|
68
|
+
a[1] * b[2] - a[2] * b[1],
|
69
|
+
a[2] * b[0] - a[0] * b[2],
|
70
|
+
a[0] * b[1] - a[1] * b[0]
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
def subtract(a, b)
|
75
|
+
[a[0] - b[0], a[1] - b[1], a[2] - b[2]]
|
76
|
+
end
|
74
77
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
+
def normalize(a)
|
79
|
+
l = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])
|
80
|
+
[a[0] / l, a[1] / l, a[2] / l]
|
81
|
+
end
|
78
82
|
end
|
79
83
|
end
|
80
84
|
end
|
@@ -1,8 +1,20 @@
|
|
1
1
|
require 'opengl'
|
2
2
|
require 'glfw'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
GLFW_LIB_EXT = OpenGL.get_platform == :OPENGL_PLATFORM_MACOSX ? 'dylib' : 'so'
|
5
|
+
GLFW_LIB = begin
|
6
|
+
"lib#{`pkg-config --libs-only-l glfw3`.gsub(/^-l/, '').chomp.strip}.#{GLFW_LIB_EXT}"
|
7
|
+
rescue
|
8
|
+
"libglfw.#{GLFW_LIB_EXT}"
|
9
|
+
end
|
10
|
+
GLFW_LIB_PATH = begin
|
11
|
+
s = `pkg-config glfw3 --libs-only-L`.gsub(/^-L/, '').chomp.strip
|
12
|
+
s.empty? ? nil : s
|
13
|
+
rescue
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
GLFW.load_lib GLFW_LIB, GLFW_LIB_PATH
|
6
18
|
|
7
19
|
include GLFW
|
8
20
|
|
@@ -22,6 +34,9 @@ module Mittsu
|
|
22
34
|
|
23
35
|
@width, @height, @title = width, height, title
|
24
36
|
@handle = glfwCreateWindow(@width, @height, @title, nil, nil)
|
37
|
+
if @handle.null?
|
38
|
+
raise "Unable to create window."
|
39
|
+
end
|
25
40
|
glfwMakeContextCurrent @handle
|
26
41
|
glfwSwapInterval 1
|
27
42
|
|
@@ -21,7 +21,7 @@ module Mittsu
|
|
21
21
|
attr_accessor :auto_clear, :auto_clear_color, :auto_clear_depth, :auto_clear_stencil, :sort_objects, :gamma_factor, :gamma_input, :gamma_output, :shadow_map_enabled, :shadow_map_type, :shadow_map_cull_face, :shadow_map_debug, :shadow_map_cascade, :max_morph_targets, :max_morph_normals, :info, :pixel_ratio, :window, :width, :height, :state
|
22
22
|
|
23
23
|
def initialize(parameters = {})
|
24
|
-
puts "OpenGLRenderer #{REVISION}"
|
24
|
+
puts "OpenGLRenderer (Revision #{REVISION})"
|
25
25
|
|
26
26
|
@pixel_ratio = 1.0
|
27
27
|
|