diff --git a/assets/README.md b/assets/README.md index bedf8d9..c0dfd91 100644 --- a/assets/README.md +++ b/assets/README.md @@ -21,8 +21,10 @@ collision: "mesh" # Path to collision model or null to use `model` collision_mesh: null # Array of scripts to load, relative to package/name/scripts/ +# Optionally shared scripts can be loaded from package/shared/scripts/ if prefixed with an exclaimation mark "!" scripts: [ - "script" + "script", + "!shared_script" ] # Array of assets to preload that this asset uses/requires uses: [ diff --git a/assets/base/alternate_tank/manifest.yaml b/assets/base/alternate_tank/manifest.yaml index 1dd6fd6..ed65eeb 100644 --- a/assets/base/alternate_tank/manifest.yaml +++ b/assets/base/alternate_tank/manifest.yaml @@ -1,5 +1,5 @@ name: "Alternate Tank" model: "alternate_tank.obj" scripts: [ - "vehicle" + "!vehicle" ] \ No newline at end of file diff --git a/assets/base/alternate_tank/scripts/vehicle.rb b/assets/base/shared/scripts/vehicle.rb similarity index 100% rename from assets/base/alternate_tank/scripts/vehicle.rb rename to assets/base/shared/scripts/vehicle.rb diff --git a/assets/base/war_factory/scripts/war_factory.rb b/assets/base/war_factory/scripts/war_factory.rb index bf099f4..ba86482 100644 --- a/assets/base/war_factory/scripts/war_factory.rb +++ b/assets/base/war_factory/scripts/war_factory.rb @@ -6,6 +6,6 @@ on.create do |event| map.insert_entity("base", "door", event.entity.position + Vector.new(3.3, 0, 6), Vector.new(0, 0, 0)) map.insert_entity("base", "door", event.entity.position + Vector.new(3.3, 0, 6), Vector.new(0, 180, 0)) - map.insert_particle_emitter(Vector.new(3.0, 15.379, 0.029), Texture.new("base", "shared", "particles", "smoke", "smoke.png")) - map.insert_particle_emitter(Vector.new(5.0, 15.379, 0.029), Texture.new("base", "shared", "particles", "smoke", "smoke.png")) + map.insert_particle_emitter(Vector.new(3.0, 15.379, 0.029), Texture.new(path: ["base", "shared", "particles", "smoke", "smoke.png"])) + map.insert_particle_emitter(Vector.new(5.0, 15.379, 0.029), Texture.new(path: ["base", "shared", "particles", "smoke", "smoke.png"])) end \ No newline at end of file diff --git a/lib/game_objects/entities/player.rb b/lib/game_objects/entities/player.rb index 9e796b0..afbaeab 100644 --- a/lib/game_objects/entities/player.rb +++ b/lib/game_objects/entities/player.rb @@ -19,7 +19,7 @@ class IMICFPS @devisor = 500.0 @name_image = Gosu::Image.from_text("#{Etc.getlogin}", 100, font: "Consolas", align: :center) - @name_texture_id = Texture.new(@name_image).id + @name_texture_id = Texture.new(image: @name_image).id end def draw_nameplate diff --git a/lib/game_objects/light.rb b/lib/game_objects/light.rb index 336bb0b..53ae0a6 100644 --- a/lib/game_objects/light.rb +++ b/lib/game_objects/light.rb @@ -8,10 +8,10 @@ class IMICFPS def initialize( id:, type: Light::POINT, - ambient: Vector.new(0.5, 0.5, 0.5, 1), - diffuse: Vector.new(1, 1, 1, 1), - specular: Vector.new(0.2, 0.2, 0.2, 1), - position: Vector.new(0, 0, 0, 0), + ambient: Vector.new(0.5, 0.5, 0.5), + diffuse: Vector.new(1, 1, 1), + specular: Vector.new(0.2, 0.2, 0.2), + position: Vector.new(0, 0, 0), intensity: 1 ) @light_id = id diff --git a/lib/manifest.rb b/lib/manifest.rb index 8749a49..3604f30 100644 --- a/lib/manifest.rb +++ b/lib/manifest.rb @@ -35,7 +35,16 @@ class IMICFPS def parse_scripts(scripts) list = [] scripts.each do |script| - list << Script.new(script, File.read("#{file_path}/scripts/#{script}.rb")) + path = "" + + if script.start_with?("!") + script = script.sub("!", "") + path = File.expand_path("../shared/", file_path) + "/scripts/" + script + else + path = "#{file_path}/scripts/#{script}" + end + + list << Script.new(script, File.read("#{path}.rb")) end return list diff --git a/lib/map.rb b/lib/map.rb index 09b2eca..3c7d7cf 100644 --- a/lib/map.rb +++ b/lib/map.rb @@ -6,8 +6,8 @@ class IMICFPS attr_reader :collision_manager attr_reader :gravity - def initialize(map_loader:, gravity: IMICFPS::EARTH_GRAVITY) - @map_loader = map_loader + def initialize(map_parser:, gravity: IMICFPS::EARTH_GRAVITY) + @map_parser = map_parser @gravity = gravity @entities = [] @@ -19,23 +19,26 @@ class IMICFPS end def setup - add_entity(Terrain.new(map_entity: @map_loader.terrain, manifest: Manifest.new(package: @map_loader.terrain.package, name: @map_loader.terrain.name))) + add_entity(Terrain.new(map_entity: @map_parser.terrain, manifest: Manifest.new(package: @map_parser.terrain.package, name: @map_parser.terrain.name))) - add_entity(Skydome.new(map_entity: @map_loader.skydome, manifest: Manifest.new(package: @map_loader.skydome.package, name: @map_loader.skydome.name), backface_culling: false)) + add_entity(Skydome.new(map_entity: @map_parser.skydome, manifest: Manifest.new(package: @map_parser.skydome.package, name: @map_parser.skydome.name), backface_culling: false)) - @map_loader.entities.each do |ent| + @map_parser.lights.each do |l| + add_light(Light.new(id: available_light, position: l.position, diffuse: l.diffuse, ambient: l.ambient, specular: l.specular, intensity: l.intensity)) + end + + @map_parser.entities.each do |ent| add_entity(Entity.new(map_entity: ent, manifest: Manifest.new(package: ent.package, name: ent.name))) end - add_entity(Player.new(spawnpoint: @map_loader.spawnpoints.sample, manifest: Manifest.new(package: "base", name: "character"))) + add_entity(Player.new(spawnpoint: @map_parser.spawnpoints.sample, manifest: Manifest.new(package: "base", name: "character"))) - # TODO: Load lights from MapParser - add_light(Light.new(id: available_light, position: Vector.new(30, 10.0, 30))) - add_light(Light.new(id: available_light, position: Vector.new(0, 100, 0), diffuse: Color.new(1.0, 0.5, 0.1))) + # add_light(Light.new(id: available_light, position: Vector.new(30, 10.0, 30))) + # add_light(Light.new(id: available_light, position: Vector.new(0, 100, 0), diffuse: Color.new(1.0, 0.5, 0.1))) end def data - @map_loader + @map_parser end def render(camera) diff --git a/lib/map_parser.rb b/lib/map_parser.rb index 6eaccda..5335203 100644 --- a/lib/map_parser.rb +++ b/lib/map_parser.rb @@ -1,11 +1,12 @@ class IMICFPS class MapParser - attr_reader :metadata, :terrain, :skydome, :entities, :spawnpoints + attr_reader :metadata, :terrain, :skydome, :lights, :entities, :spawnpoints attr_reader :assets, :missing_assets def initialize(map_file:) @metadata = MapParser::MetaData.new @terrain = MapParser::Entity.new @skydome = MapParser::Entity.new + @lights = [] @entities = [] @spawnpoints = [] @@ -76,6 +77,36 @@ class IMICFPS raise "Map skydome data is missing!" end + if section = data["lights"] + section.each do |l| + light = MapParser::Light.new + light.type = IMICFPS::Light::POINT # TODO: fix me + light.position = Vector.new( + l["position"]["x"], + l["position"]["y"], + l["position"]["z"] + ) + light.diffuse = Color.new( + l["diffuse"]["red"], + l["diffuse"]["green"], + l["diffuse"]["blue"] + ) + light.ambient = Color.new( + l["ambient"]["red"], + l["ambient"]["green"], + l["ambient"]["blue"] + ) + light.specular = Color.new( + l["specular"]["red"], + l["specular"]["green"], + l["specular"]["blue"] + ) + light.intensity = l["intensity"] + + @lights << light + end + end + if section = data["entities"] section.each do |ent| entity = MapParser::Entity.new @@ -132,6 +163,7 @@ class IMICFPS end MetaData = Struct.new(:name, :gamemode, :authors, :datetime, :thumbnail, :description) + Light = Struct.new(:type, :position, :diffuse, :ambient, :specular, :intensity) Entity = Struct.new(:package, :name, :position, :orientation, :scale, :water_level, :scripts) SpawnPoint = Struct.new(:team, :position, :orientation) end diff --git a/lib/model/material.rb b/lib/model/material.rb index 20812fa..fc50391 100644 --- a/lib/model/material.rb +++ b/lib/model/material.rb @@ -13,7 +13,7 @@ class IMICFPS end def set_texture(texture_path) - @texture_id = Texture.new(texture_path).id + @texture_id = Texture.new(path: texture_path).id end end end diff --git a/lib/model/parser.rb b/lib/model/parser.rb index 6f03071..751b000 100644 --- a/lib/model/parser.rb +++ b/lib/model/parser.rb @@ -36,7 +36,7 @@ class IMICFPS if id _model = @model.objects.find { |o| o.id == id } elsif name - _model = @model.objects.find { |o| o.id == id } + _model = @model.objects.find { |o| o.name == name } else raise "Must provide either an id: or name:" end diff --git a/lib/model/parsers/wavefront_parser.rb b/lib/model/parsers/wavefront_parser.rb index 356b47e..eff6be7 100644 --- a/lib/model/parsers/wavefront_parser.rb +++ b/lib/model/parsers/wavefront_parser.rb @@ -4,10 +4,6 @@ class IMICFPS [:obj] end - def initialize(model) - @model = model - end - def parse lines = 0 list = File.read(@model.file_path).split("\n") diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index 372c033..3e9f613 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -124,12 +124,14 @@ class IMICFPS glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) + if model.has_texture? glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, model.materials[model.textured_material].texture_id) glEnableClientState(GL_TEXTURE_COORD_ARRAY) glTexCoordPointer(3, GL_FLOAT, 0, o.flattened_textures) end + glVertexPointer(4, GL_FLOAT, 0, o.flattened_vertices) glColorPointer(3, GL_FLOAT, 0, o.flattened_materials) glNormalPointer(GL_FLOAT, 0, o.flattened_normals) @@ -160,10 +162,12 @@ class IMICFPS glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) + if model.has_texture? glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisable(GL_TEXTURE_2D) end + glDisable(GL_CULL_FACE) if model.entity.backface_culling glDisable(GL_COLOR_MATERIAL) end diff --git a/lib/scenes/turn_table.rb b/lib/scenes/turn_table.rb index c2e8021..d28acad 100644 --- a/lib/scenes/turn_table.rb +++ b/lib/scenes/turn_table.rb @@ -6,6 +6,7 @@ class IMICFPS lights << (Light.new(id: OpenGL::GL_LIGHT2, position: Vector.new(0, 10, 5), diffuse: Color.new(1.0, 1.0, 1.0), specular: Color.new(0, 0, 0))) options = { + # entity: scale "character": 0.25, "information_panel": 0.25, "purchase_terminal": 0.35, diff --git a/lib/states/game_states/game.rb b/lib/states/game_states/game.rb index cd74eb0..0aa1e1b 100644 --- a/lib/states/game_states/game.rb +++ b/lib/states/game_states/game.rb @@ -3,7 +3,7 @@ class IMICFPS attr_reader :map def setup - @map = Map.new(map_loader: @options[:map_parser]) + @map = Map.new(map_parser: @options[:map_parser]) @map.setup @player = @map.find_entity_by(name: "character") diff --git a/lib/texture.rb b/lib/texture.rb index 8d10d5f..cec3142 100644 --- a/lib/texture.rb +++ b/lib/texture.rb @@ -11,18 +11,19 @@ class IMICFPS end attr_reader :id - def initialize(*path) - if path.size > 1 - path = "#{GAME_ROOT_PATH}/assets/#{path.join("/")}" - else - path = path.first + def initialize(path: nil, image: nil, retro: false) + raise "keyword :path or :image must be provided!" if path.nil? && image.nil? + @retro = retro + + if path.is_a?(Array) + if path.size > 1 + path = "#{GAME_ROOT_PATH}/assets/#{path.join("/")}" + else + path = path.first + end end - unless path.is_a?(String) - @id = create_from_image(path) - else - @id = from_cache(path) - end + @id = create_from_image(path ? path : image) end def from_cache(path) @@ -51,7 +52,8 @@ class IMICFPS glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array_of_pixels) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) if @retro + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) unless @retro glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glGenerateMipmap(GL_TEXTURE_2D) gl_error? diff --git a/lib/ui/commands/reload_shader_command.rb b/lib/ui/commands/reload_shader_command.rb new file mode 100644 index 0000000..cf47f45 --- /dev/null +++ b/lib/ui/commands/reload_shader_command.rb @@ -0,0 +1,62 @@ +class IMICFPS + class Commands + class ReloadShaderCommand < Command + def group + :reload_shader + end + + def command + :reload_shader + end + + def handle(arguments, console) + if arguments.size > 2 + console.stdin("to many arguments for #{Style.highlight("#{command}")}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.") + return + end + + shader = nil + stdout = $stdout + $stdout = StringIO.new + + case arguments.size + when 0 + console.stdin( usage ) + return + when 1 + name = arguments.first + shader = Shader.new( + name: name, + includes_dir: "shaders/include", + vertex: "shaders/vertex/#{name}.glsl", + fragment: "shaders/fragment/#{name}.glsl" + ) + when 2 + vertex = arguments.first + fragment = arguments.last + shader = Shader.new( + name: vertex, + includes_dir: "shaders/include", + vertex: "shaders/vertex/#{vertex}.glsl", + fragment: "shaders/fragment/#{fragment}.glsl" + ) + end + + string = $stdout.string + + if shader.compiled? + console.stdin("#{Style.notice("Successfully reloaded shader")}: #{shader.name}") + else + console.stdin("#{Style.error("Failed to reload #{shader.name}")}") + console.stdin(string) + end + ensure + $stdout = stdout + end + + def usage + "#{Style.highlight(command)} #{Style.notice("vertex_name [fragment_name]")}" + end + end + end +end diff --git a/maps/test_map.json b/maps/test_map.json index ecb45e0..f5ebfc2 100644 --- a/maps/test_map.json +++ b/maps/test_map.json @@ -20,6 +20,57 @@ "scale":0.08 }, + "lights":[ + { + "type":"directional", + "intensity": 1, + "position": { + "x":30, + "y":10, + "z":30 + }, + "diffuse": { + "red":1, + "green":1, + "blue":1 + }, + "ambient": { + "red":0.5, + "green":0.5, + "blue":0.5 + }, + "specular": { + "red":0.2, + "green":0.2, + "blue":0.2 + } + }, + { + "type":"directional", + "intensity": 1, + "position": { + "x":0, + "y":100, + "z":0 + }, + "diffuse": { + "red":1, + "green":0.5, + "blue":0.1 + }, + "ambient": { + "red":0.5, + "green":0.5, + "blue":0.5 + }, + "specular": { + "red":0.2, + "green":0.2, + "blue":0.2 + } + } + ], + "entities":[ { "package":"base",