31 Commits

Author SHA1 Message Date
ce089afbf1 Fixed crashes due to removal of 'label' from CyberarmEngine GUI system 2024-04-09 08:27:00 -05:00
3851eb1630 Extracted frame timings graph to CyberarmEngine 2023-04-20 21:55:12 -05:00
2da9edb6d0 Refactored to use CyberarmEngine::Window#delta_time instead of our reimplementing it, add WIP frame timing to Overlay using CyberarmEngine::Stats.frames data 2023-04-20 16:14:29 -05:00
8f2d7ff905 Moved shaders to cyberarm_engine, patched up settings menu, updated gems. 2023-01-08 17:29:31 -06:00
580c9d79ce Updated gems, fix issues caused by the removal of $window from cyberarm_engine 2022-07-16 06:59:47 -05:00
07c8dfa45b Merge pull request #11 from cyberarm/dependabot/bundler/nokogiri-1.13.6
Bump nokogiri from 1.13.4 to 1.13.6
2022-05-24 09:37:58 -05:00
dependabot[bot]
b69bdc8e46 Bump nokogiri from 1.13.4 to 1.13.6
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.4 to 1.13.6.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.4...v1.13.6)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 05:21:15 +00:00
3481de2498 Merge pull request #9 from cyberarm/dependabot/bundler/nokogiri-1.13.4
Bump nokogiri from 1.13.2 to 1.13.4
2022-04-12 08:06:00 -05:00
dependabot[bot]
7bcd973a88 Bump nokogiri from 1.13.2 to 1.13.4
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.2 to 1.13.4.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/v1.13.4/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.2...v1.13.4)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-12 10:23:14 +00:00
1d34cbb63d Merge pull request #8 from cyberarm/dependabot/bundler/nokogiri-1.13.2
Bump nokogiri from 1.11.6 to 1.13.2
2022-03-12 21:27:21 -06:00
dependabot[bot]
2df2df8488 Bump nokogiri from 1.11.6 to 1.13.2
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.6 to 1.13.2.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.6...v1.13.2)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-26 06:56:08 +00:00
87bff4ab82 Extracted Console into CyberarmEngine 2021-06-26 13:10:54 +00:00
cf37b94d80 Initial music playlist implementation, added menu music 2021-06-17 23:54:46 +00:00
0fe1d85924 Added Window#input_hijack to allow objects to get exclusive access to button_down/up callbacks, improved Chat widget 2021-06-03 15:14:06 +00:00
ec2b32ff92 Added title screen sound, added sound when mousing over menu links, update "required" Ruby version to 3.0+ in README 2021-06-03 03:05:10 +00:00
3986b1b0af Tweak menus a bit, add proper single player menu, made back link have some margin from above links 2021-06-03 00:59:08 +00:00
58b2f8b890 Added vertical_/horizontal_margin/padding to Widgets, added HUD command to toggle HUD 2021-06-02 12:55:08 +00:00
5cb48233fb Removed vertices count from Window, use new CyberarmEngine::Renderer::OpenGLRenderer#vertices_count for debug stats 2021-05-30 14:09:32 +00:00
da54bf5c53 Replaced usages of Text shadow with properly named border, use new correct Text shadow for menu titles, use text border for a few more elements 2021-05-29 00:36:47 +00:00
3570a80d67 Added icons for settings menu, refreshed menus to unify layouts 2021-05-27 02:39:32 +00:00
51363d2e3d Changed HUD text to have solid black 'border' 2021-05-26 23:18:52 +00:00
a16e14b0e5 Merge pull request #6 from cyberarm/dependabot/bundler/nokogiri-1.11.4
Bump nokogiri from 1.11.1 to 1.11.4
2021-05-20 15:05:59 +00:00
dependabot[bot]
4ebc4772a1 Bump nokogiri from 1.11.1 to 1.11.4
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.1 to 1.11.4.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.1...v1.11.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-20 15:00:13 +00:00
15ba3fb15b Fixed AssetViewer crashing when loading a scripted asset 2021-04-25 23:22:01 +00:00
c5e0f33f21 Addded some life to the Close state with some animations 2021-04-25 15:38:39 +00:00
d3fbf5dcf5 Breathe a little life into the Boot state 2021-04-25 14:57:03 +00:00
5b662f83cf Fixed g_buffer shader failing to compile 2021-04-24 20:09:21 +00:00
55bfe6ed79 Clean up window initialization a little bit, prevent window from being resizable if fullscreen: 'fixes' gosu believing that the window is smaller than it is 2021-04-19 19:11:01 +00:00
bd414cf765 Removed border from links 2021-03-29 08:52:08 -05:00
c848a11c12 WIP changes sync 2021-03-29 08:52:08 -05:00
5759055838 Added initial gamma correction 2021-03-29 08:14:29 -05:00
81 changed files with 1491 additions and 1178 deletions

View File

