cyberarm_engine 0.14.0 → 0.15.0

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile +1 -1
  4. data/Rakefile +1 -1
  5. data/assets/textures/default.png +0 -0
  6. data/cyberarm_engine.gemspec +10 -8
  7. data/lib/cyberarm_engine.rb +13 -2
  8. data/lib/cyberarm_engine/animator.rb +6 -4
  9. data/lib/cyberarm_engine/background.rb +19 -15
  10. data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
  11. data/lib/cyberarm_engine/bounding_box.rb +18 -18
  12. data/lib/cyberarm_engine/cache.rb +4 -0
  13. data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
  14. data/lib/cyberarm_engine/common.rb +13 -13
  15. data/lib/cyberarm_engine/config_file.rb +2 -2
  16. data/lib/cyberarm_engine/game_object.rb +63 -72
  17. data/lib/cyberarm_engine/game_state.rb +6 -3
  18. data/lib/cyberarm_engine/model.rb +207 -0
  19. data/lib/cyberarm_engine/model/material.rb +21 -0
  20. data/lib/cyberarm_engine/model/model_object.rb +131 -0
  21. data/lib/cyberarm_engine/model/parser.rb +74 -0
  22. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
  23. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
  24. data/lib/cyberarm_engine/model_cache.rb +31 -0
  25. data/lib/cyberarm_engine/opengl.rb +28 -0
  26. data/lib/cyberarm_engine/opengl/light.rb +50 -0
  27. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
  28. data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
  29. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
  30. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
  31. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
  32. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
  33. data/lib/cyberarm_engine/{shader.rb → opengl/shader.rb} +51 -43
  34. data/lib/cyberarm_engine/opengl/texture.rb +69 -0
  35. data/lib/cyberarm_engine/ray.rb +5 -5
  36. data/lib/cyberarm_engine/stats.rb +2 -2
  37. data/lib/cyberarm_engine/text.rb +41 -27
  38. data/lib/cyberarm_engine/timer.rb +1 -1
  39. data/lib/cyberarm_engine/transform.rb +43 -20
  40. data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
  41. data/lib/cyberarm_engine/ui/dsl.rb +25 -11
  42. data/lib/cyberarm_engine/ui/element.rb +30 -20
  43. data/lib/cyberarm_engine/ui/elements/button.rb +86 -16
  44. data/lib/cyberarm_engine/ui/elements/check_box.rb +1 -1
  45. data/lib/cyberarm_engine/ui/elements/container.rb +44 -20
  46. data/lib/cyberarm_engine/ui/elements/edit_box.rb +175 -2
  47. data/lib/cyberarm_engine/ui/elements/edit_line.rb +121 -37
  48. data/lib/cyberarm_engine/ui/elements/flow.rb +1 -1
  49. data/lib/cyberarm_engine/ui/elements/image.rb +12 -9
  50. data/lib/cyberarm_engine/ui/elements/label.rb +93 -14
  51. data/lib/cyberarm_engine/ui/elements/list_box.rb +64 -2
  52. data/lib/cyberarm_engine/ui/elements/progress.rb +5 -5
  53. data/lib/cyberarm_engine/ui/elements/radio.rb +1 -1
  54. data/lib/cyberarm_engine/ui/elements/slider.rb +13 -16
  55. data/lib/cyberarm_engine/ui/elements/stack.rb +1 -1
  56. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +27 -19
  57. data/lib/cyberarm_engine/ui/event.rb +7 -7
  58. data/lib/cyberarm_engine/ui/gui_state.rb +44 -10
  59. data/lib/cyberarm_engine/ui/style.rb +10 -9
  60. data/lib/cyberarm_engine/ui/theme.rb +28 -20
  61. data/lib/cyberarm_engine/vector.rb +33 -30
  62. data/lib/cyberarm_engine/version.rb +2 -2
  63. data/lib/cyberarm_engine/window.rb +27 -18
  64. 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