Fixed some warnings, moved Subcommand into its own file, added support for subcommand and subcommand options autocomplete in Console, added texture ids to Model vertex buffer object

This commit is contained in:
2019-08-11 09:34:25 -05:00
parent 185d760a83
commit ce7d132864
9 changed files with 151 additions and 130 deletions

View File

@@ -23,13 +23,13 @@ when :OPENGL_PLATFORM_MACOSX
when :OPENGL_PLATFORM_LINUX when :OPENGL_PLATFORM_LINUX
gl_library_path = nil gl_library_path = nil
if File.exists?("/usr/lib/x86_64-linux-gnu/libGL.so") # Ubuntu (Debian) if File.exist?("/usr/lib/x86_64-linux-gnu/libGL.so") # Ubuntu (Debian)
gl_library_path = "/usr/lib/x86_64-linux-gnu" gl_library_path = "/usr/lib/x86_64-linux-gnu"
elsif File.exists?("/usr/lib/libGL.so") # Manjaro (ARCH) elsif File.exist?("/usr/lib/libGL.so") # Manjaro (ARCH)
gl_library_path = "/usr/lib" gl_library_path = "/usr/lib"
elsif File.exists?("/usr/lib/arm-linux-gnueabihf/libGL.so") # Raspbian (ARM/Raspberry Pi) elsif File.exist?("/usr/lib/arm-linux-gnueabihf/libGL.so") # Raspbian (ARM/Raspberry Pi)
gl_library_path = "/usr/lib/arm-linux-gnueabihf" gl_library_path = "/usr/lib/arm-linux-gnueabihf"
end end
@@ -86,6 +86,7 @@ require_relative "lib/states/game_state"
require_relative "lib/ui/menu" require_relative "lib/ui/menu"
require_relative "lib/ui/command" require_relative "lib/ui/command"
require_relative "lib/ui/subcommand"
Dir.glob("#{IMICFPS::GAME_ROOT_PATH}/lib/ui/commands/*.rb").each do |cmd| Dir.glob("#{IMICFPS::GAME_ROOT_PATH}/lib/ui/commands/*.rb").each do |cmd|
require_relative cmd require_relative cmd
end end

View File

@@ -7,15 +7,13 @@ class IMICFPS
def window; $window; end def window; $window; end
def delta_time def delta_time; (Gosu.milliseconds - @delta_time) / 1000.0; end
(Gosu.milliseconds-@delta_time)/1000.0
end
def button_down?(id); window.button_down?(id); end def button_down?(id); window.button_down?(id); end
def mouse_x; window.mouse_x; end def mouse_x; window.mouse_x; end
def mouse_y; window.mouse_y; end def mouse_y; window.mouse_y; end
def mouse_x=int; window.mouse_x=int; end def mouse_x=(int); window.mouse_x = int; end
def mouse_y=int; window.mouse_y=int; end def mouse_y=(int); window.mouse_y = int; end
def gl(&block) def gl(&block)
window.gl do window.gl do
@@ -31,6 +29,10 @@ class IMICFPS
return string return string
end end
def control_down?; button_down?(Gosu::KbLeftControl) || button_down?(Gosu::KbRightControl); end
def shift_down?; button_down?(Gosu::KbLeftShift) || button_down?(Gosu::KbRightShift); end
def alt_down?; button_down?(Gosu::KbLeftAlt) || button_down?(Gosu::KbRightAlt); end
def draw_rect(*args) def draw_rect(*args)
window.draw_rect(*args) window.draw_rect(*args)
end end

View File

@@ -10,7 +10,7 @@ class IMICFPS
query = @@keymap.dig(id_or_action) query = @@keymap.dig(id_or_action)
if query.is_a?(Integer) if query.is_a?(Integer)
id = query query
elsif query.is_a?(Array) elsif query.is_a?(Array)
query.each do |key| query.each do |key|
@@keys[key] = true @@keys[key] = true
@@ -28,7 +28,7 @@ class IMICFPS
query = @@keymap.dig(id_or_action) query = @@keymap.dig(id_or_action)
if query.is_a?(Integer) if query.is_a?(Integer)
id = query query
elsif query.is_a?(Array) elsif query.is_a?(Array)
query.each do |key| query.each do |key|
@@keys[key] = false @@keys[key] = false
@@ -40,7 +40,7 @@ class IMICFPS
end end
def self.get(action) def self.get(action)
key = @@keymap.dig(action) @@keymap.dig(action)
end end
def self.set(action, key) def self.set(action, key)