@@ -1,12 +1,9 @@
GIT
remote: https://github.com/cyberarm/cyberarm_engine
revision: 20970e5aa9fbcad6d4bf7d9b56cbd06ba5c53275
revision: 9694cc2270198005bc2388fc6dacddfbb9629f60
specs:
cyberarm_engine (0.17.1)
clipboard (~> 1.3.5)
excon (~> 0.78.0)
cyberarm_engine (0.24.4)
gosu (~> 1.1)
gosu_more_drawables (~> 0.3)
GIT
remote: https://github.com/gosu/releasy.git
@@ -21,28 +18,25 @@ GIT
GEM
remote: https://rubygems.org/
specs:
clipboard (1.3.5)
concurrent-ruby (1.1.8)
concurrent-ruby (1.2.3)
cri (2.1.0)
excon (0.78.1)
gosu (1.1.0)
gosu_more_drawables (0.3.1)
i18n (1.8.8)
excon (0.110.0)
gosu (1.4.6)
i18n (1.14.4)
concurrent-ruby (~> 1.0)
mini_portile2 (2.5.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
nokogiri (1.11.1-x64-mingw32)
mini_portile2 (2.8.5)
nokogiri (1.16.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
ocra (1.3.11)
opengl-bindings (1.6.10)
racc (1.5.2)
rake (13.0.3)
rubyzip (2.3.0)
opengl-bindings (1.6.14)
racc (1.7.3)
rake (13.2.1)
rubyzip (2.3.2)
PLATFORMS
ruby
x64-mingw-ucrt
x64-mingw32
DEPENDENCIES
@@ -57,4 +51,4 @@ DEPENDENCIES
rubyzip
BUNDLED WITH
2.2.3
2.4.8

View File

@@ -10,7 +10,7 @@ Creating a multiplayer first-person-shooter in pure Ruby; Using C extensions onl
![screenshot](https://raw.githubusercontent.com/cyberarm/i-mic-fps/master/screenshots/screenshot-game.png)
## Using
Ruby 2.5+ interpeter with support for the Gosu game library C extension.
Ruby 3.0+ interpeter with support for the Gosu game library C extension.
* Clone or download this repo
* `bundle install`
* `bundle exec ruby i-mic-fps.rb [options]`

View File

@@ -9,7 +9,7 @@ end
class Window < Gosu::Window
def initialize
super(Gosu.screen_width, Gosu.screen_height, fullscreen: true)
$window = self
CyberarmEngine::Window.instance = self
@size = 50
@slope = 250
@color_step = 10

View File

@@ -3,7 +3,7 @@
component(:vehicle) # Generic, Weapon
on.button_down(:interact) do |event|
$window.console.stdin("#{event.entity.name} handled button_down(:interact)")
CyberarmEngine::Window.instance.console.stdin("#{event.entity.name} handled button_down(:interact)")
# if event.player.touching?(event.entity)
# event.player.enter_vehicle
# elsif event.player.driving?(event.entity) or event.player.passenger?(event.entity)

View File

@@ -0,0 +1,22 @@
{
"playlists": {
"menus": [
"menu_background"
],
"nighttime": [],
"daytime": []
},
"music": [
{
"name": "menu_background",
"path": "music/untitled-2-revised-extended_mixed.ogg"
}
],
"sounds": [
{
"name": "shield_regen",
"type": "sfx",
"path": "sfx/shield_regen.wav"
}
]
}

View File

@@ -1,11 +0,0 @@
---
playlists:
- menus:
- nighttime:
- daytime:
music:
sounds:
-
name: shield_regen
type: sfx
path: sfx/shield_regen.wav

View File

@@ -31,6 +31,7 @@ include GLU
def require_all(directory)
files = Dir["#{directory}/**/*.rb"].sort!
file_order = []
loop do
failed = []
@@ -39,6 +40,7 @@ def require_all(directory)
files.each do |file|
begin
require_relative file
file_order << file
rescue NameError => e
failed << file
first_name_error ||= e
@@ -52,6 +54,8 @@ def require_all(directory)
end
break if failed.empty?
end
# pp file_order.map { |f| f.gsub(".rb", "")}
end
require_all "lib"
@@ -75,17 +79,36 @@ end
if prevent_launch?[0]
puts prevent_launch?[1]
elsif ARGV.join.include?("--profile")
begin
require "ruby-prof"
RubyProf.start
IMICFPS::Window.new.show
result = RubyProf.stop
printer = RubyProf::MultiPrinter.new(result)
printer.print(path: ".", profile: "profile", min_percent: 2)
rescue LoadError
puts "ruby-prof not installed!"
end
else
IMICFPS::Window.new.show
native = ARGV.join.include?("--native")
fps_target = ARGV.first.to_i != 0 ? ARGV.first.to_i : 60
window_width = native ? Gosu.screen_width : 1280
window_height = native ? Gosu.screen_height : 720
window_fullscreen = native ? true : false
window = IMICFPS::Window.new(
width: window_width,
height: window_height,
fullscreen: window_fullscreen,
resizable: !window_fullscreen,
update_interval: 1000.0 / fps_target
)
if ARGV.join.include?("--profile")
begin
require "ruby-prof"
RubyProf.start
window.show
result = RubyProf.stop
printer = RubyProf::MultiPrinter.new(result)
printer.print(path: ".", profile: "profile", min_percent: 2)
rescue LoadError
puts "ruby-prof not installed!"
raise
end
else
window.show
end
end

View File

@@ -7,7 +7,7 @@ class IMICFPS
attr_accessor :mode, :camera, :entity, :distance, :origin_distance,
:constant_pitch, :mouse_sensitivity, :mouse_captured
def initialize(camera:, entity:, mode: :fpv)
def initialize(camera:, entity: nil, mode: :fpv)
# :fpv - First Person View
# :tpv - Third Person View
@mode = mode
@@ -63,7 +63,7 @@ class IMICFPS
end
def update
position_camera
position_camera if @entity
return unless @mouse_captured
@@ -74,8 +74,10 @@ class IMICFPS
@camera.orientation.x -= Float(@true_mouse.y - window.mouse_y) / (@mouse_sensitivity * @camera.field_of_view) * 70
@camera.orientation.x = @camera.orientation.x.clamp(-90.0, 90.0)
@entity.orientation.y += delta
@entity.orientation.y %= 360.0
if @entity
@entity.orientation.y += delta
@entity.orientation.y %= 360.0
end
window.mouse_x = window.width / 2 if window.mouse_x <= 1 || window.mouse_x >= window.width - 1
window.mouse_y = window.height / 2 if window.mouse_y <= 1 || window.mouse_y >= window.height - 1
@@ -99,14 +101,49 @@ class IMICFPS
@camera.max_view_distance += 0.5
elsif actions.include?(:toggle_first_person_view)
@mode = first_person_view? ? :tpv : :fpv
@entity.visible = !first_person_view?
@entity.visible = !first_person_view? if @entity
elsif actions.include?(:turn_180)
@entity.orientation.y += 180
@entity.orientation.y %= 360.0
@entity.orientation.y += 180 if @entity
@entity.orientation.y %= 360.0 if @entity
end
end
def button_up(id)
end
def free_move
relative_y_rotation = (@camera.orientation.y + 180)
relative_speed = 2.5
relative_speed = 1.5 if InputMapper.down?(:sneak)
relative_speed = 10.0 if InputMapper.down?(:sprint)
relative_speed *= window.dt
if InputMapper.down?( :forward)
@camera.position.z += Math.cos(relative_y_rotation * Math::PI / 180) * relative_speed
@camera.position.x -= Math.sin(relative_y_rotation * Math::PI / 180) * relative_speed
end
if InputMapper.down?(:backward)
@camera.position.z -= Math.cos(relative_y_rotation * Math::PI / 180) * relative_speed
@camera.position.x += Math.sin(relative_y_rotation * Math::PI / 180) * relative_speed
end
if InputMapper.down?(:strife_left)
@camera.position.z += Math.sin(relative_y_rotation * Math::PI / 180) * relative_speed
@camera.position.x += Math.cos(relative_y_rotation * Math::PI / 180) * relative_speed
end
if InputMapper.down?(:strife_right)
@camera.position.z -= Math.sin(relative_y_rotation * Math::PI / 180) * relative_speed
@camera.position.x -= Math.cos(relative_y_rotation * Math::PI / 180) * relative_speed
end
if InputMapper.down?(:ascend)
@camera.position.y += relative_speed
end
if InputMapper.down?(:descend)
@camera.position.y -= relative_speed
end
end
end
end

View File

@@ -7,11 +7,11 @@ class IMICFPS
module CommonMethods
def window
$window
CyberarmEngine::Window.instance
end
def delta_time
(Gosu.milliseconds - window.delta_time) / 1000.0
window.delta_time
end
def button_down?(id)

View File

@@ -11,8 +11,25 @@ class IMICFPS
end
def draw
draw_rect(window.width / 2 - @size, (window.height / 2 - @size) - @thickness / 2, @size * 2, @thickness, @color, 0, :default)
draw_rect((window.width / 2) - @thickness / 2, window.height / 2 - (@size * 2), @thickness, @size * 2, @color, 0, :default)
draw_rect(
window.width / 2 - @size,
(window.height / 2 - @size) - @thickness / 2,
@size * 2,
@thickness,
@color,
0,
:default
)
draw_rect(
(window.width / 2) - @thickness / 2,
window.height / 2 - (@size * 2),
@thickness,
@size * 2,
@color,
0,
:default
)
end
end
end

View File

@@ -77,12 +77,12 @@ class IMICFPS
when "up"
input = InputMapper.get(data.last.to_sym)
key = input.is_a?(Array) ? input.first : input
$window.current_state.button_up(key) if key
CyberarmEngine::Window.instance.current_state.button_up(key) if key
when "down"
input = InputMapper.get(data.last.to_sym)
key = input.is_a?(Array) ? input.first : input
$window.current_state.button_down(key) if key
CyberarmEngine::Window.instance.current_state.button_down(key) if key
when "mouse"
@camera.orientation.z = data[1].to_f

13
lib/ext/element.rb Normal file
View File

@@ -0,0 +1,13 @@
module CyberarmEngine
class Element
alias enter_original enter
def enter(_sender)
if @block && is_a?(CyberarmEngine::Element::Link)
get_sample("#{IMICFPS::GAME_ROOT_PATH}/static/sounds/ui_hover.ogg").play
end
enter_original(_sender)
end
end
end

View File

@@ -32,5 +32,13 @@ class IMICFPS
def update
@hud_elements.each(&:update)
end
def button_down(id)
@hud_elements.each { |e| e.button_down(id) }
end
def button_up(id)
@hud_elements.each { |e| e.button_up(id) }
end
end
end

View File

@@ -7,21 +7,37 @@ class IMICFPS
# Widget margin from screen edge
# or how much widget is pushed in
def self.margin
@@margin ||= 10
def self.vertical_margin
@@vertical_margin ||= 36
end
def self.padding=(n)
@@padding = n
def self.vertical_margin=(n)
@@vertical_margin = n
end
def self.horizontal_margin
@@horizontal_margin ||= 10
end
def self.horizontal_margin=(n)
@@horizontal_margin = n
end
# Widget element padding
def self.padding
@@margin ||= 10
def self.vertical_padding
@@vertical_padding ||= 10
end
def self.padding=(n)
@@padding = n
def self.vertical_padding=(n)
@@vertical_padding = n
end
def self.horizontal_padding
@@horizontal_padding ||= 10
end
def self.horizontal_padding=(n)
@@horizontal_padding = n
end
attr_reader :options
@@ -41,6 +57,20 @@ class IMICFPS
def update
end
def button_down(id)
end
def button_up(id)
end
def hijack_input!
CyberarmEngine::Window.instance.input_hijack = self
end
def release_input!
CyberarmEngine::Window.instance.input_hijack = nil
end
end
end
end

View File

@@ -4,14 +4,14 @@ class IMICFPS
class HUD
class AmmoWidget < HUD::Widget
def setup
@text = Text.new("", size: 64, mode: :add, font: MONOSPACE_FONT)
@text = Text.new("", size: 64, font: MONOSPACE_FONT, border: true, border_color: Gosu::Color::BLACK)
@background = Gosu::Color.new(0x88c64600)
end
def draw
Gosu.draw_rect(
@text.x - Widget.padding, @text.y - Widget.padding,
@text.width + Widget.padding * 2, @text.height + Widget.padding * 2,
@text.x - Widget.horizontal_padding, @text.y - Widget.vertical_padding,
@text.width + Widget.horizontal_padding * 2, @text.height + Widget.vertical_padding * 2,
@background
)
@text.draw
@@ -23,8 +23,8 @@ class IMICFPS
@text.text = "#{random}/999"
end
@text.x = window.width - (Widget.margin + @text.width + Widget.padding)
@text.y = window.height - (Widget.margin + @text.height + Widget.padding)
@text.x = window.width - (Widget.horizontal_margin + @text.width + Widget.horizontal_padding)
@text.y = window.height - (Widget.vertical_margin + @text.height + Widget.vertical_padding)
end
end
end

View File

@@ -4,41 +4,93 @@ class IMICFPS
class HUD
class ChatWidget < HUD::Widget
def setup
@text = Text.new("", size: 28, mode: :add, font: SANS_FONT)
@deliver_to_text = Text.new("", size: 28, font: BOLD_SANS_FONT)
@text = Text.new("", size: 28, font: SANS_FONT)
@text_input = nil
@background = Gosu::Color.new(0x88c64600)
@selection_color = Gosu::Color.new(0x88222222)
@width = @options[:width] || 400
@delivery_options = [:all, :team, :squad]
end
def draw
return unless window.text_input
return unless @text_input
Gosu.draw_rect(
@text.x - Widget.padding, @text.y - Widget.padding,
@text.width + Widget.padding * 2, @text.height + Widget.padding * 2,
Widget.horizontal_margin, CyberarmEngine::Window.instance.height / 2 - (@text.height / 2 + Widget.horizontal_padding),
@width - Widget.horizontal_padding * 2, @text.height + Widget.vertical_padding * 2,
@background
)
@text.draw
@deliver_to_text.draw
clip_width = @deliver_to_text.width + Widget.horizontal_padding * 3 + Widget.horizontal_margin
Gosu.clip_to(@text.x, @text.y, @width - clip_width, @text.height) do
x = Widget.horizontal_margin + Widget.horizontal_padding + @deliver_to_text.width
cursor_x = x + @text.width(@text_input.text[0...@text_input.caret_pos])
selection_x = x + @text.width(@text_input.text[0...@text_input.selection_start])
selection_width = cursor_x - selection_x
cursor_thickness = 2
Gosu.draw_rect(selection_x, @text.y, selection_width, @text.height, @selection_color)
Gosu.draw_rect(cursor_x, @text.y, cursor_thickness, @text.height, Gosu::Color::WHITE)
@text.draw
end
end
def update
# NOTE: Account for Y in QWERTZ layout
text = window.text_input&.text
@deliver_to_text.text = "#{@deliver_to}: "
@deliver_to_text.x = Widget.horizontal_margin + Widget.horizontal_padding
@deliver_to_text.y = CyberarmEngine::Window.instance.height / 2 - (@text.height / 2)
if window.text_input.nil? && (Gosu.button_down?(Gosu::KbT) || Gosu.button_down?(Gosu::KbY) || Gosu.button_down?(Gosu::KbU))
window.text_input = Gosu::TextInput.new
@text.text = @text_input&.text.to_s
@text.x = Widget.horizontal_margin + Widget.horizontal_padding + @deliver_to_text.width
@text.y = CyberarmEngine::Window.instance.height / 2 - (@text.height / 2)
end
def button_down(id)
# TODO: Use InputMapper keymap to function
# NOTE: Account for Y in QWERTZ layout
case id
when Gosu::KB_T, Gosu::KB_Y, Gosu::KB_U
return if @text_input
hijack_input!
@text_input = window.text_input = Gosu::TextInput.new
@deliver_to = :all if Gosu.button_down?(Gosu::KbT)
@deliver_to = :team if Gosu.button_down?(Gosu::KbY)
@deliver_to = :squad if Gosu.button_down?(Gosu::KbU)
end
when Gosu::KB_TAB
return unless @text_input
if window.text_input && (Gosu.button_down?(Gosu::KbEnter) || Gosu.button_down?(Gosu::KbReturn))
window.text_input = nil
cycle_deliver_to
end
end
@text.text = text.to_s
@text.x = window.width / 2 - (Widget.margin + @text.width / 2 + Widget.padding)
@text.y = window.height - (Widget.margin + @text.height + Widget.padding)
def button_up(id)
return unless @text_input
case id
when Gosu::KB_ENTER, Gosu::KB_RETURN
release_input!
# TODO: Deliver message to server
@text_input = window.text_input = nil
when Gosu::KB_ESCAPE
release_input!
@text_input = window.text_input = nil
end
end
def cycle_deliver_to
i = @delivery_options.index(@deliver_to)
@deliver_to = @delivery_options[(i + 1) % (@delivery_options.size)]
end
end
end

View File

@@ -9,12 +9,9 @@ class IMICFPS
@text = CyberarmEngine::Text.new(
"",
size: 16,
x: Widget.margin, y: Widget.margin, z: 45,
shadow_size: 0.5,
shadow_alpha: 0,
shadow_color: Gosu::Color::WHITE,
mode: :add,
font: SANS_FONT
x: Widget.horizontal_margin, y: Widget.vertical_margin, z: 45,
border_color: Gosu::Color::BLACK,
font: BOLD_SANS_FONT
)
@last_message_time = 0

View File

@@ -5,7 +5,7 @@ class IMICFPS
class HealthWidget < HUD::Widget
def setup
@spacer = 0
@text = Text.new("", mode: :add, font: MONOSPACE_FONT)
@text = Text.new("", font: MONOSPACE_FONT, border: true, border_color: Gosu::Color::BLACK)
@width = 512
@height = 24
@slant = 32
@@ -19,10 +19,10 @@ class IMICFPS
def draw
@text.draw
fill_quad(
window.width / 2 - @width / 2, @spacer + Widget.margin, # TOP LEFT
window.width / 2 + @width / 2, @spacer + Widget.margin, # TOP RIGHT
window.width / 2 + @width / 2 - @slant, @spacer + Widget.margin + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + Widget.margin + @height, # BOTTOM LEFT
window.width / 2 - @width / 2, @spacer + Widget.vertical_margin, # TOP LEFT
window.width / 2 + @width / 2, @spacer + Widget.vertical_margin, # TOP RIGHT
window.width / 2 + @width / 2 - @slant, @spacer + Widget.vertical_margin + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + Widget.vertical_margin + @height, # BOTTOM LEFT
@color
)
@@ -31,10 +31,10 @@ class IMICFPS
# Current Health
fill_quad(
window.width / 2 - @width / 2, @spacer + Widget.margin, # TOP LEFT
(window.width / 2 - @width / 2) + @width * @health, @spacer + Widget.margin, # TOP RIGHT
bottom_right, @spacer + Widget.margin + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + Widget.margin + @height, # BOTTOM LEFT
window.width / 2 - @width / 2, @spacer + Widget.vertical_margin, # TOP LEFT
(window.width / 2 - @width / 2) + @width * @health, @spacer + Widget.vertical_margin, # TOP RIGHT
bottom_right, @spacer + Widget.vertical_margin + @height, # BOTTOM RIGHT
window.width / 2 - @width / 2 + @slant, @spacer + Widget.vertical_margin + @height, # BOTTOM LEFT
@shield
)
end
@@ -43,7 +43,7 @@ class IMICFPS
percentage = (@health * 100).round.to_s.rjust(3, "0")
@text.text = "[Health #{percentage}%]"
@text.x = window.width / 2 - @text.width / 2
@text.y = @spacer + Widget.margin + @height / 2 - @text.height / 2
@text.y = @spacer + Widget.vertical_margin + @height / 2 - @text.height / 2
@health += 0.1 * window.dt
@health = 0 if @health > 1.0

View File

@@ -12,36 +12,41 @@ class IMICFPS
@border_color = Gosu::Color.new(0x88c64600)
@radar_color = Gosu::Color.new(0x88212121)
@text = Text.new("RADAR", size: 18, mode: :add, font: MONOSPACE_FONT)
@text = Text.new("RADAR", size: 18, font: MONOSPACE_FONT, border: true, border_color: Gosu::Color::BLACK)
@image = Gosu::Image.new("#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/default.png", retro: true)
@scale = (@size - Widget.padding * 2.0) / @image.width
@scale = (@size - Widget.horizontal_padding * 2.0) / @image.width
end
def draw
Gosu.draw_rect(
Widget.margin, window.height - (@size + Widget.margin),
Widget.horizontal_margin, window.height - (@size + Widget.vertical_margin),
@size, @size,
@border_color
)
Gosu.draw_rect(
Widget.margin + Widget.padding, window.height - (@size + Widget.margin) + Widget.padding,
@size - Widget.padding * 2, @size - Widget.padding * 2,
Widget.horizontal_margin + Widget.horizontal_padding,
window.height - (@size + Widget.vertical_margin) + Widget.vertical_padding,
@size - Widget.horizontal_padding * 2, @size - Widget.horizontal_padding * 2,
@radar_color
)
@image.draw(Widget.margin + Widget.padding, window.height - (@size + Widget.margin) + Widget.padding, 46, @scale, @scale, 0x88ffffff)
@image.draw(
Widget.horizontal_margin + Widget.horizontal_padding,
window.height - (@size + Widget.vertical_margin) + Widget.vertical_padding,
46, @scale, @scale, 0x88ffffff
)
@text.draw
end
def update
@size = (window.width / @target_screen_width.to_f * @max_size).clamp(@min_size, @max_size)
@scale = (@size - Widget.padding * 2.0) / @image.width
@scale = (@size - Widget.horizontal_padding * 2.0) / @image.width
@text.text = "X: #{@player.position.x.round(1)} Y: #{@player.position.y.round(1)} Z: #{@player.position.z.round(1)}"
@text.x = Widget.margin + @size / 2 - @text.width / 2
@text.y = window.height - (Widget.margin + @size + @text.height)
@text.x = Widget.horizontal_margin + @size / 2 - @text.width / 2
@text.y = window.height - (Widget.vertical_margin + @size + @text.height)
end
end
end

View File

@@ -9,13 +9,10 @@ class IMICFPS
@text = CyberarmEngine::Text.new(
"",
size: 16,
x: Widget.margin, y: Widget.margin, z: 45,
shadow: true,
shadow_size: 0.5,
shadow_alpha: 30,
shadow_color: Gosu::Color::WHITE,
mode: :add,
font: MONOSPACE_FONT
x: Widget.horizontal_margin, y: Widget.vertical_margin, z: 45,
border: true,
border_color: Gosu::Color::BLACK,
font: BOLD_SANS_FONT
)
set_text
@@ -26,7 +23,7 @@ class IMICFPS
end
def update
@text.x = window.width - (@text.markup_width + Widget.margin)
@text.x = window.width - (@text.markup_width + Widget.horizontal_margin)
end
def generate_random_data

View File

@@ -14,12 +14,10 @@ class IMICFPS
@text = Text.new(
"MATE\nTinyTanker\nOther Player Dude\nHuman 0xdeadbeef",
size: 18,
mode: :add,
font: SANS_FONT,
color: @color,
shadow: true,
shadow_color: 0x88000000,
shadow_size: 0.75
border: true,
border_color: Gosu::Color::BLACK,
)
end
@@ -30,8 +28,8 @@ class IMICFPS
def update
@size = (window.width / @target_screen_width.to_f * @max_size).clamp(@min_size, @max_size)
@text.x = Widget.margin + @size + Widget.padding
@text.y = window.height - (Widget.margin + @text.height)
@text.x = Widget.horizontal_margin + @size + Widget.horizontal_padding
@text.y = window.height - (Widget.vertical_margin + @text.height)
end
end
end

View File

@@ -26,7 +26,7 @@ class IMICFPS
def available_light
raise "Using to many lights, #{light_count}/#{LightManager::MAX_LIGHTS}" if light_count > LightManager::MAX_LIGHTS
puts "OpenGL::GL_LIGHT#{light_count}" if $window.config.get(:debug_options, :stats)
puts "OpenGL::GL_LIGHT#{light_count}" if CyberarmEngine::Window.instance.config.get(:debug_options, :stats)
Object.const_get "OpenGL::GL_LIGHT#{light_count}"
end
end

View File

@@ -7,37 +7,40 @@ class IMICFPS
@masters = {}
@effects = []
@playlists = {}
@current_playlist = nil
@current_playlist_package = nil
@current_playlist_name = nil
@current_playlist_index = 0
def self.master_volume
1.0
window.config.get(:options, :audio, :volume_master)
end
def self.music_volume
0.25 * master_volume
window.config.get(:options, :audio, :volume_music) * master_volume
end
def self.sfx_volume
0.5 * master_volume
window.config.get(:options, :audio, :volume_sound_effects) * master_volume
end
def self.load_master(package)
return if @masters[package]
yaml = YAML.load_file("#{IMICFPS.assets_path}/#{package}/shared/sound/master.yaml")
@masters[package] = yaml
hash = JSON.parse(File.read("#{IMICFPS.assets_path}/#{package}/shared/sound/master.json"))
@masters[package] = hash
end
def self.sound(package, name)
if data = sound_data(package, name.to_s)
get_sample("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}")
else
raise "Missing sound: '#{name}' in package '#{package}'"
end
raise "Missing sound: '#{name}' in package '#{package}'" unless (data = sound_data(package, name.to_s))
get_sample("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}")
end
def self.sound_data(package, name)
load_master(package)
if master = @masters[package]
if (master = @masters[package])
return master["sounds"].find { |s| s["name"] == name }
end
@@ -48,8 +51,61 @@ class IMICFPS
@effects << klass.new(options)
end
def self.music(package, name)
raise "Missing song: '#{name}' in package '#{package}'" unless (data = music_data(package, name.to_s))
get_song("#{IMICFPS.assets_path}/#{package}/shared/sound/#{data['path']}")
end
def self.music_data(package, name)
load_master(package)
if (master = @masters[package])
return master["music"].find { |s| s["name"] == name }
end
nil
end
def self.playlist_data(package, name)
load_master(package)
if (master = @masters[package])
return master.dig("playlists", name.to_s)
end
nil
end
def self.play_playlist(package, name)
return if @current_playlist_name == name.to_s
return unless (list = playlist_data(package, name.to_s))
@current_playlist = list
@current_playlist_package = package
@current_playlist_name = name.to_s
@current_playlist_index = 0
@current_song = music(@current_playlist_package, @current_playlist[@current_playlist_index])
@current_song.volume = music_volume
@current_song.play
end
def self.update
@effects.each { |e| e.update; @effects.delete(e) if e.done? }
return unless @current_playlist
if !@current_song&.playing? && music_volume > 0.0
@current_playlist_index += 1
@current_playlist_index = 0 if @current_playlist_index >= @current_playlist.size
@current_song = music(@current_playlist_package, @current_playlist[@current_playlist_index])
@current_song.play
end
@current_song&.volume = music_volume
@current_song&.stop if music_volume < 0.1
end
end
end

View File

@@ -20,8 +20,8 @@ class IMICFPS
end
def setup
add_terrain
add_skybox
add_terrain if @map_parser.terrain.name
add_skybox if @map_parser.skydome.name
add_lights
add_entities

View File

@@ -40,7 +40,7 @@ class IMICFPS
@metadata.thumbnail = section["thumbnail"] # TODO: convert thumbnail to Image
@metadata.description = section["description"]
else
raise "Map metadata is missing!"
warn "Map metadata is missing!"
end
if section = data["terrain"]
@@ -64,7 +64,7 @@ class IMICFPS
end
@terrain.water_level = section["water_level"]
else
raise "Map terrain data is missing!"
warn "Map terrain data is missing!"
end
if section = data["skydome"]
@@ -87,7 +87,7 @@ class IMICFPS
@skydome.scale = Vector.new(1, 1, 1)
end
else
raise "Map skydome data is missing!"
warn "Map skydome data is missing!"
end
if section = data["lights"]
@@ -150,7 +150,7 @@ class IMICFPS
@entities << entity
end
else
raise "Map has no entities!"
warn "Map has no entities!"
end
if section = data["spawnpoints"]
@@ -171,7 +171,7 @@ class IMICFPS
@spawnpoints << spawnpoint
end
else
raise "Map has no spawnpoints!"
warn "Map has no spawnpoints!"
end
end

View File

@@ -46,7 +46,7 @@ class IMICFPS
def tick(delta_time)
return unless @map
Publisher.instance.publish(:tick, delta_time * 1000.0)
Publisher.instance.publish(:tick, delta_time)
@map.update
@server&.update

View File

@@ -7,7 +7,7 @@ class IMICFPS
Slot = Struct.new(:value, :width)
def initialize
@text = CyberarmEngine::Text.new("", x: 3, y: 3, shadow_color: Gosu::Color::BLACK)
@text = CyberarmEngine::Text.new("", x: 3, y: 3, border_color: Gosu::Color::BLACK)
@slots = []
@space_width = @text.textobject.text_width(" ")
end
@@ -33,13 +33,13 @@ class IMICFPS
if window.config.get(:options, :fps)
create_slot "FPS: #{Gosu.fps}"
if window.config.get(:debug_options, :stats)
create_slot "Frame time: #{(Gosu.milliseconds - window.delta_time).to_s.rjust(3, '0')}ms"
create_slot "Frame time: #{(window.delta_time * 1000).round.to_s}ms"
end
end
if window.config.get(:debug_options, :stats)
create_slot "Vertices: #{formatted_number(window.number_of_vertices)}"
create_slot "Faces: #{formatted_number(window.number_of_vertices / 3)}"
create_slot "Vertices: #{formatted_number(window.renderer.opengl_renderer.number_of_vertices)}"
create_slot "Faces: #{formatted_number(window.renderer.opengl_renderer.number_of_vertices / 3)}"
end
if window.config.get(:debug_options, :boundingboxes)

View File

@@ -5,7 +5,7 @@ class IMICFPS
attr_reader :camera, :entities, :lights
def initialize
@camera = PerspectiveCamera.new(position: Vector.new, aspect_ratio: $window.aspect_ratio)
@camera = PerspectiveCamera.new(position: Vector.new, aspect_ratio: CyberarmEngine::Window.instance.aspect_ratio)
@entities = []
@lights = []

View File

@@ -12,7 +12,7 @@ class IMICFPS
end
def map
$window.director.map
CyberarmEngine::Window.instance.director.map
end
end
end

View File

@@ -19,7 +19,7 @@ class IMICFPS
end
def calculate_volume
volume = (SoundManager.sfx_volume - @initial_volume) * ratio
(SoundManager.sfx_volume - @initial_volume) * ratio
end
def update

View File

@@ -3,14 +3,50 @@
class IMICFPS
class Boot < GameState
def setup
@title = Text.new(IMICFPS::NAME, size: 100, z: 0, color: Gosu::Color.new(0xff000000), shadow: false, font: "Droid Serif")
@title = Text.new(IMICFPS::NAME, size: 100, z: 0, color: Gosu::Color.new(0xff000000), border: false, font: IMICFPS::BOLD_SANS_FONT)
@logo = get_image("#{IMICFPS::GAME_ROOT_PATH}/static/logo.png")
@title_screen_sound = get_sample("#{IMICFPS::GAME_ROOT_PATH}/static/sounds/title_screen.ogg")
@start_time = Gosu.milliseconds
@time_to_live = 3_000
@time_to_live = 5_000
timing = Gosu.milliseconds
@animators = [
@fade_animator = CyberarmEngine::Animator.new(
start_time: timing,
duration: 500,
from: 0.0,
to: 1.0,
tween: :ease_in_out
),
@logo_animator = CyberarmEngine::Animator.new(
start_time: timing += 500,
duration: 500,
from: 0.0,
to: 1.0,
tween: :swing_to#:bounce_past
),
@title_animator = CyberarmEngine::Animator.new(
start_time: timing += 1_000,
duration: 500,
from: 0.0,
to: 1.0,
tween: :swing_to#:ease_out_circ
),
@arc_animator = CyberarmEngine::Animator.new(
start_time: timing += 500,
duration: 2_500,
from: 0.0,
to: 1.0,
tween: :ease_in_out
)
]
# SoundManager.sound_effect(SoundEffect::FadeIn, sound: SoundManager.sound("base", :shield_regen), duration: 3_000.0)
window.needs_cursor = false
@title_screen_sound_channel = @title_screen_sound.play(1.0)
end
def draw
@@ -19,39 +55,45 @@ class IMICFPS
menu_background(Menu::PRIMARY_COLOR, Menu::ACCENT_COLOR, Menu::BAR_COLOR_STEP, Menu::BAR_ALPHA, Menu::BAR_SIZE, Menu::BAR_SLOPE)
if fraction_left <= 1.0
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.scale(@logo_animator.transition, @logo_animator.transition, window.width / 2, window.height / 2) do
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, fraction_left.clamp(0.0, 1.0), 128, 8, Gosu::Color.new(0x33ff8800)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, @arc_animator.transition, 128, 8, Gosu::Color.new(0x33ff8800)
)
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
end
@title.draw
fill(Gosu::Color.rgba(0, 0, 0, 255 * (1.2 - fraction_left)))
fill(Gosu::Color.rgba(0, 0, 0, 255 * (1 - @fade_animator.transition)))
end
end
def update
@animators.each(&:update)
y = window.height / 2 - (@logo.height / 2 + @title.height + 8)
y = 0 if y < @title.height
@title.x = window.width / 2 - @title.width / 2
@title.y = 0
@title.y = (0 - (@title.height * (1 - @title_animator.transition))) + (y * @title_animator.transition)
push_state(MainMenu) if Gosu.milliseconds - @start_time >= @time_to_live
end
def button_up(id)
if (id == Gosu::KbEscape) ||
((id >= Gosu::GP_LEFT) && (id >= Gosu::GP_BUTTON_15)) ||
(id == Gosu::MsLeft)
push_state(MainMenu)
end
def button_down(id)
super
@title_screen_sound_channel.stop
push_state(MainMenu)
end
end
end

View File

@@ -3,41 +3,63 @@
class IMICFPS
class Close < GameState
def setup
@slope = Menu::BAR_SLOPE
@logo = get_image("#{IMICFPS::GAME_ROOT_PATH}/static/logo.png")
@start_time = Gosu.milliseconds
@time_to_live = 3_000
@time_to_live = 3_750
timing = Gosu.milliseconds
@animators = [
@arc_animator = CyberarmEngine::Animator.new(
start_time: timing += 0,
duration: 2_500,
from: 1.0,
to: 0.0,
tween: :ease_in_out
),
@logo_animator = CyberarmEngine::Animator.new(
start_time: timing += 2_500,
duration: 500,
from: 1.0,
to: 0.0,
tween: :swing_from
),
@fade_animator = CyberarmEngine::Animator.new(
start_time: timing += 500,
duration: 500,
from: 0.0,
to: 1.0,
tween: :ease_in_out
),
]
window.needs_cursor = false
end
def draw
fraction_left = 1 - ((Gosu.milliseconds - @start_time) / (@time_to_live - 200).to_f)
menu_background(Menu::PRIMARY_COLOR, Menu::ACCENT_COLOR, Menu::BAR_COLOR_STEP, Menu::BAR_ALPHA, Menu::BAR_SIZE, Menu::BAR_SLOPE)
menu_background(Menu::PRIMARY_COLOR, Menu::ACCENT_COLOR, Menu::BAR_COLOR_STEP, Menu::BAR_ALPHA, Menu::BAR_SIZE, @slope.round)
Gosu.scale(@logo_animator.transition, @logo_animator.transition, window.width / 2, window.height / 2) do
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.draw_circle(
window.width / 2,
window.height / 2,
@logo.width / 2, 128, Gosu::Color.new(0x11ffffff)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, @arc_animator.transition, 128, 8, Gosu::Color.new(0x33ff8800)
)
Gosu.draw_arc(
window.width / 2,
window.height / 2,
@logo.width / 2, fraction_left.clamp(0.0, 1.0), 128, 8, Gosu::Color.new(0x33ff8800)
)
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
end
@logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 0)
fill(Gosu::Color.rgba(0, 0, 0, 255 * (1.1 - fraction_left)))
fill(Gosu::Color.rgba(0, 0, 0, 255 * @fade_animator.transition))
end
def update
window.close! if Gosu.milliseconds - @start_time >= @time_to_live
@slope -= 25 * window.dt
end
def button_up(id)

View File

@@ -27,7 +27,7 @@ class IMICFPS
def draw
window.director.map.render(@camera)
@hud.draw
@hud.draw if window.config.get(:options, :hud)
end
def update
@@ -69,6 +69,8 @@ class IMICFPS
window.director.map.entities.each do |entity|
entity.button_down(id) if defined?(entity.button_down)
end
@hud.button_down(id)
end
def button_up(id)
@@ -81,6 +83,8 @@ class IMICFPS
window.director.map.entities.each do |entity|
entity.button_up(id) if defined?(entity.button_up)
end
@hud.button_up(id)
end
end
end

View File

@@ -22,8 +22,8 @@ class IMICFPS
@assets = []
@asset_index = 0
add_asset(:model, @map_parser.terrain.package, @map_parser.terrain.name)
add_asset(:model, @map_parser.skydome.package, @map_parser.skydome.name)
add_asset(:model, @map_parser.terrain.package, @map_parser.terrain.name) if @map_parser.terrain.package
add_asset(:model, @map_parser.skydome.package, @map_parser.skydome.name) if @map_parser.skydome.package
@map_parser.entities.each do |entity|
add_asset(:model, entity.package, entity.name)
end

View File

@@ -17,17 +17,19 @@ class IMICFPS
@manifests.sort_by! { |m| m.name.downcase }
label IMICFPS::NAME.to_s, text_size: 100, color: Gosu::Color::BLACK
label "Asset Viewer", text_size: 50
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
button "Back", width: 1.0 do
pop_state
end
end
stack(width: 0.5, height: 1.0) do
title "Asset Viewer"
link I18n.t("menus.back"), width: 1.0 do
pop_state
end
flow(width: 1.0, height: 1.0) do
@manifests.each do |manifest|
button manifest.name do

View File

@@ -3,16 +3,14 @@
class IMICFPS
class AssetViewerTool
class TurnTable < CyberarmEngine::GuiState
include LightManager
attr_reader :map
def setup
window.needs_cursor = false
@manifest = @options[:manifest]
@map = ProtoMap.new
Publisher.new
window.director.load_map(map_parser: MapParser.new(map_file: "#{GAME_ROOT_PATH}/maps/model_viewer.json"))
@map = window.director.map
@entity = Entity.new(manifest: @manifest)
@entity.bind_model
@@ -20,16 +18,15 @@ class IMICFPS
@map.entities.each { |e| e.backface_culling = false }
@crosshair = Crosshair.new(color: Gosu::Color.rgba(100, 200, 255, 100))
@lights = []
@light = Light.new(type: Light::DIRECTIONAL, id: available_light, position: Vector.new, diffuse: Vector.new(1, 1, 1, 1))
@lights << @light
@map.add_light @light = Light.new(type: Light::DIRECTIONAL, id: @map.available_light, position: Vector.new, diffuse: Vector.new(1, 1, 1, 1))
@camera = PerspectiveCamera.new(aspect_ratio: window.aspect_ratio, position: Vector.new(0, 1.5, 5), orientation: Vector.forward)
@camera_controller = CameraController.new(camera: @camera, entity: nil, mode: :fpv)
label @manifest.name, text_size: 50
label @manifest.model
@camera_position = label ""
@camera_orientation = label ""
banner @manifest.name, text_size: 50, text_border: true, text_border_color: Gosu::Color::BLACK
tagline @manifest.model, text_border: true, text_border_color: Gosu::Color::BLACK
@camera_position = tagline "", text_border: true, text_border_color: Gosu::Color::BLACK
@camera_orientation = tagline "", text_border: true, text_border_color: Gosu::Color::BLACK
button "Back" do
pop_state
@@ -48,7 +45,7 @@ class IMICFPS
)
Gosu.gl do
window.renderer.draw(@camera, [@light], @map.entities)
window.renderer.draw(@camera, @map.lights, @map.entities)
end
@crosshair.draw
@@ -64,30 +61,24 @@ class IMICFPS
@camera_position.value = "Camera Position: X #{@camera.position.x.round(2)}, Y #{@camera.position.y.round(2)}, Z #{@camera.position.z.round(2)}"
@camera_orientation.value = "Camera Orientation: X #{@camera.orientation.x.round(2)}, Y #{@camera.orientation.y.round(2)}, Z #{@camera.orientation.z.round(2)}\nEntities: #{@map.entities.count}"
@map.entities.each(&:update)
@camera_controller.free_move
@camera_controller.update
# @map.entities.each(&:update)
end
def button_down(id)
super
InputMapper.keydown(id)
@camera_controller.button_down(id)
end
def button_up(id)
super
InputMapper.keyup(id)
end
end
# Stub for enabling scripted models to load properly
class ProtoMap
include EntityManager
attr_reader :entities
def initialize
@entities = []
@camera_controller.button_up(id)
end
end
end

