hate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +95 -0
- data/Rakefile +17 -0
- data/bin/hate +7 -0
- data/example/main.rb +95 -0
- data/lib/hate.rb +16 -0
- data/lib/hate/audio.rb +0 -0
- data/lib/hate/core.rb +123 -0
- data/lib/hate/game.rb +6 -0
- data/lib/hate/graphics.rb +19 -0
- data/lib/hate/graphics/camera.rb +39 -0
- data/lib/hate/graphics/color.rb +9 -0
- data/lib/hate/graphics/light.rb +19 -0
- data/lib/hate/graphics/manager.rb +73 -0
- data/lib/hate/graphics/shader.rb +61 -0
- data/lib/hate/graphics/shaders/lights/point.fragment +31 -0
- data/lib/hate/graphics/shaders/lights/point.vertex +27 -0
- data/lib/hate/graphics/shapes.rb +118 -0
- data/lib/hate/graphics/window.rb +105 -0
- data/lib/hate/input.rb +35 -0
- data/lib/hate/network.rb +0 -0
- data/lib/hate/physics.rb +0 -0
- data/lib/hate/system.rb +0 -0
- data/lib/util/gl.rb +206 -0
- data/lib/util/trollop.rb +782 -0
- metadata +100 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Hate
|
2
|
+
module Graphics
|
3
|
+
module Manager
|
4
|
+
|
5
|
+
@objects = []
|
6
|
+
@shaders = []
|
7
|
+
@lights = []
|
8
|
+
@cameras = []
|
9
|
+
|
10
|
+
def self.lights
|
11
|
+
@lights
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.run
|
15
|
+
@cameras.each do |obj|
|
16
|
+
obj.run
|
17
|
+
end
|
18
|
+
|
19
|
+
@objects.each do |obj|
|
20
|
+
obj.run
|
21
|
+
end
|
22
|
+
|
23
|
+
@shaders.each do |obj|
|
24
|
+
obj.run
|
25
|
+
end
|
26
|
+
|
27
|
+
@lights.each do |obj|
|
28
|
+
obj.run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.add_object(obj)
|
33
|
+
@objects << obj
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.remove_object(obj)
|
37
|
+
@objects.delete obj
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.add_shader(obj)
|
41
|
+
@shaders << obj
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.remove_shader(obj)
|
45
|
+
@shaders.delete obj
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.add_light(obj)
|
49
|
+
@lights << obj
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.remove_light(obj)
|
53
|
+
@lights.delete obj
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.add_camera(obj)
|
57
|
+
@cameras << obj
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.remove_camera(obj)
|
61
|
+
@cameras.delete obj
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.default_camera
|
65
|
+
add_camera Hate::Graphics::Camera.new if @cameras.empty?
|
66
|
+
@cameras.each do |obj|
|
67
|
+
return obj if obj.is_default?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Hate
|
2
|
+
module Graphics
|
3
|
+
module Shader
|
4
|
+
|
5
|
+
class Program
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@program = glCreateProgram
|
9
|
+
end
|
10
|
+
|
11
|
+
def attach(shader)
|
12
|
+
glAttachShader(@program, shader)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def compile
|
17
|
+
glLinkProgram(@program)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
glUseProgram(@program)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Base
|
28
|
+
|
29
|
+
attr_reader :shader
|
30
|
+
|
31
|
+
def initialize(file)
|
32
|
+
source = []
|
33
|
+
source << MemoryPointer.from_string(File.open(file).read)
|
34
|
+
arg = MemoryPointer.new(:pointer, source.length)
|
35
|
+
source.each_with_index do |p, i|
|
36
|
+
arg[i].put_pointer(0, p)
|
37
|
+
end
|
38
|
+
|
39
|
+
if self.class == Hate::Graphics::Shader::Vertex
|
40
|
+
@shader = glCreateShader(GL_VERTEX_SHADER)
|
41
|
+
elsif self.class == Hate::Graphics::Shader::Fragment
|
42
|
+
@shader = glCreateShader(GL_FRAGMENT_SHADER)
|
43
|
+
end
|
44
|
+
|
45
|
+
glShaderSource(@shader, source.size, arg, nil)
|
46
|
+
glCompileShader(@shader)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class Vertex < Base
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class Fragment < Base
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
varying vec4 diffuse,ambientGlobal, ambient;
|
2
|
+
varying vec3 normal,lightDir,halfVector;
|
3
|
+
varying float dist;
|
4
|
+
|
5
|
+
void main()
|
6
|
+
{
|
7
|
+
vec3 n,halfV,viewV,ldir;
|
8
|
+
float NdotL,NdotHV;
|
9
|
+
vec4 color = ambientGlobal;
|
10
|
+
float att;
|
11
|
+
/* a fragment shader can't write a varying variable, hence we need
|
12
|
+
|
13
|
+
a new variable to store the normalized interpolated normal */
|
14
|
+
n = normalize(normal);
|
15
|
+
/* compute the dot product between normal and normalized lightdir */
|
16
|
+
|
17
|
+
NdotL = max(dot(n,normalize(lightDir)),0.0);
|
18
|
+
if (NdotL > 0.0) {
|
19
|
+
|
20
|
+
att = 1.0 / (gl_LightSource[0].constantAttenuation +
|
21
|
+
gl_LightSource[0].linearAttenuation * dist +
|
22
|
+
gl_LightSource[0].quadraticAttenuation * dist * dist);
|
23
|
+
color += att * (diffuse * NdotL + ambient);
|
24
|
+
halfV = normalize(halfVector);
|
25
|
+
|
26
|
+
NdotHV = max(dot(n,halfV),0.0);
|
27
|
+
color += att * gl_FrontMaterial.specular * gl_LightSource[0].specular *
|
28
|
+
pow(NdotHV,gl_FrontMaterial.shininess);
|
29
|
+
}
|
30
|
+
gl_FragColor = color;
|
31
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
varying vec4 diffuse,ambientGlobal,ambient;
|
2
|
+
varying vec3 normal,lightDir,halfVector;
|
3
|
+
varying float dist;
|
4
|
+
|
5
|
+
void main()
|
6
|
+
{
|
7
|
+
vec4 ecPos;
|
8
|
+
vec3 aux;
|
9
|
+
normal = normalize(gl_NormalMatrix * gl_Normal);
|
10
|
+
|
11
|
+
/* these are the new lines of code to compute the light's direction */
|
12
|
+
ecPos = gl_ModelViewMatrix * gl_Vertex;
|
13
|
+
aux = vec3(gl_LightSource[0].position-ecPos);
|
14
|
+
lightDir = normalize(aux);
|
15
|
+
dist = length(aux);
|
16
|
+
halfVector = normalize(gl_LightSource[0].halfVector.xyz);
|
17
|
+
|
18
|
+
/* Compute the diffuse, ambient and globalAmbient terms */
|
19
|
+
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
|
20
|
+
/* The ambient terms have been separated since one of them */
|
21
|
+
|
22
|
+
/* suffers attenuation */
|
23
|
+
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
|
24
|
+
ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;
|
25
|
+
gl_Position = ftransform();
|
26
|
+
|
27
|
+
}
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Hate
|
2
|
+
module Graphics
|
3
|
+
module Shapes
|
4
|
+
|
5
|
+
class Base
|
6
|
+
|
7
|
+
attr_accessor :memory, :size
|
8
|
+
attr_reader :x, :y, :z
|
9
|
+
attr_reader :ra, :rx, :ry, :rz
|
10
|
+
attr_reader :c
|
11
|
+
|
12
|
+
def initialize(s=1.0)
|
13
|
+
@size = s
|
14
|
+
|
15
|
+
@memory = nil
|
16
|
+
compile
|
17
|
+
|
18
|
+
translate
|
19
|
+
rotate
|
20
|
+
color
|
21
|
+
end
|
22
|
+
|
23
|
+
def translate(x=0.0, y=0.0, z=0.0)
|
24
|
+
@x, @y, @z = x, y, z
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def rotate(a=0.0, x=0.0, y=0.0, z=0.0)
|
29
|
+
@ra, @rx, @ry, @rz = a, x, y, z
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def color(r=0.0, g=0.0, b=0.0)
|
34
|
+
@c = [r, g, b]
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def compile
|
39
|
+
@memory = glGenLists(1) if @memory.nil?
|
40
|
+
glNewList(@memory, GL_COMPILE)
|
41
|
+
build
|
42
|
+
glEndList
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
glLoadIdentity
|
47
|
+
glPushMatrix
|
48
|
+
glColor3f(@c[0], @c[1], @c[2])
|
49
|
+
glTranslatef(@x, @y, @z)
|
50
|
+
glRotatef(@ra, @rx, @ry, @rz)
|
51
|
+
@memory.nil? ? build : glCallList(@memory)
|
52
|
+
glPopMatrix
|
53
|
+
end
|
54
|
+
|
55
|
+
def destroy
|
56
|
+
glDeleteLists(@memory)
|
57
|
+
@memory = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
class Square < Base
|
63
|
+
|
64
|
+
def build
|
65
|
+
glutSolidCube(@size)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class Cube < Base
|
71
|
+
|
72
|
+
def build
|
73
|
+
glBegin(GL_QUADS)
|
74
|
+
|
75
|
+
glNormal3f(0.0, 0.0, 1.0)
|
76
|
+
glVertex3f( @size, @size,-@size)
|
77
|
+
glVertex3f(-@size, @size,-@size)
|
78
|
+
glVertex3f(-@size, @size, @size)
|
79
|
+
glVertex3f( @size, @size, @size)
|
80
|
+
|
81
|
+
glNormal3f(0.0, 0.0, -1.0)
|
82
|
+
glVertex3f( @size,-@size, @size)
|
83
|
+
glVertex3f(-@size,-@size, @size)
|
84
|
+
glVertex3f(-@size,-@size,-@size)
|
85
|
+
glVertex3f( @size,-@size,-@size)
|
86
|
+
|
87
|
+
glNormal3f(0.0, 1.0, 0.0)
|
88
|
+
glVertex3f( @size, @size, @size)
|
89
|
+
glVertex3f(-@size, @size, @size)
|
90
|
+
glVertex3f(-@size,-@size, @size)
|
91
|
+
glVertex3f( @size,-@size, @size)
|
92
|
+
|
93
|
+
glNormal3f(0.0, -1.0, 0.0)
|
94
|
+
glVertex3f( @size,-@size,-@size)
|
95
|
+
glVertex3f(-@size,-@size,-@size)
|
96
|
+
glVertex3f(-@size, @size,-@size)
|
97
|
+
glVertex3f( @size, @size,-@size)
|
98
|
+
|
99
|
+
glNormal3f(1.0, 0.0, 0.0)
|
100
|
+
glVertex3f(-@size, @size, @size)
|
101
|
+
glVertex3f(-@size, @size,-@size)
|
102
|
+
glVertex3f(-@size,-@size,-@size)
|
103
|
+
glVertex3f(-@size,-@size, @size)
|
104
|
+
|
105
|
+
glNormal3f(-1.0, 0.0, 0.0)
|
106
|
+
glVertex3f(@size, @size,-@size)
|
107
|
+
glVertex3f(@size, @size, @size)
|
108
|
+
glVertex3f(@size,-@size, @size)
|
109
|
+
glVertex3f(@size,-@size,-@size)
|
110
|
+
|
111
|
+
glEnd
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Hate
|
2
|
+
module Graphics
|
3
|
+
|
4
|
+
DEFAULT_WIDTH = 800
|
5
|
+
DEFAULT_HEIGHT = 600
|
6
|
+
DEFAULT_COLOR = nil
|
7
|
+
DEFAULT_BACKGROUND = nil
|
8
|
+
|
9
|
+
class Window
|
10
|
+
|
11
|
+
attr_reader :width, :height
|
12
|
+
attr_reader :frames
|
13
|
+
|
14
|
+
def initialize(w=nil, h=nil, title='New Game')
|
15
|
+
@width = w || Hate::Graphics::DEFAULT_WIDTH
|
16
|
+
@height = h || Hate::Graphics::DEFAULT_HEIGHT
|
17
|
+
|
18
|
+
@frames = 0
|
19
|
+
|
20
|
+
if SDL.Init(SDL::INIT_EVERYTHING) == 0
|
21
|
+
SDL.EnableUNICODE(1)
|
22
|
+
else
|
23
|
+
throw Main::Graphics::SDLException, "SDL Exception: #{SDL.GetError()}"
|
24
|
+
end
|
25
|
+
SDL.SetVideoMode(@width, @height, 24, SDL::OPENGL)
|
26
|
+
SDL.Init(SDL::INIT_VIDEO)
|
27
|
+
|
28
|
+
glEnable(GL_DEPTH_TEST)
|
29
|
+
glEnable(GL_CULL_FACE)
|
30
|
+
glEnable(GL_COLOR_MATERIAL)
|
31
|
+
|
32
|
+
glShadeModel(GL_SMOOTH)
|
33
|
+
glClearColor(1.0, 1.0, 1.0, 0.0)
|
34
|
+
glClearDepth(1.0)
|
35
|
+
glDepthFunc(GL_LEQUAL)
|
36
|
+
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) # Small performance hit
|
37
|
+
|
38
|
+
# Hardware lights
|
39
|
+
Hate::Graphics::Manager.lights.each_with_index do |light, i|
|
40
|
+
glLightfv(eval("GL_LIGHT%i" % (i + 1)), GL_AMBIENT, light.ambient)
|
41
|
+
glLightfv(eval("GL_LIGHT%i" % (i + 1)), GL_DIFFUSE, light.diffuse)
|
42
|
+
glLightfv(eval("GL_LIGHT%i" % (i + 1)), GL_POSITION, light.position)
|
43
|
+
glEnable(eval("GL_LIGHT%i" % (i + 1)))
|
44
|
+
end
|
45
|
+
glEnable(GL_LIGHTING) if Hate::Graphics::Manager.lights.size > 0
|
46
|
+
|
47
|
+
reshape(@width, @height)
|
48
|
+
end
|
49
|
+
|
50
|
+
def draw
|
51
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
52
|
+
Hate::Core::Callbacks.draw
|
53
|
+
Hate::Graphics::Manager.run
|
54
|
+
SDL.GL_SwapBuffers()
|
55
|
+
@frames += 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def reshape(x, y)
|
59
|
+
Hate::Graphics::Manager.default_camera.reshape(x, y)
|
60
|
+
end
|
61
|
+
|
62
|
+
def update
|
63
|
+
until (event = SDL::PollEvent()).nil?
|
64
|
+
events(event)
|
65
|
+
end
|
66
|
+
Hate::Core::Callbacks.update if @frames % 2 == 0 # Only call update every second cycle
|
67
|
+
end
|
68
|
+
|
69
|
+
def events(event)
|
70
|
+
case event.type
|
71
|
+
when SDL::KEYDOWN
|
72
|
+
Hate::Input::Keyboard.pressed(event.keysym.sym)
|
73
|
+
when SDL::KEYUP
|
74
|
+
Hate::Input::Keyboard.released(event.keysym.sym)
|
75
|
+
when SDL::MOUSEBUTTONDOWN
|
76
|
+
Hate::Input::Mouse.pressed(event.x, event.y, event.button)
|
77
|
+
when SDL::MOUSEBUTTONUP
|
78
|
+
Hate::Input::Mouse.released(event.x, event.y, event.button)
|
79
|
+
when SDL::MOUSEMOTION
|
80
|
+
Hate::Input::Mouse.motion(event.x, event.y, event.xrel, event.yrel, event.state)
|
81
|
+
when SDL::VIDEORESIZE
|
82
|
+
reshape(event.w, event.h)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def time
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def start
|
91
|
+
loop do
|
92
|
+
update
|
93
|
+
draw
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def quit
|
98
|
+
SDL.QuitSubSystem(SDL::INIT_VIDEO)
|
99
|
+
SDL.Quit
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
data/lib/hate/input.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Hate
|
2
|
+
module Input
|
3
|
+
module Keyboard
|
4
|
+
|
5
|
+
@key_states = Array.new(256)
|
6
|
+
|
7
|
+
def self.pressed(k)
|
8
|
+
@key_states[k] = true
|
9
|
+
Hate::Core::Callbacks.keypressed(k)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.released(k)
|
13
|
+
@key_states[k] = false
|
14
|
+
Hate::Core::Callbacks.keyreleased(k)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
module Mouse
|
20
|
+
|
21
|
+
def self.pressed(x, y, button)
|
22
|
+
Hate::Core::Callbacks.mousepressed(x, y, button)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.released(x, y, button)
|
26
|
+
Hate::Core::Callbacks.mousereleased(x, y, button)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.motion(x, y, xr, yr, state)
|
30
|
+
Hate::Core::Callbacks.mousemotion(x, y, xr, yr, state)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|