View File

@@ -9,7 +9,7 @@ class IMICFPS
attr_accessor :scale, :visible, :renderable, :backface_culling attr_accessor :scale, :visible, :renderable, :backface_culling
attr_accessor :position, :rotation, :velocity attr_accessor :position, :rotation, :velocity
attr_reader :model, :name, :debug_color, :bounding_box, :collision, :physics, :mass, :drag attr_reader :name, :debug_color, :bounding_box, :collision, :physics, :mass, :drag
def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, manifest_file: nil) def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, manifest_file: nil)
@position = Vector.new(x, y, z) @position = Vector.new(x, y, z)
@@ -42,7 +42,7 @@ class IMICFPS
@bound_model.model.objects.each { |o| o.scale = self.scale } @bound_model.model.objects.each { |o| o.scale = self.scale }
@normalized_bounding_box = normalize_bounding_box_with_offset @normalized_bounding_box = normalize_bounding_box_with_offset
box = normalize_bounding_box normalize_bounding_box
end end
return self return self

View File

@@ -86,6 +86,41 @@ class IMICFPS
end end
def autocomplete(console) def autocomplete(console)
split = console.text_input.text.split(" ")
if @subcommands.size > 0
if !console.text_input.text.end_with?(" ") && split.size == 2
list = console.abbrev_search(@subcommands.map { |cmd| cmd.command.to_s}, split.last)
if list.size == 1
console.text_input.text = "#{split.first} #{list.first} "
else
return unless list.size > 0
console.stdin("#{list.map { |cmd| Commands::Style.highlight(cmd)}.join(", ")}")
end
# List available options on subcommand
elsif (console.text_input.text.end_with?(" ") && split.size == 2) || !console.text_input.text.end_with?(" ") && split.size == 3
subcommand = @subcommands.detect { |cmd| cmd.command.to_s == (split[1]) }
if subcommand
if split.size == 2
console.stdin("Available options: #{subcommand.values.map { |value| Commands::Style.highlight(value) }.join(",")}")
else
list = console.abbrev_search(subcommand.values, split.last)
if list.size == 1
console.text_input.text = "#{split.first} #{split[1]} #{list.first} "
else
console.stdin("Available options: #{list.map { |value| Commands::Style.highlight(value) }.join(",")}")
end
end
end
# List available subcommands if command was entered and has only a space after it
elsif console.text_input.text.end_with?(" ") && split.size == 1
console.stdin("Available subcommands: #{@subcommands.map { |cmd| Commands::Style.highlight(cmd.command)}.join(", ")}")
end
end
end end
def handle_subcommand(arguments, console) def handle_subcommand(arguments, console)
@@ -107,91 +142,5 @@ class IMICFPS
raise NotImplementedError raise NotImplementedError
end end
end end
class SubCommand
def initialize(parent, command, type)
@parent = parent
@command = command
@type = type
end
def command
@command
end
def handle(arguments, console)
if arguments.size > 1
console.stdin("to many arguments for #{Style.highlight("#{command}")}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.")
return
end
case @type
when :boolean
case arguments.last
when "", nil
var = @parent.get(command.to_sym) ? @parent.get(command.to_sym) : false
console.stdin("#{command}: #{Style.highlight(var)}")
when "on"
var = @parent.set(command.to_sym, true)
console.stdin("#{command} => #{Style.highlight(var)}")
when "off"
var = @parent.set(command.to_sym, false)
console.stdin("#{command} => #{Style.highlight(var)}")
else
console.stdin("Invalid argument for #{Style.highlight("#{command}")}, got #{Style.error(arguments.last)} expected #{Style.notice("on")}, or #{Style.notice("off")}.")
end
when :string
case arguments.last
when "", nil
var = @parent.get(command.to_sym) ? @parent.get(command.to_sym) : "\"\""
console.stdin("#{command}: #{Style.highlight(var)}")
else
var = @parent.set(command.to_sym, arguments.last)
console.stdin("#{command} => #{Style.highlight(var)}")
end
when :integer
case arguments.last
when "", nil
var = @parent.get(command.to_sym) ? @parent.get(command.to_sym) : "nil"
console.stdin("#{command}: #{Style.highlight(var)}")
else
begin
var = @parent.set(command.to_sym, Integer(arguments.last))
console.stdin("#{command} => #{Style.highlight(var)}")
rescue ArgumentError
console.stdin("Error: #{Style.error("Expected an integer, got '#{arguments.last}'")}")
end
end
when :decimal
case arguments.last
when "", nil
var = @parent.get(command.to_sym) ? @parent.get(command.to_sym) : "nil"
console.stdin("#{command}: #{Style.highlight(var)}")
else
begin
var = @parent.set(command.to_sym, Float(arguments.last))
console.stdin("#{command} => #{Style.highlight(var)}")
rescue ArgumentError
console.stdin("Error: #{Style.error("Expected a decimal or integer, got '#{arguments.last}'")}")
end
end
else
raise RuntimeError
end
end
def usage
case @type
when :boolean
"#{Style.highlight(command)} #{Style.notice("[on|off]")}"
when :string
"#{Style.highlight(command)} #{Style.notice("[string]")}"
when :integer
"#{Style.highlight(command)} #{Style.notice("[0]")}"
when :decimal
"#{Style.highlight(command)} #{Style.notice("[0.0]")}"
end
end
end
end end
end end

View File

@@ -29,7 +29,7 @@ class IMICFPS
end end
def usage def usage
string = "debug\n #{@subcommands.map { |sub| sub.usage }.join("\n ")}" "debug\n #{@subcommands.map { |sub| sub.usage }.join("\n ")}"
end end
end end
end end

View File

@@ -4,6 +4,7 @@ class IMICFPS
PADDING = 2 PADDING = 2
include CommonMethods include CommonMethods
attr_reader :text_input
def initialize def initialize
@text_input = Gosu::TextInput.new @text_input = Gosu::TextInput.new
@@ -12,11 +13,13 @@ class IMICFPS
@history_height = window.height / 4 * 3 - (PADDING * 2 + @input.textobject.height) @history_height = window.height / 4 * 3 - (PADDING * 2 + @input.textobject.height)
@history = Text.new("=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n", x: 4, y: @history_height, z: Console::Z + 1) @history = Text.new("=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n", x: 4, y: @history_height, z: Console::Z + 1)
update_history update_history_y
@command_history = [] @command_history = []
@command_history_index = 0 @command_history_index = 0
@memory = ""
@background_color = Gosu::Color.rgba(0, 0, 0, 200) @background_color = Gosu::Color.rgba(0, 0, 0, 200)
@foreground_color = Gosu::Color.rgba(100, 100, 100, 100) @foreground_color = Gosu::Color.rgba(100, 100, 100, 100)
@input_color = Gosu::Color.rgba(100, 100, 100, 200) @input_color = Gosu::Color.rgba(100, 100, 100, 200)
@@ -28,6 +31,7 @@ class IMICFPS
@caret_last_change = Gosu.milliseconds @caret_last_change = Gosu.milliseconds
@caret_interval = 250 @caret_interval = 250
@caret_color = Gosu::Color::WHITE @caret_color = Gosu::Color::WHITE
@selection_color = Gosu::Color.new(0x5522ff22)
@width = window.width / 4 * 3 @width = window.width / 4 * 3
@height = window.height / 4 * 3 @height = window.height / 4 * 3
@@ -44,12 +48,36 @@ class IMICFPS
@history.draw @history.draw
@input.draw @input.draw
# Caret # Caret
draw_rect(@input.x + caret_pos, @input.y, Console::PADDING, @input.height, @caret_color, Console::Z + 2) if @show_caret draw_rect(@input.x + caret_from_left, @input.y, Console::PADDING, @input.height, @caret_color, Console::Z + 2) if @show_caret
# Caret selection
if caret_start != caret_end
if caret_start < @text_input.selection_start
draw_rect(@input.x + caret_from_left, @input.y, caret_selection_width, @input.height, @selection_color, Console::Z)
else
draw_rect((@input.x + caret_from_left) - caret_selection_width, @input.y, caret_selection_width, @input.height, @selection_color, Console::Z)
end
end
end
def caret_from_left
return 0 if @text_input.caret_pos == 0
@input.textobject.text_width(@text_input.text[0..@text_input.caret_pos-1])
end
def caret_selection_width
@input.textobject.text_width(@text_input.text[caret_start..(caret_end - 1)])
end end
def caret_pos def caret_pos
return 0 if @text_input.caret_pos == 0 @text_input.caret_pos
@input.textobject.text_width(@text_input.text[0..@text_input.caret_pos-1]) end
def caret_start
@text_input.selection_start < @text_input.caret_pos ? @text_input.selection_start : @text_input.caret_pos
end
def caret_end
@text_input.selection_start > @text_input.caret_pos ? @text_input.selection_start : @text_input.caret_pos
end end
def update def update
@@ -68,7 +96,7 @@ class IMICFPS
@history.text += "\n<c=999999>> #{@text_input.text}</c>" @history.text += "\n<c=999999>> #{@text_input.text}</c>"
@command_history << @text_input.text @command_history << @text_input.text
@command_history_index = @command_history.size @command_history_index = @command_history.size
update_history update_history_y
handle_command handle_command
@text_input.text = "" @text_input.text = ""
@@ -90,13 +118,12 @@ class IMICFPS
split = @text_input.text.split(" ") split = @text_input.text.split(" ")
if !@text_input.text.end_with?(" ") && split.size == 1 if !@text_input.text.end_with?(" ") && split.size == 1
list = command_search(@text_input.text) list = abbrev_search(Commands::Command.list_commands.map { |cmd| cmd.command.to_s}, @text_input.text)
if list.size == 1 if list.size == 1
@text_input.text = "#{list.first} " @text_input.text = "#{list.first} "
else else
@history.text += "\n#{list.map { |cmd| Commands::Style.highlight(cmd)}.join(", ")}" stdin("\n#{list.map { |cmd| Commands::Style.highlight(cmd)}.join(", ")}")
update_history
end end
else else
if split.size > 0 && cmd = Commands::Command.find(split.first) if split.size > 0 && cmd = Commands::Command.find(split.first)
@@ -105,19 +132,64 @@ class IMICFPS
end end
when Gosu::KbBacktick when Gosu::KbBacktick
# Removed backtick character from input # Remove backtick character from input
if @text_input.text.size > 1 if @text_input.text.size > 1
@text_input.text = @text_input.text[0..@text_input.text.size - 2] @text_input.text = @text_input.text[0..@text_input.text.size - 2]
else else
@text_input.text = "" @text_input.text = ""
end end
# Copy
when Gosu::KbC
if control_down? && shift_down?
@memory = @text_input.text[caret_start..caret_end - 1] if caret_start != caret_end
p @memory
elsif control_down?
@text_input.text = ""
end
# Paste
when Gosu::KbV
if control_down? && shift_down?
string = @text_input.text.chars.insert(caret_pos, @memory).join
_caret_pos = caret_pos
@text_input.text = string
@text_input.caret_pos = _caret_pos + @memory.length
@text_input.selection_start = _caret_pos + @memory.length
end
# Cut
when Gosu::KbX
if control_down? && shift_down?
@memory = @text_input.text[caret_start..caret_end - 1] if caret_start != caret_end
string = @text_input.text.chars
Array(caret_start..caret_end - 1).each_with_index do |i, j|
string.delete_at(i - j)
end
@text_input.text = string.join
end
# Delete word to left of caret
when Gosu::KbW
if control_down?
split = @text_input.text.split(" ")
split.delete(split.last)
@text_input.text = split.join(" ")
end
# Clear history
when Gosu::KbL
if control_down?
@history.text = ""
end
end end
end end
def button_up(id) def button_up(id)
end end
def update_history def update_history_y
@history.y = @history_height - (@history.text.lines.count * (@history.textobject.height)) @history.y = @history_height - (@history.text.lines.count * (@history.textobject.height))
end end
@@ -130,13 +202,11 @@ class IMICFPS
IMICFPS::Commands::Command.use(command, arguments, self) IMICFPS::Commands::Command.use(command, arguments, self)
end end
def command_search(text) def abbrev_search(array, text)
return [] unless text.length > 0 return [] unless text.length > 0
@command_search ||= Abbrev.abbrev(Commands::Command.list_commands.map { |cmd| cmd.command.to_s})
list = [] list = []
@command_search.each do |abbrev, value| Abbrev.abbrev(array).each do |abbrev, value|
next unless abbrev && abbrev.start_with?(text) next unless abbrev && abbrev.start_with?(text)
list << value list << value
@@ -147,7 +217,7 @@ class IMICFPS
def stdin(string) def stdin(string)
@history.text += "\n#{string}" @history.text += "\n#{string}"
update_history update_history_y
end end
def focus def focus

View File

@@ -3,7 +3,7 @@ class IMICFPS
class Material class Material
include OpenGL include OpenGL
attr_accessor :name, :ambient, :diffuse, :specular attr_accessor :name, :ambient, :diffuse, :specular
attr_reader :texture attr_reader :texture_id
def initialize(name) def initialize(name)
@name = name @name = name
@ambient = Color.new(1, 1, 1, 1) @ambient = Color.new(1, 1, 1, 1)
@@ -32,10 +32,6 @@ class IMICFPS
@texture = nil @texture = nil
end end
def texture_id
@texture_id
end
end end
end end
end end

View File

@@ -44,8 +44,8 @@ class IMICFPS
puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if $debug.get(:stats) puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if $debug.get(:stats)
# allocate_gl_objects allocate_gl_objects
# populate_buffers populate_buffers
# populate_arrays # populate_arrays
@objects.each {|o| @vertex_count+=o.vertices.size} @objects.each {|o| @vertex_count+=o.vertices.size}
@@ -83,16 +83,18 @@ class IMICFPS
def populate_buffers def populate_buffers
@vertices_buffer_data = [] @vertices_buffer_data = []
verts = [] verts = []
colors= [] colors = []
norms = [] norms = []
uvs = [] uvs = []
tex_ids = []
@faces.each do |face| @faces.each do |face|
verts << face.vertices.map { |vert| [vert.x, vert.y, vert.z] } verts << face.vertices.map { |vert| [vert.x, vert.y, vert.z] }
colors << face.colors.map { |vert| [vert.x, vert.y, vert.z] } colors << face.colors.map { |vert| [vert.x, vert.y, vert.z] }
norms << face.normals.map { |vert| [vert.x, vert.y, vert.z, vert.weight] } norms << face.normals.map { |vert| [vert.x, vert.y, vert.z, vert.weight] }
uvs << face.uvs.map { |vert| [vert.x, vert.y, vert.z] } if face.material.texture uvs << face.uvs.map { |vert| [vert.x, vert.y, vert.z] } if face.material.texture_id
tex_ids << face.material.texture_id if face.material.texture_id
end end
verts.each_with_index do |vert, i| verts.each_with_index do |vert, i|
@@ -100,6 +102,7 @@ class IMICFPS
@vertices_buffer_data << colors[i] @vertices_buffer_data << colors[i]
@vertices_buffer_data << norms[i] @vertices_buffer_data << norms[i]
@vertices_buffer_data << uvs[i] if uvs.size > 0 @vertices_buffer_data << uvs[i] if uvs.size > 0
@vertices_buffer_data << tex_ids[i] if tex_ids.size > 0
end end
data = @vertices_buffer_data.flatten.pack("f*") data = @vertices_buffer_data.flatten.pack("f*")