View File

@@ -29,7 +29,7 @@ class IMICFPS
def update
super
Publisher.instance.publish(:tick, Gosu.milliseconds - window.delta_time)
Publisher.instance.publish(:tick, window.delta_time)
control_editor

View File

@@ -6,9 +6,6 @@ class IMICFPS
def setup
window.needs_cursor = true
label IMICFPS::NAME.to_s, text_size: 50
label "Map Editor", text_size: 28
@maps = []
Dir.glob("#{GAME_ROOT_PATH}/maps/*.json").each do |map|
begin
@@ -22,15 +19,20 @@ class IMICFPS
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
button "New Map", width: 1.0
button "Back", margin_top: 64, width: 1.0 do
pop_state
end
end
stack(width: 0.5, height: 1.0) do
label "Edit Map"
title "Map Editor"
flow width: 1.0 do
link I18n.t("menus.back"), width: 0.32 do
pop_state
end
button "New Map", width: 0.64
end
banner "Edit Map", width: 1.0, text_align: :center, text_size: 50
flow(width: 1.0, height: 1.0) do
@maps.each do |map|
button map.metadata.name do

View File

@@ -25,11 +25,7 @@ class IMICFPS
end
def insert_leaf(leaf)
@root = if @root
@root.insert_subtree(leaf)
else
leaf
end
@root = @root ? @root.insert_subtree(leaf) : leaf
end
def update(object, bounding_box)

