cyberarm_engine 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/assets/textures/default.png +0 -0
- data/cyberarm_engine.gemspec +10 -8
- data/lib/cyberarm_engine.rb +13 -2
- data/lib/cyberarm_engine/animator.rb +6 -4
- data/lib/cyberarm_engine/background.rb +19 -15
- data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
- data/lib/cyberarm_engine/bounding_box.rb +18 -18
- data/lib/cyberarm_engine/cache.rb +4 -0
- data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
- data/lib/cyberarm_engine/common.rb +13 -13
- data/lib/cyberarm_engine/config_file.rb +2 -2
- data/lib/cyberarm_engine/game_object.rb +63 -72
- data/lib/cyberarm_engine/game_state.rb +6 -3
- data/lib/cyberarm_engine/model.rb +207 -0
- data/lib/cyberarm_engine/model/material.rb +21 -0
- data/lib/cyberarm_engine/model/model_object.rb +131 -0
- data/lib/cyberarm_engine/model/parser.rb +74 -0
- data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
- data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
- data/lib/cyberarm_engine/model_cache.rb +31 -0
- data/lib/cyberarm_engine/opengl.rb +28 -0
- data/lib/cyberarm_engine/opengl/light.rb +50 -0
- data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
- data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
- data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
- data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
- data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
- data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
- data/lib/cyberarm_engine/{shader.rb → opengl/shader.rb} +51 -43
- data/lib/cyberarm_engine/opengl/texture.rb +69 -0
- data/lib/cyberarm_engine/ray.rb +5 -5
- data/lib/cyberarm_engine/stats.rb +2 -2
- data/lib/cyberarm_engine/text.rb +41 -27
- data/lib/cyberarm_engine/timer.rb +1 -1
- data/lib/cyberarm_engine/transform.rb +43 -20
- data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
- data/lib/cyberarm_engine/ui/dsl.rb +25 -11
- data/lib/cyberarm_engine/ui/element.rb +30 -20
- data/lib/cyberarm_engine/ui/elements/button.rb +86 -16
- data/lib/cyberarm_engine/ui/elements/check_box.rb +1 -1
- data/lib/cyberarm_engine/ui/elements/container.rb +44 -20
- data/lib/cyberarm_engine/ui/elements/edit_box.rb +175 -2
- data/lib/cyberarm_engine/ui/elements/edit_line.rb +121 -37
- data/lib/cyberarm_engine/ui/elements/flow.rb +1 -1
- data/lib/cyberarm_engine/ui/elements/image.rb +12 -9
- data/lib/cyberarm_engine/ui/elements/label.rb +93 -14
- data/lib/cyberarm_engine/ui/elements/list_box.rb +64 -2
- data/lib/cyberarm_engine/ui/elements/progress.rb +5 -5
- data/lib/cyberarm_engine/ui/elements/radio.rb +1 -1
- data/lib/cyberarm_engine/ui/elements/slider.rb +13 -16
- data/lib/cyberarm_engine/ui/elements/stack.rb +1 -1
- data/lib/cyberarm_engine/ui/elements/toggle_button.rb +27 -19
- data/lib/cyberarm_engine/ui/event.rb +7 -7
- data/lib/cyberarm_engine/ui/gui_state.rb +44 -10
- data/lib/cyberarm_engine/ui/style.rb +10 -9
- data/lib/cyberarm_engine/ui/theme.rb +28 -20
- data/lib/cyberarm_engine/vector.rb +33 -30
- data/lib/cyberarm_engine/version.rb +2 -2
- data/lib/cyberarm_engine/window.rb +27 -18
- metadata +65 -15
@@ -0,0 +1,138 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
class ColladaParser < Model::Parser
|
3
|
+
def self.handles
|
4
|
+
[:dae]
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse
|
8
|
+
@collada = Nokogiri::XML(File.read(@model.file_path))
|
9
|
+
|
10
|
+
@collada.css("library_materials material").each do |material|
|
11
|
+
parse_material(material)
|
12
|
+
end
|
13
|
+
|
14
|
+
@collada.css("library_geometries geometry").each do |geometry|
|
15
|
+
parse_geometry(geometry)
|
16
|
+
end
|
17
|
+
|
18
|
+
@model.calculate_bounding_box(@model.vertices, @model.bounding_box)
|
19
|
+
@model.objects.each do |o|
|
20
|
+
@model.calculate_bounding_box(o.vertices, o.bounding_box)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_material(material)
|
25
|
+
name = material.attributes["id"].value
|
26
|
+
effect_id = material.at_css("instance_effect").attributes["url"].value
|
27
|
+
|
28
|
+
mat = Model::Material.new(name)
|
29
|
+
effect = @collada.at_css("[id=\"#{effect_id.sub('#', '')}\"]")
|
30
|
+
|
31
|
+
emission = effect.at_css("emission color")
|
32
|
+
diffuse = effect.at_css("diffuse color").children.first.to_s.split(" ").map { |c| Float(c) }
|
33
|
+
|
34
|
+
mat.diffuse = Color.new(*diffuse[0..2])
|
35
|
+
|
36
|
+
add_material(name, mat)
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_geometry(geometry)
|
40
|
+
geometry_id = geometry.attributes["id"].value
|
41
|
+
geometry_name = geometry.attributes["name"].value
|
42
|
+
|
43
|
+
change_object(geometry_id, geometry_name)
|
44
|
+
|
45
|
+
mesh = geometry.at_css("mesh")
|
46
|
+
|
47
|
+
get_positions(geometry_id, mesh)
|
48
|
+
get_normals(geometry_id, mesh)
|
49
|
+
get_texture_coordinates(geometry_id, mesh)
|
50
|
+
|
51
|
+
project_node(geometry_name)
|
52
|
+
build_faces(geometry_id, mesh)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_positions(id, mesh)
|
56
|
+
positions = mesh.at_css("[id=\"#{id}-positions\"]")
|
57
|
+
array = positions.at_css("[id=\"#{id}-positions-array\"]")
|
58
|
+
|
59
|
+
stride = Integer(positions.at_css("[source=\"##{id}-positions-array\"]").attributes["stride"].value)
|
60
|
+
list = array.children.first.to_s.split(" ").map { |f| Float(f) }.each_slice(stride).each do |slice|
|
61
|
+
position = Vector.new(*slice)
|
62
|
+
@model.current_object.vertices << position
|
63
|
+
@model.vertices << position
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_normals(id, mesh)
|
68
|
+
normals = mesh.at_css("[id=\"#{id}-normals\"]")
|
69
|
+
array = normals.at_css("[id=\"#{id}-normals-array\"]")
|
70
|
+
|
71
|
+
stride = Integer(normals.at_css("[source=\"##{id}-normals-array\"]").attributes["stride"].value)
|
72
|
+
list = array.children.first.to_s.split(" ").map { |f| Float(f) }.each_slice(stride).each do |slice|
|
73
|
+
normal = Vector.new(*slice)
|
74
|
+
@model.current_object.normals << normal
|
75
|
+
@model.normals << normal
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_texture_coordinates(id, mesh)
|
80
|
+
end
|
81
|
+
|
82
|
+
def project_node(name)
|
83
|
+
@collada.css("library_visual_scenes visual_scene node").each do |node|
|
84
|
+
next unless node.attributes["name"].value == name
|
85
|
+
|
86
|
+
transform = Transform.new(node.at_css("matrix").children.first.to_s.split(" ").map { |f| Float(f) })
|
87
|
+
|
88
|
+
@model.current_object.vertices.each do |vert|
|
89
|
+
v = vert.multiply_transform(transform)
|
90
|
+
vert.x = v.x
|
91
|
+
vert.y = v.y
|
92
|
+
vert.z = v.z
|
93
|
+
vert.w = v.w
|
94
|
+
end
|
95
|
+
|
96
|
+
break
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_faces(_id, mesh)
|
101
|
+
material_name = mesh.at_css("triangles").attributes["material"].value
|
102
|
+
set_material(material_name)
|
103
|
+
|
104
|
+
positions_index = []
|
105
|
+
normals_index = []
|
106
|
+
uvs_index = []
|
107
|
+
|
108
|
+
mesh.at_css("triangles p").children.first.to_s.split(" ").map { |i| Integer(i) }.each_slice(3).each do |slice|
|
109
|
+
positions_index << slice[0]
|
110
|
+
normals_index << slice[1]
|
111
|
+
uvs_index << slice[2]
|
112
|
+
end
|
113
|
+
|
114
|
+
norm_index = 0
|
115
|
+
positions_index.each_slice(3) do |slice|
|
116
|
+
face = Face.new
|
117
|
+
face.vertices = []
|
118
|
+
face.uvs = []
|
119
|
+
face.normals = []
|
120
|
+
face.colors = []
|
121
|
+
face.material = current_material
|
122
|
+
face.smoothing = @model.smoothing
|
123
|
+
|
124
|
+
slice.each do |index|
|
125
|
+
face.vertices << @model.vertices[index]
|
126
|
+
# face.uvs << @model.uvs[index]
|
127
|
+
face.normals << @model.normals[normals_index[norm_index]]
|
128
|
+
face.colors << current_material.diffuse
|
129
|
+
|
130
|
+
norm_index += 1
|
131
|
+
end
|
132
|
+
|
133
|
+
@model.current_object.faces << face
|
134
|
+
@model.faces << face
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
class WavefrontParser < Model::Parser
|
3
|
+
def self.handles
|
4
|
+
[:obj]
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse
|
8
|
+
lines = 0
|
9
|
+
list = File.read(@model.file_path).split("\n")
|
10
|
+
list.each do |line|
|
11
|
+
lines += 1
|
12
|
+
line = line.strip
|
13
|
+
|
14
|
+
array = line.split(" ")
|
15
|
+
case array[0]
|
16
|
+
when "mtllib"
|
17
|
+
@model.material_file = array[1]
|
18
|
+
parse_mtllib
|
19
|
+
when "usemtl"
|
20
|
+
set_material(array[1])
|
21
|
+
when "o"
|
22
|
+
change_object(nil, array[1])
|
23
|
+
when "s"
|
24
|
+
set_smoothing(array[1])
|
25
|
+
when "v"
|
26
|
+
add_vertex(array)
|
27
|
+
when "vt"
|
28
|
+
add_texture_coordinate(array)
|
29
|
+
|
30
|
+
when "vn"
|
31
|
+
add_normal(array)
|
32
|
+
|
33
|
+
when "f"
|
34
|
+
verts = []
|
35
|
+
uvs = []
|
36
|
+
norms = []
|
37
|
+
array[1..3].each do |f|
|
38
|
+
verts << f.split("/")[0]
|
39
|
+
uvs << f.split("/")[1]
|
40
|
+
norms << f.split("/")[2]
|
41
|
+
end
|
42
|
+
|
43
|
+
face = Face.new
|
44
|
+
face.vertices = []
|
45
|
+
face.uvs = []
|
46
|
+
face.normals = []
|
47
|
+
face.colors = []
|
48
|
+
face.material = current_material
|
49
|
+
face.smoothing = @model.smoothing
|
50
|
+
|
51
|
+
mat = face.material.diffuse
|
52
|
+
color = mat
|
53
|
+
|
54
|
+
verts.each_with_index do |v, index|
|
55
|
+
if uvs.first != ""
|
56
|
+
face.vertices << @model.vertices[Integer(v) - 1]
|
57
|
+
face.uvs << @model.uvs[Integer(uvs[index]) - 1]
|
58
|
+
face.normals << @model.normals[Integer(norms[index]) - 1]
|
59
|
+
face.colors << color
|
60
|
+
else
|
61
|
+
face.vertices << @model.vertices[Integer(v) - 1]
|
62
|
+
face.uvs << nil
|
63
|
+
face.normals << @model.normals[Integer(norms[index]) - 1]
|
64
|
+
face.colors << color
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
@model.current_object.faces << face
|
69
|
+
@model.faces << face
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@model.calculate_bounding_box(@model.vertices, @model.bounding_box)
|
74
|
+
@model.objects.each do |o|
|
75
|
+
@model.calculate_bounding_box(o.vertices, o.bounding_box)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_mtllib
|
80
|
+
file = File.open(@model.file_path.sub(File.basename(@model.file_path), "") + @model.material_file, "r")
|
81
|
+
file.readlines.each do |line|
|
82
|
+
array = line.strip.split(" ")
|
83
|
+
case array.first
|
84
|
+
when "newmtl"
|
85
|
+
material = Model::Material.new(array.last)
|
86
|
+
@model.current_material = array.last
|
87
|
+
@model.materials[array.last] = material
|
88
|
+
when "Ns" # Specular Exponent
|
89
|
+
when "Ka" # Ambient color
|
90
|
+
@model.materials[@model.current_material].ambient = Color.new(Float(array[1]), Float(array[2]),
|
91
|
+
Float(array[3]))
|
92
|
+
when "Kd" # Diffuse color
|
93
|
+
@model.materials[@model.current_material].diffuse = Color.new(Float(array[1]), Float(array[2]),
|
94
|
+
Float(array[3]))
|
95
|
+
when "Ks" # Specular color
|
96
|
+
@model.materials[@model.current_material].specular = Color.new(Float(array[1]), Float(array[2]),
|
97
|
+
Float(array[3]))
|
98
|
+
when "Ke" # Emissive
|
99
|
+
when "Ni" # Unknown (Blender Specific?)
|
100
|
+
when "d" # Dissolved (Transparency)
|
101
|
+
when "illum" # Illumination model
|
102
|
+
when "map_Kd" # Diffuse texture
|
103
|
+
texture = File.basename(array[1])
|
104
|
+
texture_path = "#{File.expand_path('../../', @model.file_path)}/textures/#{texture}"
|
105
|
+
@model.materials[@model.current_material].set_texture(texture_path)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_smoothing(value)
|
111
|
+
@model.smoothing = value == "1"
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_vertex(array)
|
115
|
+
@model.vertex_count += 1
|
116
|
+
vert = nil
|
117
|
+
if array.size == 5
|
118
|
+
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
119
|
+
elsif array.size == 4
|
120
|
+
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
121
|
+
else
|
122
|
+
raise
|
123
|
+
end
|
124
|
+
@model.current_object.vertices << vert
|
125
|
+
@model.vertices << vert
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_normal(array)
|
129
|
+
vert = nil
|
130
|
+
if array.size == 5
|
131
|
+
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
132
|
+
elsif array.size == 4
|
133
|
+
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
134
|
+
else
|
135
|
+
raise
|
136
|
+
end
|
137
|
+
@model.current_object.normals << vert
|
138
|
+
@model.normals << vert
|
139
|
+
end
|
140
|
+
|
141
|
+
def add_texture_coordinate(array)
|
142
|
+
texture = nil
|
143
|
+
if array.size == 4
|
144
|
+
texture = Vector.new(Float(array[1]), 1 - Float(array[2]), Float(array[3]))
|
145
|
+
elsif array.size == 3
|
146
|
+
texture = Vector.new(Float(array[1]), 1 - Float(array[2]), 1.0)
|
147
|
+
else
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
@model.uvs << texture
|
151
|
+
@model.current_object.uvs << texture
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
module ModelCache
|
3
|
+
CACHE = {}
|
4
|
+
|
5
|
+
def self.find_or_cache(manifest:)
|
6
|
+
model_file = manifest.file_path + "/model/#{manifest.model}"
|
7
|
+
|
8
|
+
type = File.basename(model_file).split(".").last.to_sym
|
9
|
+
|
10
|
+
if model = load_model_from_cache(type, model_file)
|
11
|
+
model
|
12
|
+
else
|
13
|
+
model = CyberarmEngine::Model.new(file_path: model_file)
|
14
|
+
cache_model(type, model_file, model)
|
15
|
+
|
16
|
+
model
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load_model_from_cache(type, model_file)
|
21
|
+
return CACHE[type][model_file] if CACHE[type].is_a?(Hash) && (CACHE[type][model_file])
|
22
|
+
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.cache_model(type, model_file, model)
|
27
|
+
CACHE[type] = {} unless CACHE[type].is_a?(Hash)
|
28
|
+
CACHE[type][model_file] = model
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
begin
|
2
|
+
require "opengl"
|
3
|
+
rescue LoadError
|
4
|
+
puts "Required gem is not installed, please install 'opengl-bindings' and try again."
|
5
|
+
exit(1)
|
6
|
+
end
|
7
|
+
|
8
|
+
module CyberarmEngine
|
9
|
+
def gl_error?
|
10
|
+
e = glGetError
|
11
|
+
if e != GL_NO_ERROR
|
12
|
+
warn "OpenGL error detected by handler at: #{caller[0]}"
|
13
|
+
warn " #{gluErrorString(e)} (#{e})\n"
|
14
|
+
exit if window.exit_on_opengl_error?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require_relative "opengl/shader"
|
20
|
+
require_relative "opengl/texture"
|
21
|
+
require_relative "opengl/light"
|
22
|
+
require_relative "opengl/perspective_camera"
|
23
|
+
require_relative "opengl/orthographic_camera"
|
24
|
+
|
25
|
+
require_relative "opengl/renderer/g_buffer"
|
26
|
+
require_relative "opengl/renderer/bounding_box_renderer"
|
27
|
+
require_relative "opengl/renderer/opengl_renderer"
|
28
|
+
require_relative "opengl/renderer/renderer"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
class Light
|
3
|
+
DIRECTIONAL = 0
|
4
|
+
POINT = 1
|
5
|
+
SPOT = 2
|
6
|
+
|
7
|
+
attr_reader :light_id
|
8
|
+
attr_accessor :type, :ambient, :diffuse, :specular, :position, :direction, :intensity
|
9
|
+
|
10
|
+
def initialize(
|
11
|
+
id:,
|
12
|
+
type: Light::POINT,
|
13
|
+
ambient: Vector.new(0.5, 0.5, 0.5),
|
14
|
+
diffuse: Vector.new(1, 1, 1),
|
15
|
+
specular: Vector.new(0.2, 0.2, 0.2),
|
16
|
+
position: Vector.new(0, 0, 0),
|
17
|
+
direction: Vector.new(0, 0, 0),
|
18
|
+
intensity: 1
|
19
|
+
)
|
20
|
+
@light_id = id
|
21
|
+
@type = type
|
22
|
+
|
23
|
+
@ambient = ambient
|
24
|
+
@diffuse = diffuse
|
25
|
+
@specular = specular
|
26
|
+
@position = position
|
27
|
+
@direction = direction
|
28
|
+
|
29
|
+
@intensity = intensity
|
30
|
+
end
|
31
|
+
|
32
|
+
def draw
|
33
|
+
glLightfv(@light_id, GL_AMBIENT, convert(@ambient).pack("f*"))
|
34
|
+
glLightfv(@light_id, GL_DIFFUSE, convert(@diffuse, true).pack("f*"))
|
35
|
+
glLightfv(@light_id, GL_SPECULAR, convert(@specular, true).pack("f*"))
|
36
|
+
glLightfv(@light_id, GL_POSITION, convert(@position).pack("f*"))
|
37
|
+
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1)
|
38
|
+
glEnable(GL_LIGHTING)
|
39
|
+
glEnable(@light_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def convert(struct, apply_intensity = false)
|
43
|
+
if apply_intensity
|
44
|
+
struct.to_a.compact.map { |i| i * @intensity }
|
45
|
+
else
|
46
|
+
struct.to_a.compact
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CyberarmEngine
|
2
|
+
class OrthographicCamera
|
3
|
+
attr_accessor :position, :orientation, :zoom, :left, :right, :bottom, :top,
|
4
|
+
:min_view_distance, :max_view_distance
|
5
|
+
|
6
|
+
def initialize(
|
7
|
+
position:, right:, top:, orientation: Vector.new(0, 0, 0),
|
8
|
+
zoom: 1, left: 0, bottom: 0,
|
9
|
+
min_view_distance: 0.1, max_view_distance: 200.0
|
10
|
+
)
|
11
|
+
@position = position
|
12
|
+
@orientation = orientation
|
13
|
+
|
14
|
+
@zoom = zoom
|
15
|
+
|
16
|
+
@left = left
|
17
|
+
@right = right
|
18
|
+
@bottom = bottom
|
19
|
+
@top = top
|
20
|
+
|
21
|
+
@min_view_distance = min_view_distance
|
22
|
+
@max_view_distance = max_view_distance
|
23
|
+
end
|
24
|
+
|
25
|
+
# Immediate mode renderering fallback
|
26
|
+
def draw
|
27
|
+
glMatrixMode(GL_PROJECTION)
|
28
|
+
glLoadIdentity
|
29
|
+
glOrtho(@left, @right, @bottom, @top, @min_view_distance, @max_view_distance)
|
30
|
+
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
|
31
|
+
glRotatef(@orientation.x, 1, 0, 0)
|
32
|
+
glRotatef(@orientation.y, 0, 1, 0)
|
33
|
+
glTranslatef(-@position.x, -@position.y, -@position.z)
|
34
|
+
glMatrixMode(GL_MODELVIEW)
|
35
|
+
glLoadIdentity
|
36
|
+
end
|
37
|
+
|
38
|
+
def projection_matrix
|
39
|
+
Transform.orthographic(@left, @right, @bottom, @top, @min_view_distance, @max_view_distance)
|
40
|
+
end
|
41
|
+
|
42
|
+
def view_matrix
|
43
|
+
Transform.translate_3d(@position * -1) * Transform.rotate_3d(@orientation)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|