hate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ # Hate 3d
2
+
3
+ A Ruby 3d OpenGL game library inspired by the Lua [Love](http://love2d.org/) project, a fun little 2d game engine.
4
+
5
+ The project name `hate` is a parody of the inspiration.
6
+
7
+ Other inspirational Ruby game projects worth checking out (and much, much more feature complete, albeit only 2d).
8
+
9
+ * [Rubygame](http://rubygame.org/)
10
+ * [Gosu](http://www.libgosu.org/)
11
+
12
+ ## Installation
13
+
14
+ gem install hate
15
+
16
+ ## Usage
17
+
18
+ Your game requires a `main.rb` file at the root of your game directory which `hate` will execute. There is an example game located in the example folder which shows how the basic methods of the system work. At the moment you must wrap all the methods in a module like so.
19
+
20
+ module Hate
21
+ module Game
22
+ # methods
23
+ end
24
+ end
25
+
26
+ ### Core Methods
27
+
28
+ These are predefined and overridable methods which the engine implements. Any logic you write within them will get execute by the engine.
29
+
30
+ __self.load__
31
+
32
+ Anything defined in here is initially loaded at system startup.
33
+
34
+ __self.update__
35
+
36
+ Anything in here gets called every second draw call. In theory physics and non draw frame game updates would go in here.
37
+
38
+ __self.draw__
39
+
40
+ Draw logic for all of the objects in your scene.
41
+
42
+ __self.keypressed(k)__
43
+
44
+ Any keys which have been pressed by the user as a byte character.
45
+
46
+ __self.mousepressed(x, y, button)__
47
+
48
+ The x, y position and button pressed for the mouse.
49
+
50
+ __self.mousemotion(x, y, xr, yr, state)__
51
+
52
+ The x, y position, x, y position at click, and button state of the mouse.
53
+
54
+ __self.quit__
55
+
56
+ The quit callback.
57
+
58
+ ## Support
59
+
60
+ Currently this has only been tested on OSX using MRI 1.8.7 and MRI 1.9.2. Unfortunately ffi-opengl under Rubinius and jRuby doesn't seem to be operational.
61
+
62
+ ## Known Issues
63
+
64
+ * Quit doesn't exit cleanly.
65
+ * The framerate slows down when the mouse is moved.
66
+ * The framerate isn't locked to a constant rate.
67
+ * The full system isn't currently implemented, and the engine is a continual work in progress.
68
+
69
+ ## Authors
70
+
71
+ Brian 'bojo' Jones <mojobojo@gmail.com>
72
+
73
+ ## License
74
+
75
+ The MIT License
76
+
77
+ Copyright (c) 2011 Brian Jones
78
+
79
+ Permission is hereby granted, free of charge, to any person obtaining a copy
80
+ of this software and associated documentation files (the "Software"), to deal
81
+ in the Software without restriction, including without limitation the rights
82
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
83
+ copies of the Software, and to permit persons to whom the Software is
84
+ furnished to do so, subject to the following conditions:
85
+
86
+ The above copyright notice and this permission notice shall be included in
87
+ all copies or substantial portions of the Software.
88
+
89
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
95
+ THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'jeweler'
4
+
5
+ Jeweler::Tasks.new do |gem|
6
+ gem.name = "hate"
7
+ gem.summary = %Q{An OpenGL 3d Ruby Engine}
8
+ gem.email = "mojobojo@gmail.com"
9
+ gem.homepage = "http://github.com/boj/hate"
10
+ gem.authors = ["Brian Jones"]
11
+ gem.version = "0.1.0"
12
+
13
+ gem.add_dependency('ffi-opengl', '>= 0.2.1')
14
+ gem.add_dependency('ruby-sdl-ffi', '>= 0.4')
15
+ end
16
+
17
+ Jeweler::GemcutterTasks.new
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'hate'
6
+
7
+ Hate::Core.run
@@ -0,0 +1,95 @@
1
+ module Hate
2
+ module Game
3
+ def self.load
4
+ puts "Welcome!"
5
+
6
+ @camera = Hate::Graphics::Manager.default_camera
7
+
8
+ #@square = Hate::Graphics::Shapes::Square.new(5.0)
9
+ #@square.translate(0.0, 0.0, -15.0)
10
+ #@square.color(0.0, 0.0, 1.0)
11
+ #@square.build
12
+ #Hate::Graphics::Manager.add_object(@square)
13
+
14
+ @cubes = []
15
+ base_cube = Hate::Graphics::Shapes::Cube.new(0.5)
16
+ 100.times do |i|
17
+ cube = base_cube.clone
18
+ cube.translate(-rand(10) + 5.0, -rand(10) + 5.0, -rand(20).to_f + -5.0)
19
+ cube.rotate((rand(360) + 1).to_f, rand, rand, rand)
20
+ cube.color(rand, rand, rand)
21
+ Hate::Graphics::Manager.add_object(cube)
22
+ @cubes << cube
23
+ end
24
+
25
+ ########################################
26
+ # Shader Lights
27
+ ########################################
28
+ v = Hate::Graphics::Shader::Vertex.new(File.dirname(__FILE__) + "/../lib/hate/graphics/shaders/lights/point.vertex")
29
+ f = Hate::Graphics::Shader::Fragment.new(File.dirname(__FILE__) + "/../lib/hate/graphics/shaders/lights/point.fragment")
30
+ @p = Hate::Graphics::Shader::Program.new
31
+ @p.attach(v.shader).attach(f.shader).compile
32
+ Hate::Graphics::Manager.add_shader(@p)
33
+
34
+ ########################################
35
+ # Hardware Lights
36
+ ########################################
37
+ #@light1 = Hate::Graphics::Light.new
38
+ #Hate::Graphics::Manager.add_light(@light1)
39
+
40
+ #@light2 = Hate::Graphics::Light.new([1.0, 0.0, 0.0, 1.0], [0.0, 1.0, 1.0, 1.0], [10.0, 10.0, 10.0, 0.0])
41
+ #Hate::Graphics::Manager.add_light(@light2)
42
+
43
+ @speed = 1.0
44
+ @angle = 0.0
45
+ end
46
+ def self.update
47
+
48
+ end
49
+ def self.draw
50
+ @cubes.each_with_index do |cube, i|
51
+ if i % 2 == 0
52
+ cube.rotate(cube.ra + rand, 1.0, 0.0, 0.0)
53
+ elsif i % 3 == 0
54
+ cube.rotate(cube.ra + rand, 0.0, 1.0, 0.0)
55
+ else
56
+ cube.rotate(cube.ra + rand, 0.0, 0.0, 1.0)
57
+ end
58
+ end
59
+ end
60
+ def self.keypressed(k)
61
+ puts "key: %i" % k
62
+ puts "camera: (%f, %f) - (%f, %f)" % [@camera.x, @camera.z, @camera.xl, @camera.zl]
63
+ case k
64
+ when 119
65
+ @camera.x += @camera.xl * @speed
66
+ @camera.z += @camera.zl * @speed
67
+ when 115
68
+ @camera.x -= @camera.xl * @speed
69
+ @camera.z -= @camera.zl * @speed
70
+ when 97
71
+ @angle -= 0.01
72
+ @camera.xl = Math.sin(@angle)
73
+ @camera.zl = -Math.cos(@angle)
74
+ when 100
75
+ @angle += 0.01
76
+ @camera.xl = Math.sin(@angle)
77
+ @camera.zl = -Math.cos(@angle)
78
+ when 27 # Escape
79
+ Hate::Game.quit
80
+ end
81
+ end
82
+ def self.mousepressed(x, y, button)
83
+ puts "%i - %i" % [x, y]
84
+ end
85
+ def self.mousemotion(x, y, xr, yr, state)
86
+ puts "(%i, %i) - (%i, %i), state: %i" % [x, y, xr, yr, state]
87
+ end
88
+ def self.quit
89
+ # Until I find a better solution (events), this is one of the rare times we call Core directly.
90
+ # This doesn't kill the process nicely at the moment.
91
+ Hate::Core.quit
92
+ puts "Game Over"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,16 @@
1
+ $: << APP_PATH = File.dirname(File.expand_path(__FILE__))
2
+ Dir["#{APP_PATH}/**/lib"].each { |p| $: << p }
3
+
4
+ module Hate
5
+ VERSION = "0.0.1"
6
+
7
+ # Files are loaded on demand.
8
+ autoload :Audio, APP_PATH + '/hate/audio.rb'
9
+ autoload :Core, APP_PATH + '/hate/core.rb'
10
+ autoload :Game, APP_PATH + '/hate/game.rb'
11
+ autoload :Graphics, APP_PATH + '/hate/graphics.rb'
12
+ autoload :Input, APP_PATH + '/hate/input.rb'
13
+ autoload :Network, APP_PATH + '/hate/network.rb'
14
+ autoload :Physics, APP_PATH + '/hate/physics.rb'
15
+ autoload :System, APP_PATH + '/hate/system.rb'
16
+ end
File without changes
@@ -0,0 +1,123 @@
1
+ require 'rubygems'
2
+ require 'util/trollop'
3
+ require 'ffi-opengl'
4
+
5
+ include FFI, GL, GLU, GLUT
6
+
7
+ module Hate
8
+ module Core
9
+
10
+ def self.trapcc
11
+ trap('INT') do
12
+ self.halt
13
+ end
14
+ end
15
+
16
+ def self.halt
17
+ @window.quit
18
+ Hate::Core::Callbacks.quit
19
+ puts "Goodbye!"
20
+ exit
21
+ end
22
+
23
+ def self.options
24
+ opts = Trollop::options do
25
+ version "Hate %s (c) 2011 Brian Jones" % Hate::VERSION
26
+ banner <<-EOS
27
+ Hate 3d - A Ruby 3d Game Engine
28
+
29
+ Usage:
30
+ hate [options] <game main.rb>
31
+
32
+ Options:
33
+ EOS
34
+ end
35
+ Trollop::die "No main.rb specified!" if ARGV[0].nil?
36
+ end
37
+
38
+ def self.load
39
+ # Load main.rb
40
+ begin
41
+ require ARGV[0]
42
+ rescue LoadError
43
+ require "./" + ARGV[0]
44
+ end
45
+
46
+ # Call #load
47
+ Hate::Core::Callbacks.load
48
+ end
49
+
50
+ def self.run
51
+ trapcc # Trap CTRL-C
52
+ options # Load cli options
53
+ @window = Hate::Graphics::Window.new
54
+ load # Load user game
55
+ @window.start
56
+ end
57
+
58
+ # Grab the default OpenGL window.
59
+ def self.window
60
+ @window
61
+ end
62
+
63
+ # Get the current time in seconds according to GLUT_ELAPSED_TIME.
64
+ def self.time
65
+ @window.time
66
+ end
67
+
68
+ def self.quit
69
+ halt
70
+ end
71
+
72
+ # Callbacks are overridden by the user in Core::Game
73
+ module Callbacks
74
+
75
+ # Initializes pre-game logic.
76
+ def self.load
77
+ Hate::Game.load if Hate::Game.respond_to?('load')
78
+ end
79
+
80
+ # Called every other tick to update game logic.
81
+ def self.update
82
+ Hate::Game.update if Hate::Game.respond_to?('update')
83
+ end
84
+
85
+ # Called each tick to update interface logic.
86
+ def self.draw
87
+ Hate::Game.draw if Hate::Game.respond_to?('draw')
88
+ end
89
+
90
+ # Called when a mouse button is pressed down.
91
+ def self.mousepressed(x, y, button)
92
+ Hate::Game.mousepressed(x, y, button) if Hate::Game.respond_to?('mousepressed')
93
+ end
94
+
95
+ # Called when a mouse button is let up.
96
+ def self.mousereleased(x, y, button)
97
+ Hate::Game.mousereleased(x, y, button) if Hate::Game.respond_to?('mousereleased')
98
+ end
99
+
100
+ # Called when a mouse is moved.
101
+ def self.mousemotion(x, y, xr, xy, state)
102
+ Hate::Game.mousemotion(x, y, xr, xy, state) if Hate::Game.respond_to?('mousemotion')
103
+ end
104
+
105
+ # Called when a key is pressed down.
106
+ def self.keypressed(key)
107
+ Hate::Game.keypressed(key) if Hate::Game.respond_to?('keypressed')
108
+ end
109
+
110
+ # Called when a key is let up.
111
+ def self.keyreleased(key)
112
+ Hate::Game.keyreleased(key) if Hate::Game.respond_to?('keyreleased')
113
+ end
114
+
115
+ # Called when the game is quit.
116
+ def self.quit
117
+ Hate::Game.quit if Hate::Game.respond_to?('quit')
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,6 @@
1
+ module Hate
2
+ # This is an empty module where the user overrides Hate::Core::Callbacks
3
+ module Game
4
+
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ module Hate
2
+ module Graphics
3
+ require 'util/gl'
4
+ require "ruby-sdl-ffi/sdl"
5
+
6
+ include FFI, GL, GLU
7
+
8
+ class SDLException < RuntimeError
9
+ end
10
+
11
+ autoload :Camera, APP_PATH + '/hate/graphics/camera.rb'
12
+ autoload :Color, APP_PATH + '/hate/graphics/color.rb'
13
+ autoload :Light, APP_PATH + '/hate/graphics/light.rb'
14
+ autoload :Manager, APP_PATH + '/hate/graphics/manager.rb'
15
+ autoload :Shader, APP_PATH + '/hate/graphics/shader.rb'
16
+ autoload :Shapes, APP_PATH + '/hate/graphics/shapes.rb'
17
+ autoload :Window, APP_PATH + '/hate/graphics/window.rb'
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ module Hate
2
+ module Graphics
3
+ class Camera
4
+
5
+ attr_accessor :x, :y, :z
6
+ attr_accessor :xl, :yl, :zl
7
+ attr_accessor :default
8
+
9
+ def initialize(angle=45.0, near=0.1, far=100.0)
10
+ @angle, @near, @far = angle, near, far
11
+ @x, @y, @z = 0.0, 1.0, 0.0
12
+ @xl, @yl, @zl = 0.0, 1.0, -1.0
13
+ @default = true
14
+ end
15
+
16
+ def is_default?
17
+ @default
18
+ end
19
+
20
+ def reshape(x, y)
21
+ glMatrixMode(GL_PROJECTION)
22
+ glLoadIdentity
23
+ glViewport(0, 0, x, y)
24
+ gluPerspective(@angle, x / y, @near, @far)
25
+ glMatrixMode(GL_MODELVIEW)
26
+ end
27
+
28
+ def run
29
+ glLoadIdentity
30
+ gluLookAt(
31
+ @x, @y, @z,
32
+ @x + @xl, 1.0, @z + @zl,
33
+ 0.0, 1.0, 0.0
34
+ )
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ module Hate
2
+ module Graphics
3
+ module Color
4
+ RED = MemoryPointer.new(:float, 4).put_array_of_float(0, [0.8, 0.1, 0.0, 1.0])
5
+ GREEN = MemoryPointer.new(:float, 4).put_array_of_float(0, [0.0, 0.8, 0.2, 1.0])
6
+ BLUE = MemoryPointer.new(:float, 4).put_array_of_float(0, [0.2, 0.2, 1.0, 1.0])
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Hate
2
+ module Graphics
3
+ class Light
4
+
5
+ attr_accessor :ambient, :diffuse, :position
6
+
7
+ def initialize(a=[0.5, 0.5, 0.5, 1.0], d=[1.0, 1.0, 1.0, 1.0], p=[0.0, 10.0, 0.0, 1.0])
8
+ @ambient = MemoryPointer.new(:float, 4).put_array_of_float(0, a)
9
+ @diffuse = MemoryPointer.new(:float, 4).put_array_of_float(0, d)
10
+ @position = MemoryPointer.new(:float, 4).put_array_of_float(0, p)
11
+ end
12
+
13
+ def run
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end