View File

@@ -1,158 +0,0 @@
# frozen_string_literal: true
class IMICFPS
class Commands
module Style
def self.error(string)
"<c=ff5555>#{string}</c>"
end
def self.warn(string)
"<c=ff7700>#{string}</c>"
end
def self.notice(string)
"<c=55ff55>#{string}</c>"
end
def self.highlight(string, color = "5555ff")
"<c=#{color}>#{string}</c>"
end
end
class Command
def self.inherited(subclass)
@list ||= []
@commands ||= []
@list << subclass
end
def self.setup
@list ||= []
@commands = []
@list.each do |subclass|
cmd = subclass.new
if @commands.detect { |c| c.command == cmd.command }
raise "Command '#{cmd.command}' from '#{cmd.class}' already exists!"
end
@commands << cmd
end
end
def self.use(command, arguments, console)
found_command = @commands.detect { |cmd| cmd.command == command.to_sym }
if found_command
found_command.handle(arguments, console)
else
console.stdin("Command #{Style.error(command)} not found.")
end
end
def self.find(command)
@commands.detect { |cmd| cmd.command == command.to_sym }
end
def self.list_commands
@commands
end
def initialize
@store = {}
@subcommands = []
setup
end
def setup
end
def subcommand(command, type)
if @subcommands.detect { |subcmd| subcmd.command == command.to_sym }
raise "Subcommand '#{command}' for '#{self.command}' already exists!"
end
@subcommands << SubCommand.new(self, command, type)
end
def get(key)
@store[key]
end
def set(key, value)
@store[key] = value
end
def group
raise NotImplementedError
end
def command
raise NotImplementedError
end
def handle(arguments, console)
raise NotImplementedError
end
def autocomplete(console)
split = console.text_input.text.split(" ")
if @subcommands.size.positive?
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.positive?
console.stdin(list.map { |cmd| Commands::Style.highlight(cmd) }.join(", ").to_s)
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} "
elsif list.size.positive?
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
def handle_subcommand(arguments, console)
if arguments.size.zero?
console.stdin(usage)
return
end
subcommand = arguments.delete_at(0)
found_command = @subcommands.detect { |cmd| cmd.command == subcommand.to_sym }
if found_command
found_command.handle(arguments, console)
else
console.stdin("Unknown subcommand #{Style.error(subcommand)} for #{Style.highlight(command)}")
end
end
def usage
raise NotImplementedError
end
end
end
end

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class ConnectCommand < Command
class ConnectCommand < CyberarmEngine::Console::Command
def group
:global
end
@@ -15,7 +15,7 @@ class IMICFPS
end
def usage
"Connect to a server.\n#{Style.highlight('connect')} #{Style.notice('[example.com:56789]')}"
"Connect to a server.\n#{Console::Style.highlight('connect')} #{Style.notice('example.com[:56789]')}"
end
end
end

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class DebugCommand < Command
class DebugCommand < CyberarmEngine::Console::Command
def group
:global
end
@@ -12,20 +12,20 @@ class IMICFPS
end
def set(key, value)
$window.config[:debug_options, key] = value
CyberarmEngine::Window.instance.config[:debug_options, key] = value
end
def get(key)
$window.config.get(:debug_options, key)
CyberarmEngine::Window.instance.config.get(:debug_options, key)
end
def setup
set(:boundingboxes, false) if $window.config.get(:debug_options, :boundingboxes).nil?
set(:wireframe, false) if $window.config.get(:debug_options, :wireframe).nil?
set(:stats, false) if $window.config.get(:debug_options, :stats).nil?
set(:skydome, true) if $window.config.get(:debug_options, :skydome).nil?
set(:use_shaders, true) if $window.config.get(:debug_options, :use_shaders).nil?
set(:opengl_error_panic, false) if $window.config.get(:debug_options, :opengl_error_panic).nil?
set(:boundingboxes, false) if CyberarmEngine::Window.instance.config.get(:debug_options, :boundingboxes).nil?
set(:wireframe, false) if CyberarmEngine::Window.instance.config.get(:debug_options, :wireframe).nil?
set(:stats, false) if CyberarmEngine::Window.instance.config.get(:debug_options, :stats).nil?
set(:skydome, true) if CyberarmEngine::Window.instance.config.get(:debug_options, :skydome).nil?
set(:use_shaders, true) if CyberarmEngine::Window.instance.config.get(:debug_options, :use_shaders).nil?
set(:opengl_error_panic, false) if CyberarmEngine::Window.instance.config.get(:debug_options, :opengl_error_panic).nil?
subcommand(:boundingboxes, :boolean)
subcommand(:wireframe, :boolean)

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class DisconnectCommand < Command
class DisconnectCommand < CyberarmEngine::Console::Command
def group
:global
end

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class FPSCommand < Command
class FPSCommand < CyberarmEngine::Console::Command
def group
:global
end
@@ -13,26 +13,26 @@ class IMICFPS
def handle(arguments, console)
if arguments.size > 1
console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.")
console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.")
return
end
case arguments.last
when "", nil
console.stdin("#{Style.highlight('fps')}: #{$window.config.get(:options, :fps)}")
console.stdin("#{Console::Style.highlight('fps')}: #{CyberarmEngine::Window.instance.config.get(:options, :fps)}")
when "on"
var = $window.config[:options, :fps] = true
console.stdin("fps => #{Style.highlight(var)}")
var = CyberarmEngine::Window.instance.config[:options, :fps] = true
console.stdin("fps => #{Console::Style.highlight(var)}")
when "off"
var = $window.config[:options, :fps] = false
console.stdin("fps => #{Style.highlight(var)}")
var = CyberarmEngine::Window.instance.config[:options, :fps] = false
console.stdin("fps => #{Console::Style.highlight(var)}")
else
console.stdin("Invalid argument for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.last)} expected #{Style.notice('on')}, or #{Style.notice('off')}.")
console.stdin("Invalid argument for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.last)} expected #{Console::Style.notice('on')}, or #{Console::Style.notice('off')}.")
end
end
def usage
"#{Style.highlight('fps')} #{Style.notice('[on|off]')}"
"#{Console::Style.highlight('fps')} #{Style.notice('[on|off]')}"
end
end
end

