budgie 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d3516e5b17bc0fff22ffdbafb32895370fe69f5
4
+ data.tar.gz: 0abf1c7ebbd29c8695c91e5710be8230f9ec7734
5
+ SHA512:
6
+ metadata.gz: 3913769ac259337174a656ecf92d4aef3776d31468a24a31ba5aadca2d096f136116a3786b3ca70986da54cab32f88362909685db74ea57ee254f2e32642549c
7
+ data.tar.gz: e796383cb30668a77d792d6af97f0e245fe95c1fb59dd0365014c027da108d0f1cfeb8e678f5947adc948dbbe311824d3b69d9701c96207e8d4fd4f1ee479763
data/bin/budgie ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'budgie/application'
6
+ Budgie::Application.new ARGV.first
@@ -0,0 +1,293 @@
1
+ require 'ruby-prof'
2
+ require 'debugger'
3
+ require 'opengl'
4
+ require 'glu'
5
+ require 'glut'
6
+
7
+ require 'budgie/map.rb'
8
+ require 'budgie/scene.rb'
9
+ require 'budgie/camera.rb'
10
+ require 'budgie/palette.rb'
11
+ require 'budgie/settings.rb'
12
+ require 'budgie/store_map.rb'
13
+ require 'budgie/selection.rb'
14
+
15
+ module Budgie; class Application
16
+ include GL
17
+ include GLU
18
+ include GLUT
19
+ extend Forwardable
20
+
21
+ attr_reader :width, :height, :map, :camera, :palette, :selection
22
+
23
+ def_delegators :@camera, :forward, :backward, :left, :right, :up, :down
24
+
25
+ def initialize(filename, width = 800, height = 600)
26
+ usage unless filename
27
+
28
+ @filename = filename
29
+
30
+ glutInit
31
+ glutInitDisplayMode GLUT_RGB | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH
32
+ glutInitWindowSize width, height
33
+ glutInitWindowPosition width / 2, height / 2
34
+
35
+ @window = glutCreateWindow "ffxel"
36
+
37
+ glutIdleFunc :idle
38
+ glutMouseFunc :click
39
+ glutDisplayFunc :display
40
+ glutReshapeFunc :reshape
41
+ glutKeyboardFunc :press
42
+ glutKeyboardUpFunc :release
43
+ glutPassiveMotionFunc :mouse
44
+
45
+ glutSetKeyRepeat GLUT_KEY_REPEAT_OFF
46
+
47
+ reshape width, height
48
+
49
+ setup
50
+
51
+ glutMainLoop
52
+ end
53
+
54
+ def setup
55
+ @settings = Settings.new
56
+ @keyboard = {}
57
+ @mouse_x = @mouse_y = 0
58
+
59
+ @camera = Camera.new
60
+ @palette = Palette.new
61
+ @selection = Selection.new
62
+
63
+ @store_map = StoreMap.new @filename, @palette
64
+ @map = @store_map.load
65
+
66
+ @scene = Scene.new self
67
+ end
68
+
69
+ # Event: window size change
70
+ def reshape(width, height)
71
+ @width = width
72
+ @height = height
73
+
74
+ height = 1 if height == 0
75
+
76
+ glViewport 0, 0, width, height
77
+
78
+ glMatrixMode GL_PROJECTION
79
+ glLoadIdentity
80
+ gluPerspective 90.0, width.to_f / height.to_f, 0.001, 100.0
81
+ end
82
+
83
+ # Event: redraw
84
+ def display
85
+ @scene.display
86
+ glutSwapBuffers
87
+ end
88
+
89
+ # Event: no events
90
+ def idle
91
+ time = Time.now.to_f
92
+ @time = time unless @time
93
+ delta = time - @time
94
+ @time = time
95
+
96
+ update_window_title(delta)
97
+ update_camera_step(delta)
98
+
99
+ send_key_presses
100
+ update_selection_at @mouse_x, @mouse_y
101
+
102
+ glutPostRedisplay
103
+ end
104
+
105
+ # Event: key press
106
+ def press(key, x, y)
107
+ @keyboard[key.downcase] = true
108
+ end
109
+
110
+ # Event: key release
111
+ def release(key, x, y)
112
+ @keyboard[key.downcase] = false
113
+ if key == @settings.palette_key
114
+ if @scene.fixed?
115
+ @scene.release
116
+ else
117
+ @scene.fix
118
+ end
119
+ end
120
+ end
121
+
122
+ # Event: mouse move
123
+ def mouse(x, y)
124
+ @mouse_x = x
125
+ @mouse_y = y
126
+
127
+ send mouse_mode
128
+ end
129
+
130
+ # Event: mouse click
131
+ def click(button, state, x, y)
132
+ return unless state == GLUT_UP
133
+
134
+ update_selection_at x, y
135
+
136
+ if button == GLUT_LEFT_BUTTON && glutGetModifiers == GLUT_ACTIVE_SHIFT
137
+ @scene.replace
138
+ elsif button == GLUT_LEFT_BUTTON && glutGetModifiers == GLUT_ACTIVE_CTRL
139
+ @scene.remove
140
+ elsif button == GLUT_LEFT_BUTTON
141
+ @scene.place
142
+ elsif button == GLUT_RIGHT_BUTTON
143
+ update_selection_color_at x, y
144
+ end
145
+ end
146
+
147
+ # User action: exit application
148
+ def escape
149
+ @store_map.save @map
150
+ glutDestroyWindow @window
151
+ exit 0
152
+ end
153
+
154
+ # yields pixel color at (x, y) in window coordinates
155
+ def color_at(x, y, &block)
156
+ y = @height - y
157
+ rgb = glReadPixels x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE
158
+ r, g, b = rgb.unpack 'C*'
159
+ yield r, g, b
160
+ end
161
+
162
+ # saves (x, y, z) coordinates of the block under cursor
163
+ def update_selection_at(x, y)
164
+ @scene.picker
165
+ color_at x, y do |r, g, b|
166
+ @selection.from_color r, g, b
167
+ end
168
+ update_selection_normal_at x, y
169
+ end
170
+
171
+ # saves (x, y, z) normal of the block's face under cursor
172
+ def update_selection_normal_at(x, y)
173
+ return unless @selection.selected
174
+ @scene.normal_picker
175
+ color_at x, y do |r, g, b|
176
+ @selection.normal_from_color r, g, b
177
+ end
178
+ end
179
+
180
+ # saves (r, g, b) color of the pixel under cursor
181
+ def update_selection_color_at(x, y)
182
+ @scene.color_picker
183
+ color_at x, y do |r, g, b|
184
+ @selection.r = r
185
+ @selection.g = g
186
+ @selection.b = b
187
+ end
188
+ end
189
+
190
+ # smooth camera movement
191
+ def update_camera_step(delta)
192
+ @camera.step = 30 * delta
193
+ end
194
+
195
+ def send_key_presses
196
+ @keyboard.each do |key, pressed|
197
+ key = @settings.keymap[key]
198
+ send key if key && pressed
199
+ end
200
+ end
201
+
202
+ # draws default cursor
203
+ def free_mouse_mode
204
+ glutSetCursor GLUT_CURSOR_INHERIT
205
+ end
206
+
207
+ # hides cursor image
208
+ # centers cursor
209
+ # rotates camera
210
+ def centered_mouse_mode
211
+ glutSetCursor GLUT_CURSOR_NONE
212
+
213
+ center_x = @width / 2
214
+ center_y = @height / 2
215
+
216
+ dx = center_x - @mouse_x
217
+ dy = center_y - @mouse_y
218
+
219
+ return if dx == 0 && dy == 0
220
+
221
+ glutWarpPointer center_x, center_y
222
+
223
+ quarter_x = center_x / 2
224
+ quarter_y = center_y / 2
225
+
226
+ return if dx.abs > quarter_x || dy.abs > quarter_y
227
+
228
+ dx = 50.0 * dx / @width
229
+ dy = 50.0 * dy / @height
230
+
231
+ @camera.alpha += dx
232
+ @camera.beta += dy
233
+ end
234
+
235
+ def update_window_title(delta)
236
+ @delta = 0 unless @delta
237
+ @frames = 0 unless @frames
238
+
239
+ @delta += delta
240
+ @frames += 1
241
+
242
+ if @delta > 1
243
+ s = @selection
244
+ glutSetWindowTitle "@map.max: #{@map.max}; fps: #{@frames}; selection: #{s.new_x}, #{s.new_y}, #{s.new_z}"
245
+
246
+ @delta = 0
247
+ @frames = 0
248
+ end
249
+ end
250
+
251
+ def mouse_mode
252
+ if @keyboard[@settings.free_mouse_mode_key]
253
+ 'free_mouse_mode'
254
+ else
255
+ 'centered_mouse_mode'
256
+ end
257
+ end
258
+
259
+ def message
260
+ %{
261
+ Usage
262
+ -----
263
+
264
+ $ budgie model-file.png
265
+
266
+
267
+ Keyboard controls
268
+ -----------------
269
+
270
+ WASD horizontal movement
271
+ space move up
272
+ C move down
273
+ E toggle palette
274
+ F free mouse mode
275
+
276
+
277
+ Mouse controls
278
+ --------------
279
+
280
+ Left Click place a block
281
+ Right Click colorpicker
282
+ Shift + Left Click replace current block color
283
+ Control + Left Click remove block
284
+
285
+ }
286
+ end
287
+
288
+ def usage
289
+ puts message.gsub /^ {4}/, ''
290
+ exit 0
291
+ end
292
+
293
+ end; end
@@ -0,0 +1,38 @@
1
+ # Automatically creates array elements by calling
2
+ # the block passed to the constructor when user
3
+ # tries to access the non-existent element
4
+ module Budgie; class AutoArray < Array
5
+ def initialize(&block)
6
+ @block = block
7
+ super
8
+ end
9
+
10
+ def [](index)
11
+ value = super
12
+
13
+ if value.nil?
14
+ populate index
15
+ super
16
+ else
17
+ value
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def populate(index)
24
+ if index > size
25
+ set_upto index
26
+ else
27
+ set index
28
+ end
29
+ end
30
+
31
+ def set_upto(new_size)
32
+ size.upto(new_size) { |index| set index }
33
+ end
34
+
35
+ def set(index)
36
+ self[index] = @block.call(index)
37
+ end
38
+ end; end
@@ -0,0 +1,39 @@
1
+ module Budgie; class Camera
2
+ include Math
3
+
4
+ attr_accessor :x, :y, :z, :alpha, :beta, :step
5
+
6
+ def initialize
7
+ @x = @y = @z = @alpha = @beta = 0
8
+ @step = 0.1
9
+ end
10
+
11
+ def move(step, direction = 0)
12
+ @x += step * cos(PI * (90.0 + @alpha + direction) / 180.0)
13
+ @z += step * sin(PI * (90.0 + @alpha + direction) / 180.0)
14
+ end
15
+
16
+ def forward
17
+ move @step
18
+ end
19
+
20
+ def backward
21
+ move @step, 180
22
+ end
23
+
24
+ def left
25
+ move @step, 90
26
+ end
27
+
28
+ def right
29
+ move @step, -90
30
+ end
31
+
32
+ def up
33
+ @y += @step
34
+ end
35
+
36
+ def down
37
+ @y -= @step
38
+ end
39
+ end; end
@@ -0,0 +1,40 @@
1
+ # Updates map and map views by applying selection to them
2
+ module Budgie; class ChangeMap
3
+ def initialize(scene)
4
+ @map = scene.map
5
+ @palette = scene.palette
6
+ @draw_map = scene.draw_map
7
+ @selection = scene.selection
8
+ @draw_picker_map = scene.draw_picker_map
9
+ end
10
+
11
+ # Places a new block next to the selected one
12
+ def place
13
+ s = @selection
14
+ return unless s.selected
15
+
16
+ @map[s.new_x, s.new_y, s.new_z] = @palette.index(s.r, s.g, s.b)
17
+ @draw_map.update_partial s.new_x, s.new_y, s.new_z
18
+ @draw_picker_map.update_partial s.new_x, s.new_y, s.new_z
19
+ end
20
+
21
+ # Replaces selected block's color
22
+ def replace
23
+ s = @selection
24
+ return unless s.selected
25
+
26
+ @map[s.x, s.y, s.z] = @palette.index(s.r, s.g, s.b)
27
+ @draw_map.update_partial s.x, s.y, s.z
28
+ @draw_picker_map.update_partial s.x, s.y, s.z
29
+ end
30
+
31
+ # Remove selected block from the map
32
+ def remove
33
+ s = @selection
34
+ return unless s.selected
35
+
36
+ @map[s.x, s.y, s.z] = nil
37
+ @draw_map.update_partial s.x, s.y, s.z
38
+ @draw_picker_map.update_partial s.x, s.y, s.z
39
+ end
40
+ end; end
@@ -0,0 +1,42 @@
1
+ require 'opengl'
2
+
3
+ module Budgie; class CheckerTexture
4
+ include GL
5
+
6
+ def initialize
7
+ @id = (glGenTextures 1).first
8
+ bind
9
+
10
+ data = [
11
+ [0xee, 0xee, 0xee], [0xee, 0xee, 0xee], [0xff, 0xff, 0xff], [0xff, 0xff, 0xff],
12
+ [0xee, 0xee, 0xee], [0xee, 0xee, 0xee], [0xff, 0xff, 0xff], [0xff, 0xff, 0xff],
13
+ [0xff, 0xff, 0xff], [0xff, 0xff, 0xff], [0xee, 0xee, 0xee], [0xee, 0xee, 0xee],
14
+ [0xff, 0xff, 0xff], [0xff, 0xff, 0xff], [0xee, 0xee, 0xee], [0xee, 0xee, 0xee]
15
+ ]
16
+
17
+ data = data.flatten.pack 'C*'
18
+
19
+ glTexImage2D GL_TEXTURE_2D,
20
+ level = 0,
21
+ internal_format = 3,
22
+ width = 4,
23
+ height = 4,
24
+ border = 0,
25
+ format = GL_RGB,
26
+ type = GL_UNSIGNED_BYTE,
27
+ data
28
+
29
+ glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST
30
+ glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST
31
+
32
+ unbind
33
+ end
34
+
35
+ def bind
36
+ glBindTexture GL_TEXTURE_2D, @id
37
+ end
38
+
39
+ def unbind
40
+ glBindTexture GL_TEXTURE_2D, 0
41
+ end
42
+ end; end
@@ -0,0 +1,97 @@
1
+ require 'opengl'
2
+ require 'budgie/draw_cube'
3
+ require 'budgie/draw_picker_cube'
4
+
5
+ module Budgie; class Draw
6
+ include GL
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ @cube = DrawCube.new
11
+ @picker_cube = DrawPickerCube.new
12
+ end
13
+
14
+ def ortho(&block)
15
+ glMatrixMode GL_PROJECTION
16
+ glPushMatrix
17
+ glLoadIdentity
18
+ glOrtho 0, @app.width, 0, @app.height, -1, 1
19
+
20
+ glMatrixMode GL_MODELVIEW
21
+ glPushMatrix
22
+ glLoadIdentity
23
+
24
+ yield
25
+
26
+ glMatrixMode GL_PROJECTION
27
+ glPopMatrix
28
+
29
+ glMatrixMode GL_MODELVIEW
30
+ glPopMatrix
31
+ end
32
+
33
+ def crosshair_with_outline
34
+ glColor3ub 0, 0, 0
35
+ crosshair 12, 8
36
+ glColor3ub 0xff, 0xff, 0xff
37
+ crosshair
38
+ end
39
+
40
+ def crosshair(size = 10, width = 4)
41
+ glLineWidth width
42
+ cx = @app.width / 2
43
+ cy = @app.height / 2
44
+
45
+ glBegin GL_LINES
46
+ glVertex2f cx - size, cy
47
+ glVertex2f cx + size, cy
48
+
49
+ glVertex2f cx, cy - size
50
+ glVertex2f cx, cy + size
51
+ glEnd
52
+ end
53
+
54
+ def guides
55
+ glLineWidth 10
56
+ glBegin GL_LINES
57
+
58
+ glColor3f 1, 0, 0
59
+ glVertex3f 0, 0, 0
60
+ glVertex3f 1, 0, 0
61
+
62
+ glColor3f 0, 1, 0
63
+ glVertex3f 0, 0, 0
64
+ glVertex3f 0, 1, 0
65
+
66
+ glColor3f 0, 0, 1
67
+ glVertex3f 0, 0, 0
68
+ glVertex3f 0, 0, 1
69
+
70
+ glEnd
71
+ end
72
+
73
+ def cube_at(x, y, z)
74
+ glPushMatrix
75
+ glTranslatef x, y, z
76
+ @cube.full
77
+ glPopMatrix
78
+ end
79
+
80
+ def picker_cube_at(x, y, z)
81
+ glPushMatrix
82
+ glTranslatef x, y, z
83
+ @picker_cube.full
84
+ glPopMatrix
85
+ end
86
+
87
+ def selection_cube_at(x, y, z)
88
+ glPolygonOffset -1, -1
89
+ cube_at x, y, z
90
+ end
91
+
92
+ def selection(selection)
93
+ return unless selection.selected
94
+ glColor3ub selection.r, selection.g, selection.b
95
+ selection_cube_at selection.x, selection.y, selection.z
96
+ end
97
+ end; end
@@ -0,0 +1,118 @@
1
+ require 'opengl'
2
+
3
+ module Budgie; class DrawCube
4
+ include GL
5
+
6
+ def draw(&block)
7
+ glBegin GL_QUADS
8
+ yield
9
+ glEnd
10
+ end
11
+
12
+ def full
13
+ draw do
14
+ front
15
+ back
16
+ right
17
+ left
18
+ top
19
+ bottom
20
+ end
21
+ end
22
+
23
+ def front
24
+ glNormal3f 0, 0, 1
25
+
26
+ glTexCoord2f 0, 1
27
+ glVertex3f 0, 0, 1
28
+
29
+ glTexCoord2f 1, 1
30
+ glVertex3f 1, 0, 1
31
+
32
+ glTexCoord2f 1, 0
33
+ glVertex3f 1, 1, 1
34
+
35
+ glTexCoord2f 0, 0
36
+ glVertex3f 0, 1, 1
37
+ end
38
+
39
+ def back
40
+ glNormal3f 0, 0, -1
41
+
42
+ glTexCoord2f 0, 1
43
+ glVertex3f 0, 0, 0
44
+
45
+ glTexCoord2f 1, 1
46
+ glVertex3f 0, 1, 0
47
+
48
+ glTexCoord2f 1, 0
49
+ glVertex3f 1, 1, 0
50
+
51
+ glTexCoord2f 0, 0
52
+ glVertex3f 1, 0, 0
53
+ end
54
+
55
+ def top
56
+ glNormal3f 0, 1, 0
57
+
58
+ glTexCoord2f 0, 1
59
+ glVertex3f 0, 1, 0
60
+
61
+ glTexCoord2f 1, 1
62
+ glVertex3f 0, 1, 1
63
+
64
+ glTexCoord2f 1, 0
65
+ glVertex3f 1, 1, 1
66
+
67
+ glTexCoord2f 0, 0
68
+ glVertex3f 1, 1, 0
69
+ end
70
+
71
+ def bottom
72
+ glNormal3f 0, -1, 0
73
+
74
+ glTexCoord2f 1, 1
75
+ glVertex3f 0, 0, 0
76
+
77
+ glTexCoord2f 1, 0
78
+ glVertex3f 1, 0, 0
79
+
80
+ glTexCoord2f 0, 0
81
+ glVertex3f 1, 0, 1
82
+
83
+ glTexCoord2f 0, 1
84
+ glVertex3f 0, 0, 1
85
+ end
86
+
87
+ def right
88
+ glNormal3f 1, 0, 0
89
+
90
+ glTexCoord2f 1, 0
91
+ glVertex3f 1, 0, 0
92
+
93
+ glTexCoord2f 0, 0
94
+ glVertex3f 1, 1, 0
95
+
96
+ glTexCoord2f 0, 1
97
+ glVertex3f 1, 1, 1
98
+
99
+ glTexCoord2f 1, 1
100
+ glVertex3f 1, 0, 1
101
+ end
102
+
103
+ def left
104
+ glNormal3f -1, 0, 0
105
+
106
+ glTexCoord2f 0, 0
107
+ glVertex3f 0, 0, 0
108
+
109
+ glTexCoord2f 0, 1
110
+ glVertex3f 0, 0, 1
111
+
112
+ glTexCoord2f 1, 1
113
+ glVertex3f 0, 1, 1
114
+
115
+ glTexCoord2f 1, 0
116
+ glVertex3f 0, 1, 0
117
+ end
118
+ end; end
@@ -0,0 +1,14 @@
1
+ require 'budgie/draw_picker_map'
2
+
3
+ module Budgie; class DrawMap < DrawPickerMap
4
+ def initialize(map, palette)
5
+ @palette = palette
6
+ super map
7
+ end
8
+
9
+ def cube_color(x, y, z, index)
10
+ @palette.rgb(index) do |r, g, b|
11
+ glColor3ub r, g, b
12
+ end
13
+ end
14
+ end; end