View File

@@ -1,43 +0,0 @@
# frozen_string_literal: true
class IMICFPS
class Commands
class HelpCommand < Command
def group
:global
end
def command
:help
end
def handle(arguments, console)
console.stdin(usage(arguments.first))
end
def autocomplete(console)
split = console.text_input.text.split(" ")
if !console.text_input.text.start_with?(" ") && split.size == 2
list = console.abbrev_search(Commands::Command.list_commands.map { |cmd| cmd.command.to_s }, split.last)
if list.size == 1
console.text_input.text = "#{split.first} #{list.first} "
elsif list.size > 1
console.stdin(list.map { |cmd| Style.highlight(cmd) }.join(", "))
end
end
end
def usage(command = nil)
if command
if cmd = Command.find(command)
cmd.usage
else
"#{Style.error(command)} is not a command"
end
else
"Available commands:\n#{Command.list_commands.map { |cmd| Style.highlight(cmd.command).to_s }.join(', ')}"
end
end
end
end
end

View File

@@ -0,0 +1,43 @@
# frozen_string_literal: true
class IMICFPS
class Commands
class HUDCommand < CyberarmEngine::Console::Command
def group
:global
end
def command
:hud
end
def setup
CyberarmEngine::Window.instance.config[:options, :hud] = true if CyberarmEngine::Window.instance.config.get(:options, :hud).nil?
end
def handle(arguments, console)
if arguments.size > 1
console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.")
return
end
case arguments.last
when "", nil
console.stdin("#{Console::Style.highlight(command.to_s)}: #{CyberarmEngine::Window.instance.config.get(:options, command)}")
when "on"
var = CyberarmEngine::Window.instance.config[:options, command] = true
console.stdin("#{command} => #{Console::Style.highlight(var)}")
when "off"
var = CyberarmEngine::Window.instance.config[:options, command] = false
console.stdin("#{command} => #{Console::Style.highlight(var)}")
else
console.stdin("Invalid argument for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.last)} expected #{Console::Style.notice('on')}, or #{Console::Style.notice('off')}.")
end
end
def usage
"#{Console::Style.highlight('hud')} #{Console::Style.notice('[on|off]')}"
end
end
end
end

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class ReloadShaderCommand < Command
class ReloadShaderCommand < CyberarmEngine::Console::Command
def group
:reload_shader
end
@@ -13,7 +13,7 @@ class IMICFPS
def handle(arguments, console)
if arguments.size > 2
console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.")
console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.")
return
end
@@ -51,9 +51,9 @@ class IMICFPS
string = $stdout.string
if shader.compiled?
console.stdin("#{Style.notice('Successfully reloaded shader')}: #{shader.name}")
console.stdin("#{Console::Style.notice('Successfully reloaded shader')}: #{shader.name}")
else
console.stdin(Style.error("Failed to reload #{shader.name}").to_s)
console.stdin(Console::Style.error("Failed to reload #{shader.name}").to_s)
console.stdin(string)
end
ensure
@@ -62,7 +62,7 @@ class IMICFPS
end
def usage
"#{Style.highlight(command)} #{Style.notice('vertex_name [fragment_name]')}"
"#{Console::Style.highlight(command)} #{Console::Style.notice('vertex_name [fragment_name]')}"
end
end
end

View File

@@ -2,7 +2,7 @@
class IMICFPS
class Commands
class RendererInfoCommand < Command
class RendererInfoCommand < CyberarmEngine::Console::Command
def group
:global
end
@@ -12,14 +12,14 @@ class IMICFPS
end
def handle(_arguments, console)
console.stdin("OpenGL Vendor: #{Style.notice(glGetString(GL_VENDOR))}")
console.stdin("OpenGL Renderer: #{Style.notice(glGetString(GL_RENDERER))}")
console.stdin("OpenGL Version: #{Style.notice(glGetString(GL_VERSION))}")
console.stdin("OpenGL Shader Language Version: #{Style.notice(glGetString(GL_SHADING_LANGUAGE_VERSION))}")
console.stdin("OpenGL Vendor: #{Console::Style.notice(glGetString(GL_VENDOR))}")
console.stdin("OpenGL Renderer: #{Console::Style.notice(glGetString(GL_RENDERER))}")
console.stdin("OpenGL Version: #{Console::Style.notice(glGetString(GL_VERSION))}")
console.stdin("OpenGL Shader Language Version: #{Console::Style.notice(glGetString(GL_SHADING_LANGUAGE_VERSION))}")
end
def usage
"#{Style.highlight('renderer_info')} #{Style.notice('Returns OpenGL renderer information')}"
"#{Console::Style.highlight('renderer_info')} #{Console::Style.notice('Returns OpenGL renderer information')}"
end
end
end

View File

@@ -1,250 +0,0 @@
# frozen_string_literal: true
class IMICFPS
class Console
Z = 100_000
PADDING = 2
include CommonMethods
attr_reader :text_input
def initialize
@text_input = Gosu::TextInput.new
@width = window.width / 4 * 3
@height = window.height / 4 * 3
@input = Text.new("", x: 4, y: @height - (PADDING * 2), z: Console::Z + 1, font: MONOSPACE_FONT)
@input.y -= @input.height
@history = Text.new("=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n", x: 4, z: Console::Z + 1, font: MONOSPACE_FONT)
update_history_y
@command_history = []
@command_history_index = 0
@memory = ""
@background_color = Gosu::Color.rgba(0, 0, 0, 200)
@foreground_color = Gosu::Color.rgba(100, 100, 100, 100)
@input_color = Gosu::Color.rgba(100, 100, 100, 200)
@showing_cursor = false
@active_text_input = nil
@show_caret = true
@caret_last_change = Gosu.milliseconds
@caret_interval = 250
@caret_color = Gosu::Color::WHITE
@selection_color = Gosu::Color.new(0x5522ff22)
end
def draw
# Background/Border
draw_rect(0, 0, @width, @height, @background_color, Console::Z)
# Foregound/History
draw_rect(PADDING, PADDING, @width - (PADDING * 2), @height - (PADDING * 2), @foreground_color, Console::Z)
# Text bar
draw_rect(2, @input.y, @width - (PADDING * 2), @input.height, @input_color, Console::Z)
@history.draw
@input.draw
# Caret
if @show_caret
draw_rect(@input.x + caret_from_left, @input.y, Console::PADDING, @input.height, @caret_color, Console::Z + 2)
end
# 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.zero?
@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
def caret_pos
@text_input.caret_pos
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
def update
if Gosu.milliseconds - @caret_last_change >= @caret_interval
@caret_last_change = Gosu.milliseconds
@show_caret = !@show_caret
end
if @width != window.width || @height != @height
@width = window.width / 4 * 3
@height = window.height / 4 * 3
@input.y = @height - (PADDING * 2 + @input.height)
update_history_y
end
@input.text = @text_input.text
end
def button_down(id)
case id
when Gosu::KbEnter, Gosu::KbReturn
return unless @text_input.text.length.positive?
@history.text += "\n<c=999999>> #{@text_input.text}</c>"
@command_history << @text_input.text
@command_history_index = @command_history.size
update_history_y
handle_command
@text_input.text = ""
when Gosu::KbUp
@command_history_index -= 1
@command_history_index = 0 if @command_history_index.negative?
@text_input.text = @command_history[@command_history_index]
when Gosu::KbDown
@command_history_index += 1
if @command_history_index > @command_history.size - 1
@text_input.text = "" unless @command_history_index > @command_history.size
@command_history_index = @command_history.size
else
@text_input.text = @command_history[@command_history_index]
end
when Gosu::KbTab
split = @text_input.text.split(" ")
if !@text_input.text.end_with?(" ") && split.size == 1
list = abbrev_search(Commands::Command.list_commands.map { |cmd| cmd.command.to_s }, @text_input.text)
if list.size == 1
@text_input.text = "#{list.first} "
elsif list.size.positive?
stdin("\n#{list.map { |cmd| Commands::Style.highlight(cmd) }.join(', ')}")
end
elsif split.size.positive? && cmd = Commands::Command.find(split.first)
cmd.autocomplete(self)
end
when Gosu::KbBacktick
# Remove backtick character from input
@text_input.text = if @text_input.text.size > 1
@text_input.text[0..@text_input.text.size - 2]
else
""
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
@history.text = "" if control_down?
end
end
def button_up(id)
end
def update_history_y
@history.y = @height - (PADDING * 2) - @input.height - (@history.text.lines.count * @history.textobject.height)
end
def handle_command
string = @text_input.text
split = string.split(" ")
command = split.first
arguments = split.length.positive? ? split[1..split.length - 1] : []
IMICFPS::Commands::Command.use(command, arguments, self)
end
def abbrev_search(array, text)
return [] unless text.length.positive?
list = []
Abbrev.abbrev(array).each do |abbrev, value|
next unless abbrev&.start_with?(text)
list << value
end
list.uniq
end
def stdin(string)
@history.text += "\n#{string}"
update_history_y
end
def focus
InputMapper.reset_keys
@active_text_input = window.text_input
window.text_input = @text_input
@showing_cursor = window.needs_cursor
window.needs_cursor = true
@show_caret = true
@caret_last_change = Gosu.milliseconds
end
def blur
window.text_input = @active_text_input
window.needs_cursor = @showing_cursor
end
end
end

View File

@@ -22,7 +22,9 @@ class IMICFPS
@accent_color = ACCENT_COLOR
window.needs_cursor = true
@__version_text = CyberarmEngine::Text.new("<b>#{IMICFPS::NAME}</b> v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME})", font: BOLD_SANS_FONT)
@__version_text = CyberarmEngine::Text.new(
"<b>#{IMICFPS::NAME}</b> v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME})",
font: BOLD_SANS_FONT, border: true, border_color: Gosu::Color::BLACK)
@__version_text.x = window.width - (@__version_text.width + 10)
@__version_text.y = window.height - (@__version_text.height + 10)
@@ -39,7 +41,9 @@ class IMICFPS
text_size: 100,
color: Gosu::Color::BLACK,
text_align: :center,
width: 1.0
text_shadow: true,
text_shadow_size: 4,
width: 1.0,
},
Subtitle: {
text_size: 50,
@@ -51,10 +55,10 @@ class IMICFPS
font: BOLD_SANS_FONT,
text_size: 50,
text_align: :center,
text_shadow: true,
text_shadow_size: 2,
text_shadow_color: Gosu::Color::BLACK,
text_shadow_alpha: 100,
text_border: true,
text_border_size: 2,
text_border_color: Gosu::Color::BLACK,
text_border_alpha: 100,
color: Gosu::Color.rgb(0, 127, 127),
width: 1.0,
hover: {
@@ -62,7 +66,10 @@ class IMICFPS
},
active: {
color: Gosu::Color.rgb(64, 128, 255),
}
},
disabled: {
color: Gosu::Color.rgb(175, 175, 175),
},
},
Button:
{
@@ -86,6 +93,8 @@ class IMICFPS
}
}
)
SoundManager.play_playlist("base", "menus")
end
def draw

View File

@@ -3,8 +3,7 @@
class IMICFPS
class ExtrasMenu < Menu
def setup
title IMICFPS::NAME
subtitle "Extras"
title I18n.t("menus.extras")
link "Asset Viewer" do
push_state(IMICFPS::AssetViewerTool::MainMenu)
@@ -14,7 +13,7 @@ class IMICFPS
push_state(IMICFPS::MapEditorTool::MainMenu)
end
link I18n.t("menus.back") do
link I18n.t("menus.back"), margin_top: 25 do
pop_state
end
end

View File

@@ -4,8 +4,7 @@ class IMICFPS
class GamePauseMenu < Menu
def setup
@bar_alpha = 50
title IMICFPS::NAME
subtitle "Paused"
title "Paused"
link "Resume" do
pop_state
@@ -15,7 +14,7 @@ class IMICFPS
push_state(SettingsMenu)
end
link I18n.t("menus.leave") do
link I18n.t("menus.leave"), margin_top: 25 do
push_state(MainMenu)
end
end

View File

@@ -3,10 +3,12 @@
class IMICFPS
class LevelSelectMenu < Menu
def setup
title IMICFPS::NAME
title I18n.t("menus.singleplayer")
subtitle "Choose a Map"
Dir.glob("#{GAME_ROOT_PATH}/maps/*.json").map { |file| [file, MapParser.new(map_file: file)] }.each do |file, map|
next unless map.metadata.gamemode
link map.metadata.name do
push_state(
LoadingState.new(forward: Game, map_file: file)
@@ -14,7 +16,7 @@ class IMICFPS
end
end
link I18n.t("menus.back") do
link I18n.t("menus.back"), margin_top: 25 do
pop_state
end
end

View File

@@ -6,7 +6,7 @@ class IMICFPS
title IMICFPS::NAME
link I18n.t("menus.singleplayer") do
push_state(LevelSelectMenu)
push_state(SinglePlayerMenu)
end
link I18n.t("menus.multiplayer") do
@@ -21,7 +21,7 @@ class IMICFPS
push_state(ExtrasMenu)
end
link I18n.t("menus.quit") do
link I18n.t("menus.quit"), margin_top: 25 do
window.close
end
@@ -40,14 +40,17 @@ Fallback <b>immediate mode renderer</b> will be used."
(Linux Only) For MESA based drivers append <b>--mesa-override</b>
as a commandline argument to override reported version."
message += linux_mesa_message if RUBY_PLATFORM =~ /linux/ && gl_version.downcase.include?(" mesa ")
@old_gl_warning = Gosu::Image.from_markup(message, 24, align: :center, font: "")
@old_gl_warning = Text.new(message, size: 24, z: Float::INFINITY, border: true, border_color: Gosu::Color::BLACK)
end
end
def draw
super
@old_gl_warning&.draw(window.width / 2 - @old_gl_warning.width / 2, window.height - (@old_gl_warning.height + 10), Float::INFINITY)
@old_gl_warning&.x = window.width / 2 - @old_gl_warning.width / 2
@old_gl_warning&.y = window.height - (@old_gl_warning.height + 10)
@old_gl_warning&.draw
end
end
end

View File

@@ -3,8 +3,7 @@
class IMICFPS
class MultiplayerMenu < Menu
def setup
title IMICFPS::NAME
subtitle "Multiplayer"
title I18n.t("menus.multiplayer")
link "Quick Join"
link "Server Browser" do
@@ -13,7 +12,7 @@ class IMICFPS
link "Profile" do
push_state(MultiplayerProfileMenu)
end
link I18n.t("menus.back") do
link I18n.t("menus.back"), margin_top: 25 do
pop_state
end
end

View File

@@ -3,47 +3,52 @@
class IMICFPS
class MultiplayerProfileMenu < Menu
def setup
label "Profile", text_size: 100, color: Gosu::Color::BLACK
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
button "Edit Profile", width: 1.0
button "Log Out", width: 1.0
button I18n.t("menus.back"), width: 1.0, margin_top: 64 do
pop_state
end
end
stack(width: 0.5, height: 1.0) do
title "Profile"
flow width: 1.0 do
link I18n.t("menus.back"), width: 0.333 do
pop_state
end
button "Edit Profile", width: 0.333
button "Log Out", width: 0.333
end
flow(width: 1.0, padding: 4) do
background 0x88_222222
image "#{GAME_ROOT_PATH}/static/logo.png", width: 64
stack do
label "[Clan TAG] Username", text_size: 36
label "\"Title Badge Thingy\""
tagline "[Clan TAG] Username", text_size: 36
tagline "\"Title Badge Thingy\""
end
end
flow(margin_top: 4, margin_right: 4) do
flow(margin_top: 4, width: 1.0) do
stack do
label "Kiil/Death Ratio"
label "Kills"
label "Deaths"
label "Assists"
label "Buildings Destroyed"
label "Vehicles Destroyed"
label "Repair Points"
tagline "Kiil/Death Ratio"
tagline "Kills"
tagline "Deaths"
tagline "Assists"
tagline "Buildings Destroyed"
tagline "Vehicles Destroyed"
tagline "Repair Points"
end
stack do
label "0.72"
label "21"
label "28"
label "14"
label "111"
label "41"
label "4,451"
stack margin_left: 16 do
tagline "0.75"
tagline "21"
tagline "28"
tagline "14"
tagline "111"
tagline "41"
tagline "4,451"
end
end
end

View File

@@ -30,48 +30,54 @@ class IMICFPS
}
]
label "Server Browser", text_size: 100
flow width: 1.0, height: 1.0 do
flow(width: 1.0, height: 1.0) do
stack width: 0.25 do
button "Host Game", width: 1.0
button "Direct Connect", width: 1.0
button I18n.t("menus.back"), width: 1.0, margin_top: 64 do
pop_state
end
end
stack width: 0.5, height: 1.0 do
stack width: 1.0, height: 0.75, border_color: 0xffffffff, border_thickness: 1 do
stack width: 1.0, height: 0.25 do
title "Server Browser"
flow(width: 1.0) do
link I18n.t("menus.back"), width: 0.333 do
pop_state
end
button "Host Game", width: 0.333
button "Direct Connect", width: 0.333
end
end
stack width: 1.0, height: 0.5, border_color: 0xffffffff, border_thickness: 1 do
@sample_games.each_with_index do |game, i|
text_size = 18
flow width: 1.0 do
background i.even? ? 0x55000000 : 0x55ff5500
flow width: 0.1 do
label game[:game_type], text_size: text_size
tagline game[:game_type], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
flow width: 0.3 do
label game[:host], text_size: text_size
tagline game[:host], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
flow width: 0.3 do
label game[:map], text_size: text_size
tagline game[:map], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
flow width: 0.1 do
label game[:players], text_size: text_size
tagline game[:players], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
flow width: 0.1 do
label game[:ping], text_size: text_size
tagline game[:ping], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
flow width: 0.1 do
label game[:source], text_size: text_size
tagline game[:source], text_size: text_size, text_wrap: :none, font: i.zero? ? BOLD_SANS_FONT : SANS_FONT
end
end
end
end
flow width: 1.0, height: 0.25 do
label "Name"
tagline "Name"
name = edit_line "", margin_right: 20
button "Join", width: 0.25 do
pp name.value

View File

@@ -5,209 +5,234 @@ class IMICFPS
include CommonMethods
def self.set_defaults
if $window.config.get(:options, :audio, :volume_sound).nil?
$window.config[:options, :audio, :volume_sound] = 1.0
if CyberarmEngine::Window.instance.config.get(:options, :audio, :volume_master).nil?
CyberarmEngine::Window.instance.config[:options, :audio, :volume_master] = 1.0
end
if $window.config.get(:options, :audio, :volume_music).nil?
$window.config[:options, :audio, :volume_music] = 0.7
if CyberarmEngine::Window.instance.config.get(:options, :audio, :volume_sound_effects).nil?
CyberarmEngine::Window.instance.config[:options, :audio, :volume_sound_effects] = 1.0
end
if $window.config.get(:options, :audio, :volume_dialogue).nil?
$window.config[:options, :audio, :volume_dialogue] = 0.7
if CyberarmEngine::Window.instance.config.get(:options, :audio, :volume_music).nil?
CyberarmEngine::Window.instance.config[:options, :audio, :volume_music] = 0.7
end
if CyberarmEngine::Window.instance.config.get(:options, :audio, :volume_dialogue).nil?
CyberarmEngine::Window.instance.config[:options, :audio, :volume_dialogue] = 0.7
end
end
def setup
@categories = %w[
Display
Graphics
Audio
Controls
Multiplayer
]
@pages = {}
@current_page = nil
label "Settings", text_size: 100, color: Gosu::Color::BLACK
flow(width: 1.0, height: 1.0) do
stack(width: 0.25, height: 1.0) do
@categories.each do |category|
button category, width: 1.0 do
show_page(:"#{category}".downcase)
end
stack(fill: true, height: 1.0) do
title "Settings", width: 1.0, text_align: :center
stack(width: 1.0, height: 96) do
flow(width: 1.0) do
link I18n.t("menus.back"), width: nil do
pop_state
end
flow(fill: true)
button get_image("#{GAME_ROOT_PATH}/static/icons/settings_display.png"), image_width: 64, tip: I18n.t("settings.display") do
show_page(:display)
end
button get_image("#{GAME_ROOT_PATH}/static/icons/settings_graphics.png"), image_width: 64, tip: I18n.t("settings.graphics") do
show_page(:graphics)
end
button get_image("#{GAME_ROOT_PATH}/static/icons/settings_audio.png"), image_width: 64, tip: I18n.t("settings.audio") do
show_page(:audio)
end
button get_image("#{GAME_ROOT_PATH}/static/icons/settings_controls.png"), image_width: 64, tip: I18n.t("settings.controls") do
show_page(:controls)
end
button get_image("#{GAME_ROOT_PATH}/static/icons/settings_multiplayer.png"), image_width: 64, tip: I18n.t("settings.multiplayer") do
show_page(:multiplayer)
end
end
end
button I18n.t("menus.back"), width: 1.0, margin_top: 64 do
pop_state
@page_container = stack(width: 1.0, fill: true, scroll: true, padding: 10) do
end
end
@categories.each do |category|
stack(width: 0.5, height: 1.0) do |element|
@pages[:"#{category}".downcase] = element
element.hide
send(:"create_page_#{category}".downcase) if respond_to?(:"create_page_#{category}".downcase)
end
stack(width: 0.25, height: 1.0) do
end
end
# @categories.each do |category|
# stack(width: 0.5, height: 1.0) do |element|
# @pages[:"#{category}".downcase] = element
# element.hide
# send(:"create_page_#{category}".downcase) if respond_to?(:"create_page_#{category}".downcase)
# end
# end
# end
show_page(:display)
end
def show_page(page)
if element = @pages[page]
@current_page&.hide
@current_page = element
element.show
@page_container.clear do
send(:"page_#{page}")
end
@page_container.scroll_top = 0
end
def create_page_display
label "Display", text_size: 50
def page_display
banner "Display", text_size: 50
label "Resolution"
flow do
stack do
label "Width"
label "Height"
stack(width: 1.0, height: 128) do
flow(width: 1.0) do
tagline "Width", width: 96
edit_line window.width.to_s, fill: true
end
stack do
edit_line window.width.to_s
edit_line window.height.to_s
flow(width: 1.0) do
tagline "Height", width: 96
edit_line window.height.to_s, fill: true
end
end
check_box "Fullscreen", padding_top: 25, padding_bottom: 25
# check_box "Fullscreen", margin_top: 25, margin_bottom: 25, width: 1.0
stack do
longest_string = "Gamma Correction"
flow do
label "Gamma Correction".ljust(longest_string.length, " ")
@display_gamma_correction = slider range: 0.0..1.0, value: 0.5
stack(width: 1.0, height: 128, margin_top: 20) do
flow(width: 1.0, fill: true) do
tagline "Gamma Correction", width: 256
@display_gamma_correction = slider range: 0.0..1.0, value: 0.5, fill: true
@display_gamma_correction.subscribe(:changed) do |_sender, value|
@display_gamma_correction_label.value = value.round(1).to_s
end
@display_gamma_correction_label = label "0.0"
@display_gamma_correction_label = tagline "0.0"
end
flow do
label "Brightness".ljust(longest_string.length, " ")
@display_brightness = slider range: 0.0..1.0, value: 0.5
flow(width: 1.0, fill: true) do
tagline "Brightness", width: 256
@display_brightness = slider range: 0.0..1.0, value: 0.5, fill: true
@display_brightness.subscribe(:changed) do |_sender, value|
@display_brightness_label.value = value.round(1).to_s
end
@display_brightness_label = label "0.0"
@display_brightness_label = tagline "0.0"
end
flow do
label "Contrast".ljust(longest_string.length, " ")
@display_contrast = slider range: 0.0..1.0, value: 0.5
flow(width: 1.0, fill: true) do
tagline "Contrast", width: 256
@display_contrast = slider range: 0.0..1.0, value: 0.5, fill: true
@display_contrast.subscribe(:changed) do |_sender, value|
@display_contrast_label.value = value.round(1).to_s
end
@display_contrast_label = label "0.0"
@display_contrast_label = tagline "0.0"
end
end
end
def create_page_audio
label "Audio", text_size: 50
longest_string = "Dialogue".length
volumes = %i[sound music dialogue]
def page_audio
tagline "Audio", text_size: 50
volumes = %i[master sound_effects music dialogue]
stack do
stack(width: 1.0, height: 48 * volumes.count) do
volumes.each do |volume|
config_value = window.config.get(:options, :audio, :"volume_#{volume}")
flow do
label volume.to_s.split("_").join(" ").capitalize.ljust(longest_string, " ")
instance_variable_set(:"@volume_#{volume}", slider(range: 0.0..1.0, value: config_value))
flow(width: 1.0, fill: true, margin_bottom: 10) do
tagline volume.to_s.split("_").map(&:capitalize).join(" "), width: 172
instance_variable_set(:"@volume_#{volume}", slider(range: 0.0..1.0, value: config_value, fill: true))
instance_variable_get(:"@volume_#{volume}").subscribe(:changed) do |_sender, value|
instance_variable_get(:"@volume_#{volume}_label").value = format("%03.2f%%", value * 100.0)
window.config[:options, :audio, :"volume_#{volume}"] = value
end
instance_variable_set(:"@volume_#{volume}_label", label(format("%03.2f%%", config_value * 100.0)))
instance_variable_set(:"@volume_#{volume}_label", tagline(format("%03.2f%%", config_value * 100.0), width: 96, text_align: :right))
end
end
end
end
def create_page_controls
label "Controls", text_size: 50
def page_controls
tagline "Controls", text_size: 50
InputMapper.keymap.each do |key, values|
flow do
label key.to_s
flow(width: 1.0, height: 64) do
tagline key.to_s, width: 0.5, max_width: 312
[values].flatten.each do |value|
if name = Gosu.button_name(value)
else
unless (name = Gosu.button_name(value))
name = Gosu.constants.find { |const| Gosu.const_get(const) == value }
name = name.to_s.capitalize.split("_").join(" ") if name
end
button name
button name, fill: true
end
end
end
end
def create_page_graphics
label "Graphics", text_size: 50
def page_graphics
tagline "Graphics", text_size: 50
longest_string = "Surface Effect Detail"
check_box "V-Sync (Not Disableable, Yet.)", checked: true, enabled: false, width: 1.0
flow do
check_box "V-Sync (Not Disableable, Yet.)", checked: true, enabled: false
end
flow do
label "Field of View".ljust(longest_string.length, " ")
@fov = slider range: 70.0..110.0
flow(width: 1.0, height: 64) do
tagline "Field of View", width: 128
@fov = slider range: 70.0..110.0, fill: true
@fov.subscribe(:changed) do |_sender, value|
@fov_label.value = value.round.to_s
end
@fov_label = label "90.0"
@fov_label = tagline "90.0"
end
flow do
label "Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low], width: 250
flow(width: 1.0, height: 64) do
tagline "Detail", width: 128
list_box items: %i[high medium low], fill: true
end
label ""
advanced_mode = check_box "Advanced Settings"
label ""
advanced_mode = check_box "Advanced Settings", margin_top: 20, margin_bottom: 20
advanced_settings = stack width: 1.0 do |element|
advanced_settings = stack(width: 1.0) do |element|
element.hide
stack do
flow do
label "Geometry Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low], width: 250
stack(width: 1.0, height: 64 * 7) do
flow(width: 1.0, height: 64) do
tagline "Geometry Detail", width: 312
list_box items: %i[high medium low], fill: true
end
flow do
label "Shadow Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low off], width: 250
flow(width: 1.0, height: 64) do
tagline "Shadow Detail", width: 312
list_box items: %i[high medium low off], fill: true
end
flow do
label "Texture Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low], width: 250
flow(width: 1.0, height: 64) do
tagline "Texture Detail", width: 312
list_box items: %i[high medium low], fill: true
end
flow do
label "Particle Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low off], width: 250
flow(width: 1.0, height: 64) do
tagline "Particle Detail", width: 312
list_box items: %i[high medium low off], fill: true
end
flow do
label "Surface Effect Detail".ljust(longest_string.length, " ")
list_box items: %i[high medium low], width: 250
flow(width: 1.0, height: 64) do
tagline "Surface Effect Detail", width: 312
list_box items: %i[high medium low], fill: true
end
flow do
label "Lighting Mode".ljust(longest_string.length, " ")
list_box items: %i[per_pixel per_vertex], width: 250
flow(width: 1.0, height: 64) do
tagline "Lighting Mode", width: 312
list_box items: %i[per_pixel per_vertex], fill: true
end
flow do
label "Texture Filtering".ljust(longest_string.length, " ")
list_box items: [:none], width: 250
flow(width: 1.0, height: 64) do
tagline "Texture Filtering", width: 312
list_box items: [:none], fill: true
end
end
end
@@ -218,13 +243,14 @@ class IMICFPS
end
end
def create_page_multiplayer
label "Multiplayer", text_size: 50
def page_multiplayer
tagline "Multiplayer", text_size: 50
flow do
label "Player Name"
edit_line "player-#{SecureRandom.hex(2)}"
flow(width: 1.0, height: 64) do
tagline "Player Name", width: 172
edit_line "player-#{SecureRandom.hex(2)}", fill: true
end
check_box "Show player names"
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
class IMICFPS
class SinglePlayerMenu < Menu
def setup
title I18n.t("menus.singleplayer")
link "Tutorial", enabled: false, tip: "No tutorial implemented, yet..."
link "Campaign", enabled: false, tip: "No campaign, yet..."
link "Multiplayer Practice" do
push_state(LevelSelectMenu)
end
link I18n.t("menus.back"), margin_top: 25 do
pop_state
end
end
end
end

View File

@@ -1,100 +0,0 @@
# frozen_string_literal: true
class IMICFPS
class Commands
class Command
class SubCommand
def initialize(parent, command, type)
@parent = parent
@command = command
@type = type
end
attr_reader :command
def handle(arguments, console)
if arguments.size > 1
console.stdin("to many arguments for #{Style.highlight(command.to_s)}, 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) || 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.to_s)}, 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) || "\"\""
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) || "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) || "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 values
case @type
when :boolean
%w[on off]
else
[]
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

View File

@@ -2,17 +2,10 @@
class IMICFPS
class Window < CyberarmEngine::Window
attr_accessor :number_of_vertices, :needs_cursor
attr_accessor :needs_cursor
attr_reader :renderer, :scene, :config, :director, :console, :delta_time
def initialize(window_width = 1280, window_height = 720, fullscreen = false)
fps_target = ARGV.first.to_i != 0 ? ARGV.first.to_i : 60
if ARGV.join.include?("--native")
super(width: Gosu.screen_width, height: Gosu.screen_height, fullscreen: true, resizable: true, update_interval: 1000.0 / fps_target)
else
super(width: window_width, height: window_height, fullscreen: fullscreen, resizable: true, update_interval: 1000.0 / fps_target)
end
$window = self
def setup
I18n.load_path << Dir["#{GAME_ROOT_PATH}/locales/*.yml"]
I18n.default_locale = :en
language = Gosu.language.split("_").first.to_sym
@@ -29,11 +22,11 @@ class IMICFPS
@config = CyberarmEngine::ConfigFile.new(file: "#{IMICFPS::GAME_ROOT_PATH}/data/config.json")
@show_console = false
@console = Console.new
Commands::Command.setup
CyberarmEngine::Console::Command.setup
@console.stdin("=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n")
SettingsMenu.set_defaults
@renderer = Renderer.new
preload_default_shaders
@scene = TurnTableScene.new
@overlay = Overlay.new
@@ -43,21 +36,13 @@ class IMICFPS
@config.save!
end
push_state(Boot)
@delta_time = Gosu.milliseconds
push_state(CyberarmEngine::IntroState, forward: Boot)
end
def preload_default_shaders
shaders = %w[g_buffer lighting]
shaders.each do |shader|
Shader.new(
name: shader,
includes_dir: "shaders/include",
vertex: "shaders/vertex/#{shader}.glsl",
fragment: "shaders/fragment/#{shader}.glsl"
)
end
def input_hijack=(hijacker)
@input_hijacker = hijacker
InputMapper.reset_keys
end
def needs_cursor?
@@ -88,9 +73,6 @@ class IMICFPS
@console.update if @show_console
@overlay.update
SoundManager.update
@number_of_vertices = 0
@delta_time = Gosu.milliseconds
end
def close
@@ -100,12 +82,14 @@ class IMICFPS
def button_down(id)
if @show_console
@console.button_down(id)
elsif @input_hijacker
@input_hijacker.button_down(id)
else
super
end
if id == Gosu::KbBacktick
@show_console ? @console.blur : @console.focus
@show_console ? @console.blur : @console.focus && InputMapper.reset_keys
@show_console = !@show_console
end
end
@@ -113,6 +97,8 @@ class IMICFPS
def button_up(id)
if @show_console
@console.button_up(id)
elsif @input_hijacker
@input_hijacker.button_up(id)
else
super
end

View File

@@ -10,4 +10,10 @@ en:
back: Back
leave: Leave
paused: Paused
resume: Resume
resume: Resume
settings:
display: Display
graphics: Graphics
audio: Audio
controls: Controls
multiplayer: Multiplayer

30
maps/model_viewer.json Normal file
View File

@@ -0,0 +1,30 @@
{
"metadata": {
"name": "Model Viewer",
"gamemode": null,
"authors": [
"Cyberarm"
],
"datetime": "2021-04-25 22:51:00 UTC",
"thumbnail": "",
"description": "A map for the model viewer tool to use."
},
"entities": [],
"spawnpoints": [
{
"team": 0,
"position": {
"x": 0,
"y": 0,
"z": 0
},
"orientation": {
"x": 0,
"y": 0,
"z": 0
}
}
]
}

View File

@@ -1,26 +0,0 @@
# version 330 core
layout(location = 0) out vec3 fragPosition;
layout (location = 1) out vec4 fragColor;
layout (location = 2) out vec3 fragNormal;
layout (location = 3) out vec3 fragUV;
in vec3 outPosition, outColor, outNormal, outUV, outFragPos, outCameraPos;
flat in int outHasTexture;
uniform sampler2D diffuse_texture;
void main() {
vec3 result;
if (outHasTexture == 0) {
result = outColor;
} else {
result = texture(diffuse_texture, outUV.xy).xyz + 0.25;
}
fragPosition = outPosition;
fragColor = vec4(result, 1.0);
fragNormal = outNormal;
fragUV = outUV;
}

View File

@@ -1,63 +0,0 @@
#version 330 core
out vec4 FragColor;
@include "light_struct"
const int DIRECTIONAL = 0;
const int POINT = 1;
const int SPOT = 2;
in vec2 outTexCoords;
flat in Light outLight[1];
uniform sampler2D diffuse, position, texcoord, normal, depth;
vec4 directionalLight(Light light) {
vec3 norm = normalize(texture(normal, outTexCoords).rgb);
vec3 diffuse_color = texture(diffuse, outTexCoords).rgb;
vec3 fragPos = texture(position, outTexCoords).rgb;
vec3 lightDir = normalize(light.position - fragPos);
float diff = max(dot(norm, lightDir), 0);
vec3 _ambient = light.ambient;
vec3 _diffuse = light.diffuse * diff;
vec3 _specular = light.specular;
return vec4(_diffuse + _ambient + _specular, 1.0);
}
vec4 pointLight(Light light) {
return vec4(0.25, 0.25, 0.25, 1);
}
vec4 spotLight(Light light) {
return vec4(0.5, 0.5, 0.5, 1);
}
vec4 calculateLighting(Light light) {
vec4 result;
// switch(light.type) {
// case DIRECTIONAL: {
// result = directionalLight(light);
// }
// case SPOT: {
// result = spotLight(light);
// }
// default: {
// result = pointLight(light);
// }
// }
if (light.type == DIRECTIONAL) {
result = directionalLight(light);
} else {
result = pointLight(light);
}
return result;
}
void main() {
FragColor = texture(diffuse, outTexCoords) * calculateLighting(outLight[0]);
}

View File

@@ -1,11 +0,0 @@
struct Light {
int type;
vec3 direction;
vec3 position;
vec3 diffuse;
vec3 ambient;
vec3 specular;
float intensity;
};

View File

@@ -1,28 +0,0 @@
# version 330 core
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec3 inNormal;
layout(location = 3) in vec3 inUV;
uniform mat4 projection, view, model;
uniform int hasTexture;
uniform vec3 cameraPos;
out vec3 outPosition, outColor, outNormal, outUV;
out vec3 outFragPos, outViewPos, outCameraPos;
flat out int outHasTexture;
void main() {
// projection * view * model * position
outPosition = inPosition;
outColor = inColor;
outNormal= normalize(transpose(inverse(mat3(model))) * inNormal);
outUV = inUV;
outHasTexture = hasTexture;
outCameraPos = cameraPos;
outFragPos = vec3(model * vec4(inPosition, 1.0));
gl_Position = projection * view * model * vec4(inPosition, 1.0);
}

View File

@@ -1,17 +0,0 @@
#version 330 core
@include "light_struct"
layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec2 inTexCoords;
uniform sampler2D diffuse, position, texcoord, normal, depth;
uniform Light light[1];
out vec2 outTexCoords;
flat out Light outLight[1];
void main() {
gl_Position = vec4(inPosition.x, inPosition.y, inPosition.z, 1.0);
outTexCoords = inTexCoords;
outLight = light;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

BIN
static/sounds/ui_hover.ogg Normal file

Binary file not shown.

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866666 33.866668"
version="1.1"
id="svg8"
sodipodi:docname="settings_audio.svg"
inkscape:export-filename="C:\Users\cyber\Code\i-mic-fps\static\icons\settings_audio.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568542"
inkscape:cx="59.160271"
inkscape:cy="53.794164"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid833"
empspacing="8" />
<sodipodi:guide
position="2.1166666,16.933334"
orientation="1,0"
id="guide837" />
<sodipodi:guide
position="16.933333,31.750001"
orientation="0,-1"
id="guide839" />
<sodipodi:guide
position="31.749999,16.933334"
orientation="1,0"
id="guide841" />
<sodipodi:guide
position="19.05,2.1166667"
orientation="0,-1"
id="guide843" />
<sodipodi:guide
position="16.933333,27.516668"
orientation="1,0"
id="guide855" />
<sodipodi:guide
position="16.933333,16.933334"
orientation="0,-1"
id="guide857" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#deddda;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 16.933333,8.4666671 12.7,10.583333 H 6.3500001 4.2333333 L 2.1166666,12.7 l 1e-7,8.466667 2.1166668,2.116667 H 12.7 l 4.233333,2.116667 H 19.05 l 0,-16.9333339 z"
id="path863"
sodipodi:nodetypes="cccccccccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:1.05833334;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 21.166667,8.4666669 C 25.4,12.7 25.4,21.166667 21.166667,25.400001"
id="path865"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1.05833334;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.283334,8.4666667 c 4.233333,4.2333333 4.233333,12.7000003 0,16.9333343"
id="path865-8"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1.05833334;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 25.4,8.4666667 C 29.633333,12.7 29.633333,21.166667 25.4,25.400001"
id="path865-6"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 16.933333,8.4666671 V 25.400001"
id="path896" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866666 33.866668"
version="1.1"
id="svg8"
sodipodi:docname="settings_controls.svg"
inkscape:export-filename="C:\Users\cyber\Code\i-mic-fps\static\icons\settings_controls.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568542"
inkscape:cx="59.417753"
inkscape:cy="46.567825"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-intersection-paths="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox-edge-midpoints="true">
<inkscape:grid
type="xygrid"
id="grid833"
empspacing="8" />
<sodipodi:guide
position="2.1166666,16.933334"
orientation="1,0"
id="guide837" />
<sodipodi:guide
position="16.933333,31.750001"
orientation="0,-1"
id="guide839" />
<sodipodi:guide
position="31.749999,16.933334"
orientation="1,0"
id="guide841" />
<sodipodi:guide
position="19.05,2.1166667"
orientation="0,-1"
id="guide843" />
<sodipodi:guide
position="16.933333,27.516668"
orientation="1,0"
id="guide855" />
<sodipodi:guide
position="16.933333,16.933334"
orientation="0,-1"
id="guide857" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#deddda;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect898"
width="19.050001"
height="12.700001"
x="2.1166668"
y="10.583334"
rx="1.058336"
ry="1.0583334" />
<ellipse
style="fill:#deddda;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path900"
cx="27.516666"
cy="17.197916"
rx="3.9245155"
ry="6.3499994" />
<rect
style="fill:#deddda;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect902"
width="12.964583"
height="1.5875001"
x="4.2333336"
y="20.902084"
rx="1.102295e-06"
ry="1.0583334" />
<path
style="fill:none;stroke:#000000;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 24.077084,14.816667 h 6.879167"
id="path904" />
<path
style="fill:none;stroke:#000000;stroke-width:0.52916667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 27.516667,10.847917 v 3.96875"
id="path906" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866666 33.866668"
version="1.1"
id="svg8"
sodipodi:docname="settings_display.svg"
inkscape:export-filename="C:\Users\cyber\Code\i-mic-fps\static\icons\settings_display.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="38.887284"
inkscape:cy="53.219323"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid833"
empspacing="8" />
<sodipodi:guide
position="2.1166666,16.933334"
orientation="1,0"
id="guide837" />
<sodipodi:guide
position="16.933333,31.750001"
orientation="0,-1"
id="guide839" />
<sodipodi:guide
position="31.749999,16.933334"
orientation="1,0"
id="guide841" />
<sodipodi:guide
position="19.05,2.1166667"
orientation="0,-1"
id="guide843" />
<sodipodi:guide
position="16.933333,27.516668"
orientation="1,0"
id="guide855" />
<sodipodi:guide
position="16.933333,16.933334"
orientation="0,-1"
id="guide857" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#deddda;stroke:#000000;stroke-width:0.52916667;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 16.933334,23.283334 -4.233334,0 -6.3499999,6.35 H 27.516667 l -6.35,-6.35 z"
id="path853"
sodipodi:nodetypes="cccccc" />
<rect
style="fill:#c0bfbc;stroke-width:0.52916667;stroke:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round"
id="rect845"
width="29.633331"
height="16.933334"
x="2.1166668"
y="6.3499999"
ry="2.1166663"
rx="2.1166663" />
<rect
style="fill:#ffffff;stroke-width:1.05833"
id="rect849"
width="25.400002"
height="12.700001"
x="4.2333336"
y="8.4666672"
ry="1.4885254e-06"
rx="1.4885254e-06" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866666 33.866668"
version="1.1"
id="svg8"
sodipodi:docname="settings_graphics.svg"
inkscape:export-filename="C:\Users\cyber\Code\i-mic-fps\static\icons\settings_graphics.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="40.619584"
inkscape:cy="57.766917"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid833"
empspacing="8" />
<sodipodi:guide
position="2.1166666,16.933334"
orientation="1,0"
id="guide837" />
<sodipodi:guide
position="16.933333,31.750001"
orientation="0,-1"
id="guide839" />
<sodipodi:guide
position="31.749999,16.933334"
orientation="1,0"
id="guide841" />
<sodipodi:guide
position="19.05,2.1166667"
orientation="0,-1"
id="guide843" />
<sodipodi:guide
position="16.933333,27.516668"
orientation="1,0"
id="guide855" />
<sodipodi:guide
position="16.933333,16.933334"
orientation="0,-1"
id="guide857" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#f6f5f4;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 31.750001,10.583333 -8.466667,6.35 L 31.750001,25.4 Z"
id="path861" />
<rect
style="fill:#deddda;stroke:#000000;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect859"
width="23.283335"
height="14.816667"
x="2.1166666"
y="10.583333"
rx="1.058336"
ry="1.0583334" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB