From af5d52cfd932020c0e73b7365454bba099d91f83 Mon Sep 17 00:00:00 2001 From: Gliese852 Date: Sat, 4 Apr 2020 10:47:51 +0300 Subject: [PATCH 1/2] Move the System Map to PiGUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main idea of the interaction of lua side and C++ side is the same as in the worldview - the C++ View Class builds three-dimensional objects, some projected points are passed to the lua script, the lua script only works with screen coordinates. The difference between the system view and the world view is that not all objects can have a physical body. If we examine a non-current star system, we see only system bodies that do not have physical bodies. Therefore, if for a world view you can simply create an array of physical bodies, this will not work in a system view. To solve this problem, struct "Projectable" was created, into which you can write any point object, system body, ship, Lagrange point, apocenter, pericenter, etc. Now all these objects can be processed in a single array. The names of the types of these objects are recorded in an enum, which is exported to a enum_table.cpp and read by the script as integers at the start. I thought it was better to avoid passing strings in such a hot place in the code. (runs for every object in every frame) Therefore, type names are written and transmitted as integers. All colors are now imported from lua: color index names are listed in the enum, which is exported to the enum_table.cpp. At event "onGameStart" the lua script reads these names and sends color values to the class. Now you can change colors at runtime. * Improvements/fixes: * - Fix zooming speeds. - Fix ship's orbits in nonroot frame. - Remove unused old gui objects. - Landed ship are now spinning with the planet when rewinding time in a planner. - Now you can center the view on any object, including the player’s ship. - Add right-click context menu to center or set object as target. Therefore, to rotate the view, set the middle button. - Add indicators for navigation target and combat target. * Changes in the files explained * SystemView.cpp, SystemView.h, system-view-ui.lua, lang/core/en.json The whole thing, lots of changes. Now the system view draws only the orbits and the grid. In those places where the icons were drawn, instead of drawing, they are stored in an array, which is then requested from the lua. LuaEngine.cpp Add a general function that returns the value of an any enum by name from an enum_table.cpp (for calling from a lua) Space.cpp Added a notification for the systemview when the ship is removed from space, because it can be centered at this time, and an segmentation fault will occur. LuaSystemBody.cpp Added attributes to determine the shape of the icon and set the navigation target. enum_table.cpp, enum_table.h Rescanned enums to pass color settings and object types between Lua and C++. LuaGame.cpp The float does not have enough accuracy to display time up to seconds, change to double. icons.svg, themes/default.lua Add rotate view icon --- data/icons/icons.svg | 42 +- data/lang/core/en.json | 16 + data/lang/ui-core/en.json | 16 + data/pigui/modules/system-view-ui.lua | 516 +++++++++++++++ data/pigui/themes/default.lua | 1 + scripts/scan_enums.py | 4 +- src/Space.cpp | 3 + src/SystemView.cpp | 865 +++++++++----------------- src/SystemView.h | 135 ++-- src/enum_table.cpp | 231 ++++--- src/enum_table.h | 18 +- src/lua/Lua.cpp | 2 + src/lua/LuaEngine.cpp | 12 +- src/lua/LuaGame.cpp | 25 +- src/lua/LuaSystemBody.cpp | 24 + src/lua/LuaSystemView.cpp | 436 +++++++++++++ 16 files changed, 1601 insertions(+), 745 deletions(-) create mode 100644 data/pigui/modules/system-view-ui.lua create mode 100644 src/lua/LuaSystemView.cpp diff --git a/data/icons/icons.svg b/data/icons/icons.svg index dc98ce867..0a16d89e7 100644 --- a/data/icons/icons.svg +++ b/data/icons/icons.svg @@ -16,7 +16,7 @@ viewBox="0 0 3628.3465 3628.3464" id="svg4446" version="1.1" - inkscape:version="0.92.4 (5da689c313, 2019-01-14)" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="icons.svg"> @@ -881,16 +881,16 @@ borderopacity="1.0" inkscape:pageopacity="1" inkscape:pageshadow="2" - inkscape:zoom="0.1767767" - inkscape:cx="1429.7092" - inkscape:cy="1859.5164" + inkscape:zoom="0.25000001" + inkscape:cx="2379.8651" + inkscape:cy="2002.5917" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="true" - inkscape:window-width="1850" - inkscape:window-height="1057" - inkscape:window-x="1912" - inkscape:window-y="-8" + inkscape:window-width="1853" + inkscape:window-height="1016" + inkscape:window-x="67" + inkscape:window-y="27" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" @@ -943,7 +943,7 @@ image/svg+xml - + @@ -9014,5 +9014,29 @@ id="rect7847" style="fill:none;stroke:none;stroke-width:10.69061661;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:10.69061666, 21.38123329;stroke-dashoffset:0" /> + + + + + diff --git a/data/lang/core/en.json b/data/lang/core/en.json index c58ed7440..b833f8f5b 100644 --- a/data/lang/core/en.json +++ b/data/lang/core/en.json @@ -167,6 +167,10 @@ "description": "", "message": "Cargo scoop attempted. Not enough room in cargo hold." }, + "CENTER": { + "description": "", + "message": "Center" + }, "CH4_ATMOSPHERE": { "description": "", "message": "\" Methane atmosphere\"" @@ -1091,6 +1095,10 @@ "description": "", "message": "Orbital starport" }, + "ORBIT_PLANNER": { + "description": "", + "message": "Orbit planner" + }, "OUTDOOR_AGRICULTURAL_WORLD": { "description": "", "message": "Outdoor agricultural world." @@ -1323,6 +1331,14 @@ "description": "", "message": "Semi-major axis" }, + "SET_AS_COMBAT_TARGET": { + "description": "", + "message": "Set as combat target" + }, + "SET_AS_TARGET": { + "description": "", + "message": "Set as navigation target" + }, "SET_HYPERSPACE_DESTINATION_TO": { "description": "", "message": "Set hyperspace destination to %system" diff --git a/data/lang/ui-core/en.json b/data/lang/ui-core/en.json index 771c3d167..cf73c6c24 100644 --- a/data/lang/ui-core/en.json +++ b/data/lang/ui-core/en.json @@ -263,6 +263,10 @@ "description": "Player combat rating", "message": "Deadly" }, + "DECREASE": { + "description": "Decrease something.", + "message": "Decrease" + }, "DELTA_V": { "description": "", "message": "Delta-v" @@ -963,6 +967,10 @@ "description": "For player reputation", "message": "Incompetent" }, + "INCREASE": { + "description": "Increase something.", + "message": "Increase" + }, "INEXPERIENCED": { "description": "For player reputation", "message": "Inexperienced" @@ -1531,6 +1539,10 @@ "description": "", "message": "Reward" }, + "ROTATE_VIEW": { + "description": "", + "message": "Rotate view" + }, "ROUTE_INFO": { "description": "For hyperjump planner", "message": "Route Info" @@ -1627,6 +1639,10 @@ "description": "", "message": "Ship Repairs" }, + "SHIP_TYPE": { + "description": "", + "message": "Ship Type" + }, "SHIP_VIEWING_WAS_SOLD": { "description": "", "message": "The ship you were viewing has been sold" diff --git a/data/pigui/modules/system-view-ui.lua b/data/pigui/modules/system-view-ui.lua new file mode 100644 index 000000000..0ba760304 --- /dev/null +++ b/data/pigui/modules/system-view-ui.lua @@ -0,0 +1,516 @@ +local Game = require 'Game' +local Engine = require 'Engine' +local Event = require 'Event' +local Lang = require 'Lang' +local ui = require 'pigui' +local Format = require 'Format' +local Input = require 'Input' + +local Vector2 = _G.Vector2 +local lc = Lang.GetResource("core") +local luc = Lang.GetResource("ui-core") + +local player = nil +local colors = ui.theme.colors +local icons = ui.theme.icons + +local systemView + +local mainButtonSize = ui.rescaleUI(Vector2(32,32), Vector2(1600, 900)) +local mainButtonFramePadding = 3 +local itemSpacing = Vector2(8, 4) -- couldn't get default from ui +local indicatorSize = Vector2(30 , 30) + +local selectedObject -- object, centered in SystemView + +local pionillium = ui.fonts.pionillium +local ASTEROID_RADIUS = 1500000 -- rocky planets smaller than this (in meters) are considered an asteroid, not a planet + +--load enums Projectable::types and Projectable::bases in one table "Projectable" +local Projectable = {} +for _, key in pairs(Constants.ProjectableTypes) do Projectable[key] = Engine.GetEnumValue("ProjectableTypes", key) end +for _, key in pairs(Constants.ProjectableBases) do Projectable[key] = Engine.GetEnumValue("ProjectableBases", key) end + +local svColor = { + BUTTON_BACK = colors.buttonBlue, + BUTTON_INK = colors.white, + COMBAT_TARGET = colors.combatTarget, + GRID = Color(25,25,25), + LAGRANGE = Color(0,214,226), + NAV_TARGET = colors.navTarget, + OBJECT = colors.frame, + PLANNER = Color(0,0,255), + PLANNER_ORBIT = Color(0,0,255), + PLAYER = Color(255,0,0), + PLAYER_ORBIT = Color(255,0,0), + SELECTED_SHIP_ORBIT = Color(0,186,255), + SHIP = colors.frame, + SHIP_ORBIT = Color(0,0,155), + SYSTEMBODY = Color(109,109,134), + SYSTEMBODY_ICON = colors.frame, + SYSTEMBODY_ORBIT = Color(0,155,0), + SYSTEMNAME_BACK = colors.transparent, + WINDOW_BACK = colors.lightBlackBackground, + UNKNOWN = Color(255,0,255) +} + +local onGameStart = function () + --connect to class SystemView + systemView = Game.systemView + --export several colors to class SystemView (only those which mentioned in the enum SystemViewColorIndex) + for _, key in pairs(Constants.SystemViewColorIndex) do + systemView:SetColor(key, svColor[key]) + end +end + +local function showDvLine(leftIcon, resetIcon, rightIcon, key, Formatter, leftTooltip, resetTooltip, rightTooltip) + local wheel = function() + if ui.isItemHovered() then + local w = ui.getMouseWheel() + if w ~= 0 then + systemView:TransferPlannerAdd(key, w * 10) + end + end + end + local press = ui.coloredSelectedIconButton(leftIcon, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, leftTooltip) + if press or (key ~= "factor" and ui.isItemActive()) then + systemView:TransferPlannerAdd(key, -10) + end + wheel() + ui.sameLine() + if ui.coloredSelectedIconButton(resetIcon, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, resetTooltip) then + systemView:TransferPlannerReset(key) + end + wheel() + ui.sameLine() + press = ui.coloredSelectedIconButton(rightIcon, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, rightTooltip) + if press or (key ~= "factor" and ui.isItemActive()) then + systemView:TransferPlannerAdd(key, 10) + end + wheel() + ui.sameLine() + local speed, speed_unit = Formatter(systemView:TransferPlannerGet(key)) + ui.text(speed .. " " .. speed_unit) + return 0 +end + +local time_selected_button_icon = icons.time_center + +local function timeButton(icon, tooltip, factor) + if ui.coloredSelectedIconButton(icon, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, tooltip) then + time_selected_button_icon = icon + end + local active = ui.isItemActive() + if active then + systemView:AccelerateTime(factor) + end + ui.sameLine() + return active +end + +local function loop3items(a, b, c) return { [a] = b, [b] = c, [c] = a } end + +local ship_drawing = "SHIPS_OFF" +local show_lagrange = "LAG_OFF" +local show_grid = "GRID_OFF" +local nextShipDrawings = loop3items("SHIPS_OFF", "SHIPS_ON", "SHIPS_ORBITS") +local nextShowLagrange = loop3items("LAG_OFF", "LAG_ICON", "LAG_ICONTEXT") +local nextShowGrid = loop3items("GRID_OFF", "GRID_ON", "GRID_AND_LEGS") + +local function calcWindowWidth(buttons) + return (mainButtonSize.y + mainButtonFramePadding * 2) * buttons + + itemSpacing.x * (buttons + 1) +end + +local function calcWindowHeight(buttons, separators, texts) + return + (mainButtonSize.y + mainButtonFramePadding * 2) * buttons + + separators * itemSpacing.y + + texts * ui.fonts.pionillium.medium.size + + (buttons + texts - 1) * itemSpacing.y + + itemSpacing.x * 2 +end + +local orbitPlannerWindowPos = Vector2(ui.screenWidth - calcWindowWidth(7), ui.screenHeight - calcWindowHeight(7, 3, 2)) + +local function showOrbitPlannerWindow() + ui.setNextWindowPos(orbitPlannerWindowPos, "Always") + ui.withStyleColors({["WindowBg"] = svColor.WINDOW_BACK}, function() + ui.window("OrbitPlannerWindow", {"NoTitleBar", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus", "NoSavedSettings", "AlwaysAutoResize"}, + function() + ui.text(lc.ORBIT_PLANNER) + + ui.separator() + + if ui.coloredSelectedIconButton(icons.reset_view, mainButtonSize, showShips, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, lc.RESET_ORIENTATION_AND_ZOOM) then + systemView:SetVisibility("RESET_VIEW") + end + ui.sameLine() + if ui.coloredSelectedIconButton(icons.toggle_grid, mainButtonSize, showShips, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, lc.GRID_DISPLAY_MODE_TOGGLE) then + show_grid = nextShowGrid[show_grid] + systemView:SetVisibility(show_grid); + end + ui.sameLine() + if ui.coloredSelectedIconButton(icons.toggle_ships, mainButtonSize, showShips, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, lc.SHIPS_DISPLAY_MODE_TOGGLE) then + ship_drawing = nextShipDrawings[ship_drawing] + systemView:SetVisibility(ship_drawing); + end + ui.sameLine() + if ui.coloredSelectedIconButton(icons.toggle_lagrange, mainButtonSize, showLagrangePoints, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, lc.L4L5_DISPLAY_MODE_TOGGLE) then + show_lagrange = nextShowLagrange[show_lagrange] + systemView:SetVisibility(show_lagrange); + end + ui.sameLine() + ui.coloredSelectedIconButton(icons.search_lens,mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, luc.ZOOM) + systemView:SetZoomMode(ui.isItemActive()) + + ui.sameLine() + ui.coloredSelectedIconButton(icons.rotate_view, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_BACK, svColor.BUTTON_INK, luc.ROTATE_VIEW) + systemView:SetRotateMode(ui.isItemActive()) + + ui.separator() + + showDvLine(icons.decrease, icons.delta, icons.increase, "factor", function(i) return i, "x" end, luc.DECREASE, lc.PLANNER_RESET_FACTOR, luc.INCREASE) + showDvLine(icons.decrease, icons.clock, icons.increase, "starttime", + function(i) + local now = Game.time + local start = systemView:GetOrbitPlannerStartTime() + if start then + return ui.Format.Duration(math.floor(start - now)), "" + else + return lc.NOW, "" + end + end, + luc.DECREASE, lc.PLANNER_RESET_START, luc.INCREASE) + showDvLine(icons.decrease, icons.orbit_prograde, icons.increase, "prograde", ui.Format.Speed, luc.DECREASE, lc.PLANNER_RESET_PROGRADE, luc.INCREASE) + showDvLine(icons.decrease, icons.orbit_normal, icons.increase, "normal", ui.Format.Speed, luc.DECREASE, lc.PLANNER_RESET_NORMAL, luc.INCREASE) + showDvLine(icons.decrease, icons.orbit_radial, icons.increase, "radial", ui.Format.Speed, luc.DECREASE, lc.PLANNER_RESET_RADIAL, luc.INCREASE) + + ui.separator() + + local t = systemView:GetOrbitPlannerTime() + ui.text(t and ui.Format.Datetime(t) or lc.NOW) + local r = false + r = timeButton(icons.time_backward_100x, "-10,000,000x",-10000000) or r + r = timeButton(icons.time_backward_10x, "-100,000x", -100000) or r + r = timeButton(icons.time_backward_1x, "-1,000x", -1000) or r + r = timeButton(icons.time_center, lc.NOW, nil) or r + r = timeButton(icons.time_forward_1x, "1,000x", 1000) or r + r = timeButton(icons.time_forward_10x, "100,000x", 100000) or r + r = timeButton(icons.time_forward_100x, "10,000,000x", 10000000) or r + if not r then + if time_selected_button_icon == icons.time_center then + systemView:AccelerateTime(nil) + else + systemView:AccelerateTime(0.0) + end + end + end) + end) +end + +local function getBodyIcon(obj) + if obj.type == Projectable.APOAPSIS then return icons.apoapsis + elseif obj.type == Projectable.PERIAPSIS then return icons.periapsis + elseif obj.type == Projectable.L4 then return icons.lagrange_marker + elseif obj.type == Projectable.L5 then return icons.lagrange_marker + elseif obj.base == Projectable.PLAYER or obj.base == Projectable.PLANNER then + local shipClass = obj.ref:GetShipClass() + if icons[shipClass] then + return icons[shipClass] + else + return icons.ship + end + elseif obj.base == Projectable.SYSTEMBODY then + local body = obj.ref + local st = body.superType + local t = body.type + if st == "STARPORT" then + if t == "STARPORT_ORBITAL" then + return icons.spacestation + elseif body.type == "STARPORT_SURFACE" then + return icons.starport + end + elseif st == "GAS_GIANT" then + return icons.gas_giant + elseif st == "STAR" then + return icons.sun + elseif st == "ROCKY_PLANET" then + if body.IsMoon then + return icons.moon + else + if body.radius < ASTEROID_RADIUS then + return icons.asteroid_hollow + else + return icons.rocky_planet + end + end + end -- st + else + -- physical body + local body = obj.ref + if body:IsShip() then + local shipClass = body:GetShipClass() + if icons[shipClass] then + return icons[shipClass] + else + print("system-view-ui.lua: getBodyIcon unknown ship class " .. (shipClass and shipClass or "nil")) + return icons.ship -- TODO: better icon + end + elseif body:IsHyperspaceCloud() then + return icons.hyperspace -- TODO: better icon + elseif body:IsMissile() then + return icons.bullseye -- TODO: better icon + elseif body:IsCargoContainer() then + return icons.rocky_planet -- TODO: better icon + else + print("system-view-ui.lua: getBodyIcon not sure how to process body, supertype: " .. (st and st or "nil") .. ", type: " .. (t and t or "nil")) + --utils.print_r(body) + return icons.ship + end + end +end + +local function getLabel(obj) + if obj.type == Projectable.OBJECT then + if obj.base == Projectable.SYSTEMBODY then return obj.ref.name + elseif obj.base == Projectable.PLANNER then return "" + else return obj.ref:GetLabel() end + elseif obj.type == Projectable.L4 and show_lagrange == "LAG_ICONTEXT" then return "L4" + elseif obj.type == Projectable.L5 and show_lagrange == "LAG_ICONTEXT" then return "L5" + else return "" + end +end + +local function getColor(obj) + if obj.type == Projectable.OBJECT then + if obj.base == Projectable.SYSTEMBODY then return svColor.SYSTEMBODY_ICON + elseif obj.base == Projectable.SHIP then return svColor.SHIP + elseif obj.base == Projectable.PLAYER then return svColor.PLAYER + elseif obj.base == Projectable.PLANNER then return svColor.PLANNER + else return svColor.OBJECT + end + elseif obj.type == Projectable.APOAPSIS or obj.type == Projectable.PERIAPSIS then + if obj.base == Projectable.SYSTEMBODY then return svColor.SYSTEMBODY_ORBIT + elseif obj.base == Projectable.SHIP then + if obj.ref == selectedObject then return svColor.SELECTED_SHIP_ORBIT + else return svColor.SHIP_ORBIT + end + elseif obj.base == Projectable.PLAYER then return svColor.PLAYER_ORBIT + elseif obj.base == Projectable.PLANNER then return svColor.PLANNER_ORBIT + else return svColor.UNKNOWN -- unknown base + end + elseif obj.type == Projectable.L4 or obj.type == Projectable.L5 then return svColor.LAGRANGE + else return svColor.UNKNOWN + end +end + +local function showSystemName() + ui.setNextWindowPos(Vector2(20, 20), "Always") + ui.withStyleColors({["WindowBg"] = svColor.SYSTEMNAME_BACK}, function() + ui.window("SystemName", {"NoTitleBar", "AlwaysAutoResize", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus", "NoSavedSettings"}, + function() + local path = Engine.GetSectorMapSelectedSystemPath() + local starsystem = path:GetStarSystem() + ui.text(starsystem.name .. " (" .. path.sectorX .. ", " .. path.sectorY .. ", " .. path.sectorZ .. ")") + end) + end) +end + +-- forked from data/pigui/views/game.lua +local function displayOnScreenObjects() + + local navTarget = player:GetNavTarget() + local combatTarget = player:GetCombatTarget() + + local should_show_label = ui.shouldShowLabels() + local iconsize = Vector2(18 , 18) + local label_offset = 14 -- enough so that the target rectangle fits + local collapse = iconsize -- size of clusters to be collapsed into single bodies + local click_radius = collapse:length() * 0.5 + -- make click_radius sufficiently smaller than the cluster size + -- to prevent overlap of selection regions + local objectCounter = 0 + local objects_grouped = systemView:GetProjectedGrouped(collapse, 1e64) + if #objects_grouped == 0 then + ui.setNextWindowPos(Vector2(ui.screenWidth, ui.screenHeight) / 2 - ui.calcTextSize(lc.UNEXPLORED_SYSTEM_NO_SYSTEM_VIEW) / 2, "Always") + ui.withStyleColors({["WindowBg"] = svColor.SYSTEMNAME_BACK}, function() + ui.window("NoSystemView", {"NoTitleBar", "AlwaysAutoResize", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus", "NoSavedSettings"}, + function() + ui.text(lc.UNEXPLORED_SYSTEM_NO_SYSTEM_VIEW); + end) + end) + return + end + + for _,group in ipairs(objects_grouped) do + local mainObject = group.mainObject + local mainCoords = Vector2(group.screenCoordinates.x, group.screenCoordinates.y) + + -- indicators + local stackedSize = indicatorSize + local stackStep = Vector2(10, 10) + if group.hasPlayer then + ui.addIcon(mainCoords, icons.square, svColor.PLAYER, stackedSize, ui.anchor.center, ui.anchor.center) + stackedSize = stackedSize + stackStep + end + if group.hasNavTarget then + ui.addIcon(mainCoords, icons.square, svColor.NAV_TARGET, stackedSize, ui.anchor.center, ui.anchor.center) + stackedSize = stackedSize + stackStep + end + if group.hasCombatTarget then + ui.addIcon(mainCoords, icons.square, svColor.COMBAT_TARGET, stackedSize, ui.anchor.center, ui.anchor.center) + stackedSize = stackedSize + stackStep + end + if mainObject.type == Projectable.OBJECT and mainObject.base == Projectable.PLANNER then ui.addIcon(mainCoords, icons.square, svColor.PLANNER, indicatorSize, ui.anchor.center, ui.anchor.center) end + + ui.addIcon(mainCoords, getBodyIcon(mainObject), getColor(mainObject), iconsize, ui.anchor.center, ui.anchor.center) + + if should_show_label then + local label = getLabel(mainObject) + if group.objects then + label = label .. " (" .. #group.objects .. ")" + end + ui.addStyledText(mainCoords + Vector2(label_offset,0), ui.anchor.left, ui.anchor.center, label , getColor(mainObject), pionillium.small) + end + local mp = ui.getMousePos() + + if mainObject.type == Projectable.OBJECT and (mainObject.base == Projectable.SYSTEMBODY or mainObject.base == Projectable.SHIP or mainObject.base == Projectable.PLAYER) then + -- mouse release handler for right button + if (mp - mainCoords):length() < click_radius then + if not ui.isAnyWindowHovered() and ui.isMouseReleased(1) then + ui.openPopup("target" .. objectCounter) + end + end + -- make popup + ui.popup("target" .. objectCounter, function() + local isObject = mainObject.type == Projectable.OBJECT + local isSystemBody = isObject and mainObject.base == Projectable.SYSTEMBODY + local isShip = isObject and not isSystemBody and mainObject.ref:IsShip() + ui.text(getLabel(mainObject)) + ui.separator() + if ui.selectable(lc.CENTER, false, {}) then + systemView:SetSelectedObject(mainObject.type, mainObject.base, mainObject.ref) + end + if (isShip or isSystemBody and mainObject.ref.physicsBody) and ui.selectable(lc.SET_AS_TARGET, false, {}) then + if isSystemBody then + player:SetNavTarget(mainObject.ref.physicsBody) + else + if combatTarget == mainObject.ref then player:SetCombatTarget(nil) end + player:SetNavTarget(mainObject.ref) + end + end + if isShip and ui.selectable(lc.SET_AS_COMBAT_TARGET, false, {}) then + if navTarget == mainObject.ref then player:SetNavTarget(nil) end + player:SetCombatTarget(mainObject.ref) + end + end) + end + -- mouse release handler for left button + if (mp - mainCoords):length() < click_radius then + if not ui.isAnyWindowHovered() and ui.isMouseReleased(0) and mainObject.type == Projectable.OBJECT then + systemView:SetSelectedObject(mainObject.type, mainObject.base, mainObject.ref) + end + end + + objectCounter = objectCounter + 1 + end +end + +local function tabular(data) + if data and #data > 0 then + ui.columns(2, "Attributes", true) + for _,item in pairs(data) do + if item.value then + ui.text(item.name) + ui.nextColumn() + ui.text(item.value) + ui.nextColumn() + end + end + ui.columns(1, "NoAttributes", false) + end +end + +local function showTargetInfoWindow(obj) + if obj.type ~= Projectable.OBJECT or obj.base ~= Projectable.SHIP and obj.base ~= Projectable.SYSTEMBODY then return end + ui.setNextWindowSize(Vector2(ui.screenWidth / 5, 0), "Always") + ui.setNextWindowPos(Vector2(20, (ui.screenHeight / 5) * 2 + 20), "Always") + ui.withStyleColors({["WindowBg"] = svColor.WINDOW_BACK}, function() + ui.window("TargetInfoWindow", {"NoTitleBar", "AlwaysAutoResize", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus", "NoSavedSettings"}, + function() + local data + -- system body + if obj.type == Projectable.OBJECT and obj.base == Projectable.SYSTEMBODY then + local systemBody = obj.ref + local name = systemBody.name + local rp = systemBody.rotationPeriod * 24 * 60 * 60 + local r = systemBody.radius + local radius = nil + if r and r > 0 then + local v,u = ui.Format.Distance(r) + radius = v .. u + end + local sma = systemBody.semiMajorAxis + local semimajoraxis = nil + if sma and sma > 0 then + local v,u = ui.Format.Distance(sma) + semimajoraxis = v .. u + end + local op = systemBody.orbitPeriod * 24 * 60 * 60 + data = { + { name = lc.NAME_OBJECT, + value = name }, + { name = lc.DAY_LENGTH .. lc.ROTATIONAL_PERIOD, + value = rp > 0 and ui.Format.Duration(rp, 2) or nil }, + { name = lc.RADIUS, + value = radius }, + { name = lc.SEMI_MAJOR_AXIS, + value = semimajoraxis }, + { name = lc.ORBITAL_PERIOD, + value = op and op > 0 and ui.Format.Duration(op, 2) or nil } + } + -- physical body + elseif obj.type == Projectable.OBJECT and obj.ref:IsShip() then + local body = obj.ref + local name = body.label + data = {{ name = lc.NAME_OBJECT, value = name }, } + -- TODO: the advanced target scanner should add additional data here, + -- but we really do not want to hardcode that here. there should be + -- some kind of hook that the target scanner can hook into to display + -- more info here. + -- This is what should be inserted: + table.insert(data, { name = luc.SHIP_TYPE, value = body:GetShipType() }) + if player:GetEquipCountOccupied('target_scanner') > 0 or player:GetEquipCountOccupied('advanced_target_scanner') > 0 then + local hd = body:GetEquip("engine", 1) + table.insert(data, { name = lc.HYPERDRIVE, value = hd and hd:GetName() or lc.NO_HYPERDRIVE }) + table.insert(data, { name = lc.MASS, value = Format.MassTonnes(body:GetStats().staticMass) }) + table.insert(data, { name = lc.CARGO, value = Format.MassTonnes(body:GetStats().usedCargo) }) + end + else + data = {} + end + tabular(data) + end) + end) +end + +local function displaySystemViewUI() + player = Game.player + local current_view = Game.CurrentView() + + if current_view == "system" and not Game.InHyperspace() then + selectedObject = systemView:GetSelectedObject() + displayOnScreenObjects() + ui.withFont(ui.fonts.pionillium.medium.name, ui.fonts.pionillium.medium.size, function() + showOrbitPlannerWindow() + showTargetInfoWindow(selectedObject) + end) + showSystemName() + end +end + +Event.Register("onGameStart", onGameStart) +ui.registerModule("game", displaySystemViewUI) + +return {} diff --git a/data/pigui/themes/default.lua b/data/pigui/themes/default.lua index 560bbcb27..5e667b1e5 100644 --- a/data/pigui/themes/default.lua +++ b/data/pigui/themes/default.lua @@ -160,6 +160,7 @@ theme.icons = { shield = 92, hull = 93, temperature = 94, + rotate_view = 95, -- seventh row heavy_cargo_shuttle = 96, medium_cargo_shuttle = 97, diff --git a/scripts/scan_enums.py b/scripts/scan_enums.py index 3c4fbf331..708c7e874 100755 --- a/scripts/scan_enums.py +++ b/scripts/scan_enums.py @@ -373,8 +373,8 @@ def write_header(enums, fl): fl.write('#ifndef HX_GEN_ENUM_TABLES\n') fl.write('#define HX_GEN_ENUM_TABLES\n\n') write_generation_header(fl) - fl.write('struct EnumItem { const char *name; int value; };\n') - fl.write('struct EnumTable { const char *name; const EnumItem *first; };\n\n') + fl.write('struct EnumItem {\n\tconst char *name;\n\tint value;\n};\n') + fl.write('struct EnumTable {\n\tconst char *name;\n\tconst EnumItem *first;\n};\n\n') for e in enums: e.write_c_header(fl) fl.write('\n') diff --git a/src/Space.cpp b/src/Space.cpp index 8d77b4b8f..8fdcca93b 100644 --- a/src/Space.cpp +++ b/src/Space.cpp @@ -16,6 +16,7 @@ #include "Player.h" #include "SpaceStation.h" #include "Star.h" +#include "SystemView.h" #include "collider/CollisionContact.h" #include "collider/CollisionSpace.h" #include "galaxy/Galaxy.h" @@ -1006,6 +1007,7 @@ void Space::UpdateBodies() rmb->SetFrame(FrameId::Invalid); for (Body *b : m_bodies) b->NotifyRemoved(rmb); + if (Pi::GetView()) Pi::game->GetSystemView()->BodyInaccessible(rmb); m_bodies.remove(rmb); } m_removeBodies.clear(); @@ -1013,6 +1015,7 @@ void Space::UpdateBodies() for (Body *killb : m_killBodies) { for (Body *b : m_bodies) b->NotifyRemoved(killb); + if (Pi::GetView()) Pi::game->GetSystemView()->BodyInaccessible(killb); m_bodies.remove(killb); delete killb; } diff --git a/src/SystemView.cpp b/src/SystemView.cpp index 0da52b813..f945713c1 100644 --- a/src/SystemView.cpp +++ b/src/SystemView.cpp @@ -1,10 +1,11 @@ // Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt +#include "lua/LuaPiGui.h" + #include "SystemView.h" #include "AnimationCurves.h" -#include "Frame.h" #include "Game.h" #include "GameLog.h" #include "Input.h" @@ -20,6 +21,7 @@ #include "graphics/Renderer.h" #include "graphics/TextureBuilder.h" #include "lua/LuaObject.h" +#include "lua/LuaTable.h" #include #include @@ -29,8 +31,8 @@ const double SystemView::PICK_OBJECT_RECT_SIZE = 12.0; const Uint16 SystemView::N_VERTICES_MAX = 100; static const float MIN_ZOOM = 1e-30f; // Just to avoid having 0 static const float MAX_ZOOM = 1e30f; -static const float ZOOM_IN_SPEED = 2; -static const float ZOOM_OUT_SPEED = 1.f / ZOOM_IN_SPEED; +static const float ZOOM_IN_SPEED = 3; +static const float ZOOM_OUT_SPEED = 3; static const float WHEEL_SENSITIVITY = .1f; // Should be a variable in user settings. static const double DEFAULT_VIEW_DISTANCE = 10.0; @@ -93,7 +95,7 @@ void TransferPlanner::ResetStartTime() double TransferPlanner::GetStartTime() const { - return m_startTime; + return m_startTime < 0.0 ? 0.0 : m_startTime; } static std::string formatTime(double t) @@ -172,6 +174,16 @@ void TransferPlanner::ResetDv() } } +double TransferPlanner::GetDv(BurnDirection d) +{ + switch (d) { + case PROGRADE: return m_dvPrograde; break; + case NORMAL: return m_dvNormal; break; + case RADIAL: return m_dvRadial; break; + } + return 0.0; +} + std::string TransferPlanner::printDv(BurnDirection d) { double dv = 0; @@ -218,6 +230,9 @@ SystemView::SystemView(Game *game) : m_shipDrawing(OFF), m_showL4L5(LAG_OFF) { + m_rot_y = 0; + m_rot_x = 50; + m_zoom = 1.0f / float(AU); SetTransparency(true); Graphics::RenderStateDesc rsd; @@ -226,206 +241,9 @@ SystemView::SystemView(Game *game) : m_realtime = true; m_unexplored = true; - Gui::Screen::PushFont("OverlayFont"); - m_objectLabels = new Gui::LabelSet(); - Add(m_objectLabels, 0, 0); - m_shipLabels = new Gui::LabelSet(); - m_shipLabels->SetLabelColor(Color(255, 155, 0, 200)); - Add(m_shipLabels, 0, 0); - Gui::Screen::PopFont(); - - m_timePoint = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_timePoint, 2, Gui::Screen::GetHeight() - Gui::Screen::GetFontHeight() - 66); - - m_infoLabel = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_infoLabel, 2, 0); - - m_infoText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_infoText, 200, 0); - - m_zoomOutButton = new Gui::ImageButton("icons/zoom_out.png"); - m_zoomOutButton->SetToolTip(Lang::ZOOM_OUT); - m_zoomOutButton->SetRenderDimensions(30, 22); - Add(m_zoomOutButton, 700, 5); - - m_zoomInButton = new Gui::ImageButton("icons/zoom_in.png"); - m_zoomInButton->SetToolTip(Lang::ZOOM_IN); - m_zoomInButton->SetRenderDimensions(30, 22); - Add(m_zoomInButton, 732, 5); - - m_toggleShipsButton = new Gui::ImageButton("icons/toggle_ships_display.png"); - m_toggleShipsButton->SetToolTip(Lang::SHIPS_DISPLAY_MODE_TOGGLE); - m_toggleShipsButton->SetRenderDimensions(30, 22); - m_toggleShipsButton->onClick.connect(sigc::mem_fun(this, &SystemView::OnToggleShipsButtonClick)); - Add(m_toggleShipsButton, 660, 5); - - // Add the 3 Lagrange button stations - m_toggleL4L5Button = new Gui::MultiStateImageButton(); - m_toggleL4L5Button->AddState(LAG_ICON, "icons/toggle_lag_icon.png"); - m_toggleL4L5Button->AddState(LAG_ICONTEXT, "icons/toggle_lag_icon_text.png"); - m_toggleL4L5Button->AddState(LAG_OFF, "icons/toggle_lag_off.png"); - m_toggleL4L5Button->SetToolTip(Lang::L4L5_DISPLAY_MODE_TOGGLE); - m_toggleL4L5Button->SetRenderDimensions(30, 22); - m_toggleL4L5Button->onClick.connect(sigc::mem_fun(this, &SystemView::OnToggleL4L5ButtonClick)); - Add(m_toggleL4L5Button, 628, 5); - m_toggleL4L5Button->SetActiveState(LAG_OFF); - - m_toggleGridButton = new Gui::ImageButton("icons/toggle_grid_display.png"); - m_toggleGridButton->SetToolTip(Lang::GRID_DISPLAY_MODE_TOGGLE); - m_toggleGridButton->SetRenderDimensions(30, 22); - m_toggleGridButton->onClick.connect(sigc::mem_fun(this, &SystemView::OnToggleGridButtonClick)); - Add(m_toggleGridButton, 596, 5); - - m_ResetOrientButton = new Gui::ImageButton("icons/reset_orient_and_zoom.png"); - m_ResetOrientButton->SetToolTip(Lang::RESET_ORIENTATION_AND_ZOOM); - m_ResetOrientButton->SetRenderDimensions(30, 22); - m_ResetOrientButton->onClick.connect(sigc::mem_fun(this, &SystemView::ResetViewpoint)); - Add(m_ResetOrientButton, 564, 5); - - // orbital transfer planner UI - int dx = 670; - int dy = 40; - - m_plannerIncreaseFactorButton = new Gui::ImageButton("icons/orbit_increase_big.png"); - m_plannerIncreaseFactorButton->SetRenderDimensions(18, 18); - m_plannerIncreaseFactorButton->onClick.connect(sigc::mem_fun(this, &SystemView::OnIncreaseFactorButtonClick)); - Add(m_plannerIncreaseFactorButton, dx + 40, dy); - - m_plannerResetFactorButton = new Gui::ImageButton("icons/orbit_factor_big.png"); - m_plannerResetFactorButton->SetRenderDimensions(18, 18); - m_plannerResetFactorButton->SetToolTip(Lang::PLANNER_RESET_FACTOR); - m_plannerResetFactorButton->onClick.connect(sigc::mem_fun(this, &SystemView::OnResetFactorButtonClick)); - Add(m_plannerResetFactorButton, dx + 20, dy); - - m_plannerDecreaseFactorButton = new Gui::ImageButton("icons/orbit_reduce_big.png"); - m_plannerDecreaseFactorButton->SetRenderDimensions(18, 18); - m_plannerDecreaseFactorButton->onClick.connect(sigc::mem_fun(this, &SystemView::OnDecreaseFactorButtonClick)); - Add(m_plannerDecreaseFactorButton, dx, dy); - - m_plannerFactorText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_plannerFactorText, dx + 60 + 7, dy); - - m_plannerIncreaseStartTimeButton = new Gui::ImageButton("icons/orbit_increase_big.png"); - m_plannerIncreaseStartTimeButton->SetRenderDimensions(18, 18); - Add(m_plannerIncreaseStartTimeButton, dx + 40, dy + 20); - - m_plannerResetStartTimeButton = new Gui::ImageButton("icons/orbit_start_big.png"); - m_plannerResetStartTimeButton->SetRenderDimensions(18, 18); - m_plannerResetStartTimeButton->SetToolTip(Lang::PLANNER_RESET_START); - Add(m_plannerResetStartTimeButton, dx + 20, dy + 20); - - m_plannerDecreaseStartTimeButton = new Gui::ImageButton("icons/orbit_reduce_big.png"); - m_plannerDecreaseStartTimeButton->SetRenderDimensions(18, 18); - Add(m_plannerDecreaseStartTimeButton, dx, dy + 20); - - m_plannerStartTimeText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_plannerStartTimeText, dx + 60, dy + 20); - - m_plannerAddProgradeVelButton = new Gui::ImageButton("icons/orbit_increase_big.png"); - m_plannerAddProgradeVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddProgradeVelButton, dx + 40, dy + 40); - - m_plannerZeroProgradeVelButton = new Gui::ImageButton("icons/orbit_proretro_big.png"); - m_plannerZeroProgradeVelButton->SetRenderDimensions(18, 18); - m_plannerZeroProgradeVelButton->SetToolTip(Lang::PLANNER_RESET_PROGRADE); - Add(m_plannerZeroProgradeVelButton, dx + 20, dy + 40); - - m_plannerAddRetrogradeVelButton = new Gui::ImageButton("icons/orbit_reduce_big.png"); - m_plannerAddRetrogradeVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddRetrogradeVelButton, dx, dy + 40); - - m_plannerProgradeDvText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_plannerProgradeDvText, dx + 60, dy + 40); - - m_plannerAddNormalVelButton = new Gui::ImageButton("icons/orbit_increase_big.png"); - m_plannerAddNormalVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddNormalVelButton, dx + 40, dy + 60); - - m_plannerZeroNormalVelButton = new Gui::ImageButton("icons/orbit_normal_big.png"); - m_plannerZeroNormalVelButton->SetRenderDimensions(18, 18); - m_plannerZeroNormalVelButton->SetToolTip(Lang::PLANNER_RESET_NORMAL); - Add(m_plannerZeroNormalVelButton, dx + 20, dy + 60); - - m_plannerAddAntiNormalVelButton = new Gui::ImageButton("icons/orbit_reduce_big.png"); - m_plannerAddAntiNormalVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddAntiNormalVelButton, dx, dy + 60); - - m_plannerNormalDvText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_plannerNormalDvText, dx + 60, dy + 60); - - m_plannerAddRadiallyInVelButton = new Gui::ImageButton("icons/orbit_increase_big.png"); - m_plannerAddRadiallyInVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddRadiallyInVelButton, dx + 40, dy + 80); - - m_plannerZeroRadialVelButton = new Gui::ImageButton("icons/orbit_radial_big.png"); - m_plannerZeroRadialVelButton->SetRenderDimensions(18, 18); - m_plannerZeroRadialVelButton->SetToolTip(Lang::PLANNER_RESET_RADIAL); - Add(m_plannerZeroRadialVelButton, dx + 20, dy + 80); - - m_plannerAddRadiallyOutVelButton = new Gui::ImageButton("icons/orbit_reduce_big.png"); - m_plannerAddRadiallyOutVelButton->SetRenderDimensions(18, 18); - Add(m_plannerAddRadiallyOutVelButton, dx, dy + 80); - - m_plannerRadialDvText = (new Gui::Label(""))->Color(178, 178, 178); - Add(m_plannerRadialDvText, dx + 60, dy + 80); - - const int time_controls_left = Gui::Screen::GetWidth() - 150; - const int time_controls_top = Gui::Screen::GetHeight() - 86; - - Gui::ImageButton *b = new Gui::ImageButton("icons/sysview_accel_r3.png", "icons/sysview_accel_r3_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -10000000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(26, 17); - Add(b, time_controls_left + 0, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_r2.png", "icons/sysview_accel_r2_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -100000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(19, 17); - Add(b, time_controls_left + 26, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_r1.png", "icons/sysview_accel_r1_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), -1000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(19, 17); - Add(b, time_controls_left + 45, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_rl.png", "icons/sysview_accel_rl_on.png"); - b->onPress.connect(sigc::mem_fun(this, &SystemView::OnClickRealt)); - b->SetRenderDimensions(19, 17); - Add(b, time_controls_left + 64, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_f1.png", "icons/sysview_accel_f1_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 1000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(19, 17); - Add(b, time_controls_left + 83, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_f2.png", "icons/sysview_accel_f2_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 100000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(19, 17); - Add(b, time_controls_left + 102, time_controls_top); - - b = new Gui::ImageButton("icons/sysview_accel_f3.png", "icons/sysview_accel_f3_on.png"); - b->onPress.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 10000000.f)); - b->onRelease.connect(sigc::bind(sigc::mem_fun(this, &SystemView::OnClickAccel), 0.0f)); - b->SetRenderDimensions(26, 17); - Add(b, time_controls_left + 121, time_controls_top); - m_onMouseWheelCon = Pi::input->onMouseWheel.connect(sigc::mem_fun(this, &SystemView::MouseWheel)); - Graphics::TextureBuilder b1 = Graphics::TextureBuilder::UI("icons/periapsis.png"); - m_periapsisIcon.reset(new Gui::TexturedQuad(b1.GetOrCreateTexture(Gui::Screen::GetRenderer(), "ui"))); - Graphics::TextureBuilder b2 = Graphics::TextureBuilder::UI("icons/apoapsis.png"); - m_apoapsisIcon.reset(new Gui::TexturedQuad(b2.GetOrCreateTexture(Gui::Screen::GetRenderer(), "ui"))); - - Graphics::TextureBuilder l4 = Graphics::TextureBuilder::UI("icons/l4.png"); - m_l4Icon.reset(new Gui::TexturedQuad(l4.GetOrCreateTexture(Gui::Screen::GetRenderer(), "ui"))); - Graphics::TextureBuilder l5 = Graphics::TextureBuilder::UI("icons/l5.png"); - m_l5Icon.reset(new Gui::TexturedQuad(l5.GetOrCreateTexture(Gui::Screen::GetRenderer(), "ui"))); - ResetViewpoint(); RefreshShips(); @@ -441,87 +259,29 @@ SystemView::~SystemView() m_onMouseWheelCon.disconnect(); } -void SystemView::OnClickAccel(float step) +void SystemView::AccelerateTime(float step) { m_realtime = false; m_timeStep = step; } -void SystemView::OnIncreaseFactorButtonClick(void) { m_planner->IncreaseFactor(); } -void SystemView::OnResetFactorButtonClick(void) { m_planner->ResetFactor(); } -void SystemView::OnDecreaseFactorButtonClick(void) { m_planner->DecreaseFactor(); } - -void SystemView::OnToggleShipsButtonClick(void) -{ - switch (m_shipDrawing) { - case OFF: - m_shipDrawing = BOXES; - RefreshShips(); - break; - case BOXES: - m_shipDrawing = ORBITS; - RefreshShips(); - break; - case ORBITS: - m_shipDrawing = OFF; - m_shipLabels->Clear(); - break; - } -} - -void SystemView::OnToggleGridButtonClick() -{ - //printf("OnToggleGridButtonClick %i\n", static_cast::type>(m_gridDrawing)); - switch (m_gridDrawing) { - case GridDrawing::OFF: - m_gridDrawing = GridDrawing::GRID; - break; - case GridDrawing::GRID: - m_gridDrawing = GridDrawing::GRID_AND_LEGS; - break; - case GridDrawing::GRID_AND_LEGS: - m_gridDrawing = GridDrawing::OFF; - break; - } -} - -void SystemView::OnToggleL4L5ButtonClick(Gui::MultiStateImageButton *b) -{ - switch (m_showL4L5) { - case LAG_OFF: - m_showL4L5 = LAG_ICON; - m_toggleL4L5Button->SetActiveState(LAG_ICON); - break; - case LAG_ICON: - m_showL4L5 = LAG_ICONTEXT; - m_toggleL4L5Button->SetActiveState(LAG_ICONTEXT); - break; - case LAG_ICONTEXT: - m_showL4L5 = LAG_OFF; - m_toggleL4L5Button->SetActiveState(LAG_OFF); - break; - } -} - -void SystemView::OnClickRealt() +void SystemView::SetRealTime() { m_realtime = true; } void SystemView::ResetViewpoint() { - m_selectedObject = 0; - m_rot_z = 0; - m_rot_x = 50; - m_rot_z_to = m_rot_z; - m_rot_x_to = m_rot_x; - m_zoom = 1.0f / float(AU); - m_zoomTo = m_zoom; + m_selectedObject.type = Projectable::NONE; + m_rot_y_to = 0; + m_rot_x_to = 50; + m_zoomTo = 1.0f / float(AU); m_timeStep = 1.0f; m_time = m_game->GetTime(); } -void SystemView::PutOrbit(const Orbit *orbit, const vector3d &offset, const Color &color, const double planetRadius, const bool showLagrange) +template +void SystemView::PutOrbit(Projectable::bases base, RefType *ref, const Orbit *orbit, const vector3d &offset, const Color &color, const double planetRadius, const bool showLagrange) { double maxT = 1.; unsigned short num_vertices = 0; @@ -573,159 +333,24 @@ void SystemView::PutOrbit(const Orbit *orbit, const vector3d &offset, const Colo Gui::Screen::EnterOrtho(); vector3d pos; if (Gui::Screen::Project(offset + orbit->Perigeum() * double(m_zoom), pos) && pos.z < 1) - m_periapsisIcon->Draw(Pi::renderer, vector2f(pos.x - 3, pos.y - 5), vector2f(6, 10), color); + AddProjected(Projectable::PERIAPSIS, base, ref, pos); if (Gui::Screen::Project(offset + orbit->Apogeum() * double(m_zoom), pos) && pos.z < 1) - m_apoapsisIcon->Draw(Pi::renderer, vector2f(pos.x - 3, pos.y - 5), vector2f(6, 10), color); + AddProjected(Projectable::APOAPSIS, base, ref, pos); if (showLagrange && m_showL4L5 != LAG_OFF) { - const Color LPointColor(0x00d6e2ff); const vector3d posL4 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 60.0, tMinust0); if (Gui::Screen::Project(offset + posL4 * double(m_zoom), pos) && pos.z < 1) { - m_l4Icon->Draw(Pi::renderer, vector2f(pos.x - 2, pos.y - 2), vector2f(4, 4), LPointColor); - if (m_showL4L5 == LAG_ICONTEXT) - m_objectLabels->Add(std::string("L4"), sigc::mem_fun(this, &SystemView::OnClickLagrange), pos.x, pos.y); + AddProjected(Projectable::L4, base, ref, pos); } const vector3d posL5 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 300.0, tMinust0); if (Gui::Screen::Project(offset + posL5 * double(m_zoom), pos) && pos.z < 1) { - m_l5Icon->Draw(Pi::renderer, vector2f(pos.x - 2, pos.y - 2), vector2f(4, 4), LPointColor); - if (m_showL4L5 == LAG_ICONTEXT) - m_objectLabels->Add(std::string("L5"), sigc::mem_fun(this, &SystemView::OnClickLagrange), pos.x, pos.y); + AddProjected(Projectable::L5, base, ref, pos); } } Gui::Screen::LeaveOrtho(); } -void SystemView::OnClickObject(const SystemBody *b) -{ - m_selectedObject = b; - std::string desc; - std::string data; - - desc += std::string(Lang::NAME_OBJECT); - desc += ":\n"; - data += b->GetName() + "\n"; - - desc += std::string(Lang::DAY_LENGTH); - desc += std::string(Lang::ROTATIONAL_PERIOD); - desc += ":\n"; - data += stringf(Lang::N_DAYS, formatarg("days", b->GetRotationPeriodInDays())) + "\n"; - - desc += std::string(Lang::RADIUS); - desc += ":\n"; - data += format_distance(b->GetRadius()) + "\n"; - - if (b->GetParent()) { - desc += std::string(Lang::SEMI_MAJOR_AXIS); - desc += ":\n"; - data += format_distance(b->GetOrbit().GetSemiMajorAxis()) + "\n"; - - desc += std::string(Lang::ORBITAL_PERIOD); - desc += ":\n"; - data += stringf(Lang::N_DAYS, formatarg("days", b->GetOrbit().Period() / (24 * 60 * 60))) + "\n"; - } - m_infoLabel->SetText(desc); - m_infoText->SetText(data); - - // click on object (in same system) sets/unsets it as nav target - SystemPath path = m_system->GetPathOf(b); - if (m_game->GetSpace()->GetStarSystem()->GetPath() == m_system->GetPath()) { - Body *body = m_game->GetSpace()->FindBodyForPath(&path); - if (body != 0) { - if (Pi::player->GetNavTarget() == body) { - Pi::player->SetNavTarget(body); - Pi::player->SetNavTarget(0); - m_game->log->Add(Lang::UNSET_NAVTARGET); - } else { - Pi::player->SetNavTarget(body); - m_game->log->Add(Lang::SET_NAVTARGET_TO + body->GetLabel()); - } - } - } -} - -void SystemView::OnClickLagrange() -{ -} - -void SystemView::PutLabel(const SystemBody *b, const vector3d &offset) -{ - Gui::Screen::EnterOrtho(); - - vector3d pos; - if (Gui::Screen::Project(offset, pos) && pos.z < 1) { - // libsigc++ is a beautiful thing - m_objectLabels->Add(b->GetName(), sigc::bind(sigc::mem_fun(this, &SystemView::OnClickObject), b), pos.x, pos.y); - } - - Gui::Screen::LeaveOrtho(); -} - -void SystemView::LabelShip(Ship *s, const vector3d &offset) -{ - Gui::Screen::EnterOrtho(); - - vector3d pos; - if (Gui::Screen::Project(offset, pos) && pos.z < 1) { - m_shipLabels->Add(s->GetLabel(), sigc::bind(sigc::mem_fun(this, &SystemView::OnClickShip), s), pos.x, pos.y); - } - - Gui::Screen::LeaveOrtho(); -} - -void SystemView::OnClickShip(Ship *s) -{ - if (!s) { - printf("clicked on ship label but ship wasn't there\n"); - return; - } - if (Pi::player->GetNavTarget() == s) { //un-select ship if already selected - Pi::player->SetNavTarget(0); // remove current - m_game->log->Add(Lang::UNSET_NAVTARGET); - m_infoLabel->SetText(""); // remove lingering text - m_infoText->SetText(""); - } else { - Pi::player->SetNavTarget(s); - m_game->log->Add(Lang::SET_NAVTARGET_TO + s->GetLabel()); - - // always show label of selected ship... - std::string text; - text += s->GetLabel(); - text += "\n"; - - // ...if we have advanced target scanner equipment, show some extra info on selected ship - int prop_var = 0; - Pi::player->Properties().Get("target_scanner_level_cap", prop_var); - if (prop_var > 1) { // advanced target scanner - const shipstats_t &stats = s->GetStats(); - - text += s->GetShipType()->name; - text += "\n"; - - lua_State *l = Lua::manager->GetLuaState(); - int clean_stack = lua_gettop(l); - - LuaObject::CallMethod(s, "GetEquip", "engine").PushCopyToStack(); - lua_rawgeti(l, -1, 1); - if (lua_isnil(l, -1)) { - text += Lang::NO_HYPERDRIVE; - } else { - text += LuaTable(l, -1).CallMethod("GetName"); - } - lua_settop(l, clean_stack); - - text += "\n"; - text += stringf(Lang::MASS_N_TONNES, formatarg("mass", stats.static_mass)); - text += "\n"; - text += stringf(Lang::CARGO_N, formatarg("mass", stats.used_cargo)); - text += "\n"; - } - - m_infoLabel->SetText(text); - m_infoText->SetText(""); // clear lingering info from body being selected - } -} - void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matrix4x4f &trans) { if (b->GetType() == SystemBody::TYPE_STARPORT_SURFACE) @@ -735,7 +360,7 @@ void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matr if (!m_bodyIcon) { Graphics::RenderStateDesc rsd; auto solidState = m_renderer->CreateRenderState(rsd); - m_bodyIcon.reset(new Graphics::Drawables::Disk(m_renderer, solidState, Color::WHITE, 1.0f)); + m_bodyIcon.reset(new Graphics::Drawables::Disk(m_renderer, solidState, svColor[SYSTEMBODY], 1.0f)); } const double radius = b->GetRadius() * m_zoom; @@ -752,39 +377,13 @@ void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matr m_renderer->SetTransform(trans); - PutLabel(b, offset); + AddNotProjected(Projectable::OBJECT, Projectable::SYSTEMBODY, b, offset); } Frame *frame = Frame::GetFrame(Pi::player->GetFrame()); if (frame->IsRotFrame()) frame = Frame::GetFrame(frame->GetNonRotFrame()); - // display the players orbit(?) - if (frame->GetSystemBody() == b && frame->GetSystemBody()->GetMass() > 0) { - const double t0 = m_game->GetTime(); - if (Pi::player->IsDocked()) { - if (m_time == t0) PutSelectionBox(offset + Pi::player->GetPositionRelTo(frame->GetId()) * static_cast(m_zoom), Color::RED); - } else { - Orbit playerOrbit = Pi::player->ComputeOrbit(); - - PutOrbit(&playerOrbit, offset, Color::RED, b->GetRadius()); - - const double plannerStartTime = m_planner->GetStartTime(); - if (!m_planner->GetPosition().ExactlyEqual(vector3d(0, 0, 0))) { - Orbit plannedOrbit = Orbit::FromBodyState(m_planner->GetPosition(), - m_planner->GetVel(), - frame->GetSystemBody()->GetMass()); - PutOrbit(&plannedOrbit, offset, Color::STEELBLUE, b->GetRadius()); - if (std::fabs(m_time - t0) > 1. && (m_time - plannerStartTime) > 0.) - PutSelectionBox(offset + plannedOrbit.OrbitalPosAtTime(m_time - plannerStartTime) * static_cast(m_zoom), Color::STEELBLUE); - else - PutSelectionBox(offset + m_planner->GetPosition() * static_cast(m_zoom), Color::STEELBLUE); - } - - PutSelectionBox(offset + playerOrbit.OrbitalPosAtTime(m_time - t0) * double(m_zoom), Color::RED); - } - } - // display all child bodies and their orbits if (b->HasChildren()) { for (const SystemBody *kid : b->GetChildren()) { @@ -795,7 +394,7 @@ void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matr if (axisZoom < DEFAULT_VIEW_DISTANCE) { const SystemBody::BodySuperType bst = kid->GetSuperType(); const bool showLagrange = (bst == SystemBody::SUPERTYPE_ROCKY_PLANET || bst == SystemBody::SUPERTYPE_GAS_GIANT); - PutOrbit(&(kid->GetOrbit()), offset, Color::GREEN, 0.0, showLagrange); + PutOrbit(Projectable::SYSTEMBODY, kid, &(kid->GetOrbit()), offset, svColor[SYSTEMBODY_ORBIT], 0.0, showLagrange); } // not using current time yet @@ -805,62 +404,77 @@ void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matr } } -void SystemView::PutSelectionBox(const SystemBody *b, const vector3d &rootPos, const Color &col) -{ - // surface starports just show the planet as being selected, - // because SystemView doesn't render terrains anyway - if (b->GetType() == SystemBody::TYPE_STARPORT_SURFACE) - b = b->GetParent(); - assert(b); - - vector3d pos = rootPos; - // while (b->parent), not while (b) because the root SystemBody is defined to be at (0,0,0) - while (b->GetParent()) { - pos += b->GetOrbit().OrbitalPosAtTime(m_time) * double(m_zoom); - b = b->GetParent(); - } - - PutSelectionBox(pos, col); -} - -void SystemView::PutSelectionBox(const vector3d &worldPos, const Color &col) -{ - Gui::Screen::EnterOrtho(); - - vector3d screenPos; - if (Gui::Screen::Project(worldPos, screenPos) && screenPos.z < 1) { - // XXX copied from WorldView::DrawTargetSquare -- these should be unified - const float x1 = float(screenPos.x - SystemView::PICK_OBJECT_RECT_SIZE * 0.5); - const float x2 = float(x1 + SystemView::PICK_OBJECT_RECT_SIZE); - const float y1 = float(screenPos.y - SystemView::PICK_OBJECT_RECT_SIZE * 0.5); - const float y2 = float(y1 + SystemView::PICK_OBJECT_RECT_SIZE); - - const vector3f verts[4] = { - vector3f(x1, y1, 0.f), - vector3f(x2, y1, 0.f), - vector3f(x2, y2, 0.f), - vector3f(x1, y2, 0.f) - }; - m_selectBox.SetData(4, &verts[0], col); - m_selectBox.Draw(m_renderer, m_lineState, Graphics::LINE_LOOP); - } - - Gui::Screen::LeaveOrtho(); -} - void SystemView::GetTransformTo(const SystemBody *b, vector3d &pos) { if (b->GetParent()) { GetTransformTo(b->GetParent(), pos); - pos -= double(m_zoom) * b->GetOrbit().OrbitalPosAtTime(m_time); + pos -= b->GetOrbit().OrbitalPosAtTime(m_time); + } +} + +void SystemView::GetTransformTo(Projectable &p, vector3d &pos) +{ + // accept only real objects (no orbit icons or lagrange points) + assert(p.type == Projectable::OBJECT); + pos = vector3d(0., 0., 0.); + if (p.base == Projectable::SYSTEMBODY) + GetTransformTo(p.ref.sbody, pos); + else if (p.ref.body->GetType() == Object::Type::SHIP || p.ref.body->GetType() == Object::Type::PLAYER) { + const Ship *s = static_cast(p.ref.body); + CalculateShipPositionAtTime(s, s->ComputeOrbit(), m_time, pos); + pos = -pos; + // sometimes ships can dissapear from world (i.e. docking / undocking) + if (std::isnan(pos.x)) { // failsafe: calculate parent systembody instead + pos = vector3d(0., 0., 0.); + GetTransformTo(Frame::GetFrame(Frame::GetFrame(Pi::player->GetFrame())->GetNonRotFrame())->GetSystemBody(), pos); + } + } +} + +void SystemView::CalculateShipPositionAtTime(const Ship *s, Orbit o, double t, vector3d &pos) +{ + pos = vector3d(0., 0., 0.); + FrameId shipFrameId = s->GetFrame(); + FrameId shipNonRotFrameId = Frame::GetFrame(shipFrameId)->GetNonRotFrame(); + if (s->GetFlightState() != Ship::FlightState::FLYING) { + vector3d rpos(0.0); + if (Frame::GetFrame(shipFrameId)->IsRotFrame()) { + Frame *rotframe = Frame::GetFrame(shipFrameId); + if (t == m_game->GetTime()) { + pos = s->GetPositionRelTo(m_game->GetSpace()->GetRootFrame()); + return; + } else + rpos = s->GetPositionRelTo(shipNonRotFrameId) * rotframe->GetOrient() * matrix3x3d::RotateY(rotframe->GetAngSpeed() * (t - m_game->GetTime())) * rotframe->GetOrient().Transpose(); + } + vector3d fpos(0.0); + CalculateFramePositionAtTime(shipNonRotFrameId, t, fpos); + pos += fpos + rpos; + } else { + vector3d fpos(0.0); + CalculateFramePositionAtTime(shipNonRotFrameId, t, fpos); + pos += (fpos + o.OrbitalPosAtTime(t - m_game->GetTime())); + } +} + +//frame must be nonrotating +void SystemView::CalculateFramePositionAtTime(FrameId frameId, double t, vector3d &pos) +{ + if (frameId == m_game->GetSpace()->GetRootFrame()) + pos = vector3d(0., 0., 0.); + else { + Frame *frame = Frame::GetFrame(frameId); + CalculateFramePositionAtTime(frame->GetParent(), t, pos); + pos += frame->GetSystemBody()->GetOrbit().OrbitalPosAtTime(t); } } void SystemView::Draw3D() { PROFILE_SCOPED() - m_renderer->SetPerspectiveProjection(50.f, m_renderer->GetDisplayAspect(), 1.f, 1000.f * m_zoom * float(AU) + DEFAULT_VIEW_DISTANCE * 2); + m_renderer->SetPerspectiveProjection(CAMERA_FOV, m_renderer->GetDisplayAspect(), 1.f, 1000.f * m_zoom * float(AU) + DEFAULT_VIEW_DISTANCE * 2); m_renderer->ClearScreen(); + m_projected.clear(); + //TODO add reserve SystemPath path = m_game->GetSectorView()->GetSelected().SystemOnly(); if (m_system) { @@ -876,42 +490,62 @@ void SystemView::Draw3D() m_time += m_timeStep * Pi::GetFrameTime(); } std::string t = Lang::TIME_POINT + format_date(m_time); - m_timePoint->SetText(t); if (!m_system) { m_system = m_game->GetGalaxy()->GetStarSystem(path); m_unexplored = m_system->GetUnexplored(); } - matrix4x4f trans = matrix4x4f::Identity(); - trans.Translate(0, 0, -DEFAULT_VIEW_DISTANCE); - trans.Rotate(DEG2RAD(m_rot_x), 1, 0, 0); - trans.Rotate(DEG2RAD(m_rot_z), 0, 1, 0); - m_renderer->SetTransform(trans); + m_cameraSpace = matrix4x4f::Identity(); + m_cameraSpace.Translate(0, 0, -DEFAULT_VIEW_DISTANCE); + m_cameraSpace.Rotate(DEG2RAD(m_rot_x), 1, 0, 0); + m_cameraSpace.Rotate(DEG2RAD(m_rot_y), 0, 1, 0); + m_renderer->SetTransform(m_cameraSpace); vector3d pos(0, 0, 0); if (m_selectedObject) GetTransformTo(m_selectedObject, pos); // glLineWidth(2); - m_objectLabels->Clear(); - if (m_system->GetUnexplored()) - m_infoLabel->SetText(Lang::UNEXPLORED_SYSTEM_NO_SYSTEM_VIEW); - else { - if (m_system->GetRootBody()) { - PutBody(m_system->GetRootBody().Get(), pos, trans); - if (m_game->GetSpace()->GetStarSystem() == m_system) { - const Body *navTarget = Pi::player->GetNavTarget(); - const SystemBody *navTargetSystemBody = navTarget ? navTarget->GetSystemBody() : 0; - if (navTargetSystemBody) - PutSelectionBox(navTargetSystemBody, pos, Color::GREEN); - } - } + if (!m_system->GetUnexplored() && m_system->GetRootBody()) { + // all systembodies draws here + PutBody(m_system->GetRootBody().Get(), pos, m_cameraSpace); } // glLineWidth(1); - if (m_shipDrawing != OFF) { - RefreshShips(); - DrawShips(m_time - m_game->GetTime(), pos); + if (m_game->GetSpace()->GetStarSystem()->GetPath().IsSameSystem(m_game->GetSectorView()->GetSelected())) { + // draw ships + if (m_shipDrawing != OFF) { + RefreshShips(); + DrawShips(m_time, pos); + } + // draw player and planner + vector3d ppos(0.0); + Orbit playerOrbit = Pi::player->ComputeOrbit(); + Body *PlayerBody = static_cast(Pi::player); + FrameId playerNonRotFrameId = Frame::GetFrame(PlayerBody->GetFrame())->GetNonRotFrame(); + Frame *playerNonRotFrame = Frame::GetFrame(playerNonRotFrameId); + SystemBody *playerAround = playerNonRotFrame->GetSystemBody(); + CalculateShipPositionAtTime(static_cast(Pi::player), playerOrbit, m_time, ppos); + AddNotProjected(Projectable::OBJECT, Projectable::PLAYER, PlayerBody, ppos * m_zoom + pos); + + vector3d offset(0.0); + CalculateFramePositionAtTime(playerNonRotFrameId, m_time, offset); + offset = offset * m_zoom + pos; + + if (Pi::player->GetFlightState() == Ship::FlightState::FLYING) { + PutOrbit(Projectable::PLAYER, PlayerBody, &playerOrbit, offset, svColor[PLAYER_ORBIT], playerAround->GetRadius()); + const double plannerStartTime = m_planner->GetStartTime(); + if (!m_planner->GetPosition().ExactlyEqual(vector3d(0, 0, 0))) { + Orbit plannedOrbit = Orbit::FromBodyState(m_planner->GetPosition(), + m_planner->GetVel(), + playerAround->GetMass()); + PutOrbit(Projectable::PLANNER, PlayerBody, &plannedOrbit, offset, svColor[PLANNER_ORBIT], playerAround->GetRadius()); + if (std::fabs(m_time - m_game->GetTime()) > 1. && (m_time - plannerStartTime) > 0.) + AddNotProjected(Projectable::OBJECT, Projectable::PLANNER, PlayerBody, offset + plannedOrbit.OrbitalPosAtTime(m_time - plannerStartTime) * static_cast(m_zoom)); + else + AddNotProjected(Projectable::OBJECT, Projectable::PLANNER, PlayerBody, offset + m_planner->GetPosition() * static_cast(m_zoom)); + } + } } if (m_gridDrawing != GridDrawing::OFF) { @@ -924,59 +558,6 @@ void SystemView::Draw3D() void SystemView::Update() { const float ft = Pi::GetFrameTime(); - // XXX ugly hack checking for console here - if (!Pi::IsConsoleActive()) { - if (Pi::input->KeyState(SDLK_EQUALS) || - m_zoomInButton->IsPressed()) - m_zoomTo *= pow(ZOOM_IN_SPEED * Pi::GetMoveSpeedShiftModifier(), ft); - if (Pi::input->KeyState(SDLK_MINUS) || - m_zoomOutButton->IsPressed()) - m_zoomTo *= pow(ZOOM_OUT_SPEED / Pi::GetMoveSpeedShiftModifier(), ft); - - // transfer planner buttons - if (m_plannerIncreaseStartTimeButton->IsPressed()) { - m_planner->AddStartTime(10.); - } - if (m_plannerDecreaseStartTimeButton->IsPressed()) { - m_planner->AddStartTime(-10.); - } - if (m_plannerAddProgradeVelButton->IsPressed()) { - m_planner->AddDv(PROGRADE, 10.0); - } - if (m_plannerAddRetrogradeVelButton->IsPressed()) { - m_planner->AddDv(PROGRADE, -10.0); - } - if (m_plannerAddNormalVelButton->IsPressed()) { - m_planner->AddDv(NORMAL, 10.0); - } - if (m_plannerAddAntiNormalVelButton->IsPressed()) { - m_planner->AddDv(NORMAL, -10.0); - } - if (m_plannerAddRadiallyInVelButton->IsPressed()) { - m_planner->AddDv(RADIAL, 10.0); - } - if (m_plannerAddRadiallyOutVelButton->IsPressed()) { - m_planner->AddDv(RADIAL, -10.0); - } - if (m_plannerResetStartTimeButton->IsPressed()) { - m_planner->ResetStartTime(); - } - if (m_plannerZeroProgradeVelButton->IsPressed()) { - m_planner->ResetDv(PROGRADE); - } - if (m_plannerZeroNormalVelButton->IsPressed()) { - m_planner->ResetDv(NORMAL); - } - if (m_plannerZeroRadialVelButton->IsPressed()) { - m_planner->ResetDv(RADIAL); - } - - m_plannerFactorText->SetText(m_planner->printFactor()); - m_plannerStartTimeText->SetText(m_planner->printDeltaTime()); - m_plannerProgradeDvText->SetText(m_planner->printDv(PROGRADE)); - m_plannerNormalDvText->SetText(m_planner->printDv(NORMAL)); - m_plannerRadialDvText->SetText(m_planner->printDv(RADIAL)); - } // TODO: add "true" lower/upper bounds to m_zoomTo / m_zoom m_zoomTo = Clamp(m_zoomTo, MIN_ZOOM, MAX_ZOOM); m_zoom = Clamp(m_zoom, MIN_ZOOM, MAX_ZOOM); @@ -985,13 +566,25 @@ void SystemView::Update() AnimationCurves::Approach(m_zoom, m_zoomTo, ft, 10.f, m_zoomTo / 60.f); AnimationCurves::Approach(m_rot_x, m_rot_x_to, ft); - AnimationCurves::Approach(m_rot_z, m_rot_z_to, ft); + AnimationCurves::Approach(m_rot_y, m_rot_y_to, ft); - if (Pi::input->MouseButtonState(SDL_BUTTON_RIGHT)) { + // to capture mouse when button was pressed and release when released + if (Pi::input->MouseButtonState(SDL_BUTTON_MIDDLE) != m_rotateWithMouseButton) { + m_rotateWithMouseButton = !m_rotateWithMouseButton; + Pi::input->SetCapturingMouse(m_rotateWithMouseButton); + } + + if (m_rotateWithMouseButton || m_rotateView) { int motion[2]; Pi::input->GetMouseMotion(motion); m_rot_x_to += motion[1] * 20 * ft; - m_rot_z_to += motion[0] * 20 * ft; + m_rot_y_to += motion[0] * 20 * ft; + } + else if (m_zoomView) { + Pi::input->SetCapturingMouse(true); + int motion[2]; + Pi::input->GetMouseMotion(motion); + m_zoomTo *= pow(ZOOM_IN_SPEED * 0.003 + 1, -motion[1]); } UIView::Update(); @@ -1001,7 +594,7 @@ void SystemView::MouseWheel(bool up) { if (this == Pi::GetView()) { if (!up) - m_zoomTo *= ((ZOOM_OUT_SPEED - 1) * WHEEL_SENSITIVITY + 1) / Pi::GetMoveSpeedShiftModifier(); + m_zoomTo *= 1 / ((ZOOM_OUT_SPEED - 1) * WHEEL_SENSITIVITY + 1) / Pi::GetMoveSpeedShiftModifier(); else m_zoomTo *= ((ZOOM_IN_SPEED - 1) * WHEEL_SENSITIVITY + 1) * Pi::GetMoveSpeedShiftModifier(); } @@ -1010,9 +603,6 @@ void SystemView::MouseWheel(bool up) void SystemView::RefreshShips(void) { m_contacts.clear(); - if (!m_game->GetSpace()->GetStarSystem()->GetPath().IsSameSystem(m_game->GetSectorView()->GetSelected())) - return; - auto bs = m_game->GetSpace()->GetBodies(); for (auto s = bs.begin(); s != bs.end(); s++) { if ((*s) != Pi::player && @@ -1026,26 +616,19 @@ void SystemView::RefreshShips(void) void SystemView::DrawShips(const double t, const vector3d &offset) { - m_shipLabels->Clear(); + // offset - translate vector to selected object, scaled to camera scale for (auto s = m_contacts.begin(); s != m_contacts.end(); s++) { - vector3d pos = offset; - if ((*s).first->GetFlightState() != Ship::FlightState::FLYING) { - FrameId frameId = Pi::game->GetSpace()->GetRootFrame(); - pos += (*s).first->GetPositionRelTo(frameId) * double(m_zoom); - } else { - FrameId frameId = (*s).first->GetFrame(); - vector3d bpos = vector3d(0., 0., 0.); - if (frameId != Pi::game->GetSpace()->GetRootFrame()) { - Frame *frame = Frame::GetFrame(frameId); - bpos += frame->GetPositionRelTo(Pi::game->GetSpace()->GetRootFrame()); - } - pos += (bpos + (*s).second.OrbitalPosAtTime(t)) * double(m_zoom); + vector3d pos(0.0); + CalculateShipPositionAtTime((*s).first, (*s).second, t, pos); + pos = pos * m_zoom + offset; + //draw highlighted orbit for selected ship + const bool isSelected = m_selectedObject.type == Projectable::OBJECT && m_selectedObject.base != Projectable::SYSTEMBODY && m_selectedObject.ref.body == (*s).first; + AddNotProjected(Projectable::OBJECT, Projectable::SHIP, static_cast((*s).first), pos); + if (m_shipDrawing == ORBITS && (*s).first->GetFlightState() == Ship::FlightState::FLYING) { + vector3d framepos(0.0); + CalculateFramePositionAtTime(Frame::GetFrame((*s).first->GetFrame())->GetNonRotFrame(), m_time, framepos); + PutOrbit(Projectable::SHIP, static_cast((*s).first), &(*s).second, offset + framepos * m_zoom, isSelected ? svColor[SELECTED_SHIP_ORBIT] : svColor[SHIP_ORBIT], 0); } - const bool isNavTarget = Pi::player->GetNavTarget() == (*s).first; - PutSelectionBox(pos, isNavTarget ? Color::GREEN : Color::BLUE); - LabelShip((*s).first, pos); - if (m_shipDrawing == ORBITS && (*s).first->GetFlightState() == Ship::FlightState::FLYING) - PutOrbit(&(*s).second, offset, isNavTarget ? Color::GREEN : Color::BLUE, 0); } } @@ -1070,28 +653,136 @@ void SystemView::DrawGrid() float zoom = m_zoom * float(AU); vector3d pos(0.); - if (m_selectedObject) GetTransformTo(m_selectedObject, pos); + if (m_selectedObject.type != Projectable::NONE) GetTransformTo(m_selectedObject, pos); + pos *= m_zoom; for (int i = -m_grid_lines; i < m_grid_lines + 1; i++) { float z = float(i) * zoom; - m_lineVerts->Add(vector3f(-m_grid_lines * zoom, 0.0f, z) + vector3f(pos), Color::GRAY); - m_lineVerts->Add(vector3f(+m_grid_lines * zoom, 0.0f, z) + vector3f(pos), Color::GRAY); + m_lineVerts->Add(vector3f(-m_grid_lines * zoom, 0.0f, z) + vector3f(pos), svColor[GRID]); + m_lineVerts->Add(vector3f(+m_grid_lines * zoom, 0.0f, z) + vector3f(pos), svColor[GRID]); } for (int i = -m_grid_lines; i < m_grid_lines + 1; i++) { float x = float(i) * zoom; - m_lineVerts->Add(vector3f(x, 0.0f, -m_grid_lines * zoom) + vector3f(pos), Color::GRAY); - m_lineVerts->Add(vector3f(x, 0.0f, +m_grid_lines * zoom) + vector3f(pos), Color::GRAY); + m_lineVerts->Add(vector3f(x, 0.0f, -m_grid_lines * zoom) + vector3f(pos), svColor[GRID]); + m_lineVerts->Add(vector3f(x, 0.0f, +m_grid_lines * zoom) + vector3f(pos), svColor[GRID]); } for (SystemBody *sbody : m_displayed_sbody) { vector3d offset(0.); GetTransformTo(sbody, offset); - m_lineVerts->Add(vector3f(pos - offset), Color::GRAY * 0.5); + offset *= m_zoom; + m_lineVerts->Add(vector3f(pos - offset), svColor[GRID] * 0.5); offset.y = 0.0; - m_lineVerts->Add(vector3f(pos - offset), Color::GRAY * 0.5); + m_lineVerts->Add(vector3f(pos - offset), svColor[GRID] * 0.5); } m_lines.SetData(m_lineVerts->GetNumVerts(), &m_lineVerts->position[0], &m_lineVerts->diffuse[0]); m_lines.Draw(Pi::renderer, m_lineState); } + +template +void SystemView::AddNotProjected(Projectable::types type, Projectable::bases base, T *ref, const vector3d &worldscaledpos) +{ + //project and add + Gui::Screen::EnterOrtho(); + vector3d pos; + if (Gui::Screen::Project(worldscaledpos, pos) && pos.z < 1) + AddProjected(type, base, ref, pos); + Gui::Screen::LeaveOrtho(); +} + +template +void SystemView::AddProjected(Projectable::types type, Projectable::bases base, T *ref, vector3d &pos) +{ + float scale[2]; + Gui::Screen::GetCoords2Pixels(scale); + Projectable p(type, base, ref); + p.screenpos.x = pos.x / scale[0]; + p.screenpos.y = pos.y / scale[1]; + p.screenpos.z = pos.z; + m_projected.push_back(p); +} + +// SystemBody can't be inaccessible +void SystemView::BodyInaccessible(Body *b) +{ + if (m_selectedObject.type == Projectable::OBJECT && m_selectedObject.base != Projectable::SYSTEMBODY && m_selectedObject.ref.body == b) + ResetViewpoint(); +} + +void SystemView::SetVisibility(std::string param) +{ + if (param == "RESET_VIEW") + ResetViewpoint(); + else if (param == "GRID_OFF") + m_gridDrawing = GridDrawing::OFF; + else if (param == "GRID_ON") + m_gridDrawing = GridDrawing::GRID; + else if (param == "GRID_AND_LEGS") + m_gridDrawing = GridDrawing::GRID_AND_LEGS; + else if (param == "LAG_OFF") + m_showL4L5 = LAG_OFF; + else if (param == "LAG_ICON") + m_showL4L5 = LAG_ICON; + else if (param == "LAG_ICONTEXT") + m_showL4L5 = LAG_ICONTEXT; + else if (param == "SHIPS_OFF") + m_shipDrawing = OFF; + else if (param == "SHIPS_ON") + m_shipDrawing = BOXES; + else if (param == "SHIPS_ORBITS") + m_shipDrawing = ORBITS; + else + Output("Unknown visibility: %s\n", param.c_str()); +} + +void SystemView::SetZoomMode(bool enable) +{ + if (enable != m_zoomView) { + Pi::input->SetCapturingMouse(enable); + m_zoomView = enable; + if (m_zoomView) m_rotateView = false; + } +} + +void SystemView::SetRotateMode(bool enable) { + if (enable != m_rotateView) { + Pi::input->SetCapturingMouse(enable); + m_rotateView = enable; + if (m_rotateView) m_zoomView = false; + } +} + +Projectable *SystemView::GetSelectedObject() +{ + return &m_selectedObject; +} + +void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases base, SystemBody *sb) +{ + m_selectedObject.type = type; + m_selectedObject.base = base; + m_selectedObject.ref.sbody = sb; + m_animateTransition = MAX_TRANSITION_FRAMES; +} + +void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases base, Body *b) +{ + m_selectedObject.type = type; + m_selectedObject.base = base; + m_selectedObject.ref.body = b; + m_animateTransition = MAX_TRANSITION_FRAMES; +} + +double SystemView::ProjectedSize(double size, vector3d pos) +{ + matrix4x4d dtrans; + matrix4x4ftod(m_cameraSpace, dtrans); + pos = dtrans * pos; //position in camera space to know distance + double result = size / pos.Length() / CAMERA_FOV_RADIANS; + return result; +} + +double SystemView::GetOrbitTime(double t, const SystemBody *b) { return t; } +double SystemView::GetOrbitTime(double t, const Body *b) { return t - m_game->GetTime(); } diff --git a/src/SystemView.h b/src/SystemView.h index f8f7ef024..fbf335a7e 100644 --- a/src/SystemView.h +++ b/src/SystemView.h @@ -9,12 +9,15 @@ #include "graphics/Drawables.h" #include "matrix4x4.h" #include "vector3.h" +#include "enum_table.h" +#include "Frame.h" class StarSystem; class SystemBody; class Orbit; class Ship; class Game; +class Body; enum BurnDirection { PROGRADE, @@ -51,7 +54,9 @@ public: void IncreaseFactor(), ResetFactor(), DecreaseFactor(); void AddStartTime(double timeStep); void ResetStartTime(); + double GetFactor() const { return m_factor; } void AddDv(BurnDirection d, double dv); + double GetDv(BurnDirection d); void ResetDv(BurnDirection d); void ResetDv(); std::string printDeltaTime(); @@ -69,85 +74,126 @@ private: double m_startTime; }; -class SystemView : public UIView { +struct Projectable +{ + enum types { // + NONE = 0, // empty projectable, don't try to get members + OBJECT = 1, // clickable space object, may be without phys.body (other starsystem) + L4 = 2, + L5 = 3, + APOAPSIS = 4, + PERIAPSIS = 5 + } type; + enum bases { // + SYSTEMBODY = 0, // ref class SystemBody, may not have a physical body + BODY = 1, // generic body + SHIP = 2, + PLAYER = 3, // player's ship + PLANNER = 4 // player's ship planned by transfer planner, refers to player's object + } base; + union{ + const Body* body; + const SystemBody* sbody; + } ref; + vector3d screenpos; // x,y - screen coordinate, z - in NDC + + Projectable(const types t, const bases b, const Body* obj) : type(t), base(b) + { + ref.body = obj; + } + Projectable(const types t, const bases b, const SystemBody* obj) : type(t), base(b) + { + ref.sbody = obj; + } + Projectable() : type(NONE) {} +}; + +class SystemView : public UIView, public DeleteEmitter { public: SystemView(Game *game); virtual ~SystemView(); virtual void Update(); virtual void Draw3D(); + virtual void OnSwitchTo() { Update(); Draw3D(); } + + Projectable* GetSelectedObject(); + void SetSelectedObject(Projectable::types type, Projectable::bases base, SystemBody *sb); + void SetSelectedObject(Projectable::types type, Projectable::bases base, Body *b); + TransferPlanner* GetTransferPlanner() const { return m_planner; } + double GetOrbitPlannerStartTime() const { return m_planner->GetStartTime(); } + double GetOrbitPlannerTime() const { return m_time; } + void AccelerateTime(float step); + void SetRealTime(); + std::vector GetProjected() const { return m_projected; } + void BodyInaccessible(Body *b); + void SetVisibility(std::string param); + void SetZoomMode(bool enable); + void SetRotateMode(bool enable); + + // all used colors. defined in system-view-ui.lua + enum ColorIndex { // + GRID = 0, + SYSTEMBODY = 1, + SYSTEMBODY_ORBIT = 2, + PLAYER_ORBIT = 3, + PLANNER_ORBIT = 4, + SELECTED_SHIP_ORBIT = 5, + SHIP_ORBIT = 6 + }; + + Color svColor[7]; + void SetColor(ColorIndex color_index, Color* color_value) { svColor[color_index] = *color_value; } private: + bool m_rotateWithMouseButton = false; + bool m_rotateView = false; + bool m_zoomView = false; + std::vector m_projected; static const double PICK_OBJECT_RECT_SIZE; static const Uint16 N_VERTICES_MAX; - void PutOrbit(const Orbit *orb, const vector3d &offset, const Color &color, const double planetRadius = 0.0, const bool showLagrange = false); + const float CAMERA_FOV = 50.f; + const float CAMERA_FOV_RADIANS = CAMERA_FOV / 57.295779f; + matrix4x4f m_cameraSpace; + template + void PutOrbit(Projectable::bases base, RefType *ref, const Orbit *orb, const vector3d &offset, const Color &color, const double planetRadius = 0.0, const bool showLagrange = false); void PutBody(const SystemBody *b, const vector3d &offset, const matrix4x4f &trans); - void PutLabel(const SystemBody *b, const vector3d &offset); - void PutSelectionBox(const SystemBody *b, const vector3d &rootPos, const Color &col); - void PutSelectionBox(const vector3d &worldPos, const Color &col); void GetTransformTo(const SystemBody *b, vector3d &pos); - void OnClickObject(const SystemBody *b); - void OnClickLagrange(); - void OnClickAccel(float step); - void OnClickRealt(); - void OnIncreaseFactorButtonClick(void), OnResetFactorButtonClick(void), OnDecreaseFactorButtonClick(void); - void OnIncreaseStartTimeButtonClick(void), OnResetStartTimeButtonClick(void), OnDecreaseStartTimeButtonClick(void); - void OnToggleShipsButtonClick(void); - void OnToggleGridButtonClick(void); - void OnToggleL4L5ButtonClick(Gui::MultiStateImageButton *); + void GetTransformTo(Projectable &p, vector3d &pos); void ResetViewpoint(); void MouseWheel(bool up); void RefreshShips(void); void DrawShips(const double t, const vector3d &offset); void PrepareGrid(); void DrawGrid(); - void LabelShip(Ship *s, const vector3d &offset); - void OnClickShip(Ship *s); + template + void AddProjected(Projectable::types type, Projectable::bases base, T *ref, vector3d &pos); + template + void AddNotProjected(Projectable::types type, Projectable::bases base, T *ref, const vector3d &worldscaledpos); + void CalculateShipPositionAtTime(const Ship *s, Orbit o, double t, vector3d &pos); + void CalculateFramePositionAtTime(FrameId frameId, double t, vector3d &pos); + double GetOrbitTime(double t, const SystemBody* b); + double GetOrbitTime(double t, const Body* b); Game *m_game; RefCountedPtr m_system; - const SystemBody *m_selectedObject; + Projectable m_selectedObject; std::vector m_displayed_sbody; bool m_unexplored; ShowLagrange m_showL4L5; TransferPlanner *m_planner; std::list> m_contacts; - Gui::LabelSet *m_shipLabels; ShipDrawing m_shipDrawing; GridDrawing m_gridDrawing; int m_grid_lines; - float m_rot_x, m_rot_z; - float m_rot_x_to, m_rot_z_to; + float m_rot_x, m_rot_y; + float m_rot_x_to, m_rot_y_to; float m_zoom, m_zoomTo; double m_time; bool m_realtime; double m_timeStep; - Gui::ImageButton *m_zoomInButton; - Gui::ImageButton *m_zoomOutButton; - Gui::ImageButton *m_toggleShipsButton; - Gui::ImageButton *m_toggleGridButton; - Gui::ImageButton *m_ResetOrientButton; - Gui::MultiStateImageButton *m_toggleL4L5Button; - Gui::ImageButton *m_plannerIncreaseStartTimeButton, *m_plannerResetStartTimeButton, *m_plannerDecreaseStartTimeButton; - Gui::ImageButton *m_plannerIncreaseFactorButton, *m_plannerResetFactorButton, *m_plannerDecreaseFactorButton; - Gui::ImageButton *m_plannerAddProgradeVelButton; - Gui::ImageButton *m_plannerAddRetrogradeVelButton; - Gui::ImageButton *m_plannerAddNormalVelButton; - Gui::ImageButton *m_plannerAddAntiNormalVelButton; - Gui::ImageButton *m_plannerAddRadiallyInVelButton; - Gui::ImageButton *m_plannerAddRadiallyOutVelButton; - Gui::ImageButton *m_plannerZeroProgradeVelButton, *m_plannerZeroNormalVelButton, *m_plannerZeroRadialVelButton; - Gui::Label *m_timePoint; - Gui::Label *m_infoLabel; - Gui::Label *m_infoText; - Gui::Label *m_plannerFactorText, *m_plannerStartTimeText, *m_plannerProgradeDvText, *m_plannerNormalDvText, *m_plannerRadialDvText; - Gui::LabelSet *m_objectLabels; sigc::connection m_onMouseWheelCon; std::unique_ptr m_bodyIcon; - std::unique_ptr m_l4Icon; - std::unique_ptr m_l5Icon; - std::unique_ptr m_periapsisIcon; - std::unique_ptr m_apoapsisIcon; Graphics::RenderState *m_lineState; Graphics::Drawables::Lines m_orbits; Graphics::Drawables::Lines m_selectBox; @@ -157,7 +203,6 @@ private: std::unique_ptr m_lineVerts; Graphics::Drawables::Lines m_lines; - }; #endif /* _SYSTEMVIEW_H */ diff --git a/src/enum_table.cpp b/src/enum_table.cpp index 339e3d2b1..0c7d8cf6d 100644 --- a/src/enum_table.cpp +++ b/src/enum_table.cpp @@ -10,15 +10,17 @@ #include "Ship.h" #include "ShipAICmd.h" #include "ShipType.h" +#include "SystemView.h" #include "galaxy/Economy.h" #include "galaxy/Polit.h" -#include "galaxy/StarSystem.h" +#include "galaxy/SystemBody.h" #include "gameui/Face.h" #include "lua/LuaEngine.h" #include "lua/LuaFileSystem.h" +#include "pigui/Face.h" #include "scenegraph/Model.h" -#include "ship/PlayerShipController.h" #include "ship/Propulsion.h" +#include "ship/ShipController.h" #include "ui/Align.h" #include "ui/Animation.h" #include "ui/Event.h" @@ -37,21 +39,6 @@ const struct EnumItem ENUM_ShipAIError[] = { { 0, 0 }, }; -const struct EnumItem ENUM_DetailLevel[] = { - { "VERY_LOW", int(LuaEngine::DETAIL_VERY_LOW) }, - { "LOW", int(LuaEngine::DETAIL_LOW) }, - { "MEDIUM", int(LuaEngine::DETAIL_MEDIUM) }, - { "HIGH", int(LuaEngine::DETAIL_HIGH) }, - { "VERY_HIGH", int(LuaEngine::DETAIL_VERY_HIGH) }, - { 0, 0 }, -}; - -const struct EnumItem ENUM_FileSystemRoot[] = { - { "USER", int(LuaFileSystem::ROOT_USER) }, - { "DATA", int(LuaFileSystem::ROOT_DATA) }, - { 0, 0 }, -}; - const struct EnumItem ENUM_PhysicsObjectType[] = { { "BODY", int(Object::BODY) }, { "MODELBODY", int(Object::MODELBODY) }, @@ -65,52 +52,6 @@ const struct EnumItem ENUM_PhysicsObjectType[] = { { 0, 0 }, }; -const struct EnumItem ENUM_PolitEcon[] = { - { "NONE", int(Polit::ECON_NONE) }, - { "VERY_CAPITALIST", int(Polit::ECON_VERY_CAPITALIST) }, - { "CAPITALIST", int(Polit::ECON_CAPITALIST) }, - { "MIXED", int(Polit::ECON_MIXED) }, - { "PLANNED", int(Polit::ECON_PLANNED) }, - { 0, 0 }, -}; - -const struct EnumItem ENUM_PolitGovType[] = { - { "NONE", int(Polit::GOV_NONE) }, - { "EARTHCOLONIAL", int(Polit::GOV_EARTHCOLONIAL) }, - { "EARTHDEMOC", int(Polit::GOV_EARTHDEMOC) }, - { "EMPIRERULE", int(Polit::GOV_EMPIRERULE) }, - { "CISLIBDEM", int(Polit::GOV_CISLIBDEM) }, - { "CISSOCDEM", int(Polit::GOV_CISSOCDEM) }, - { "LIBDEM", int(Polit::GOV_LIBDEM) }, - { "CORPORATE", int(Polit::GOV_CORPORATE) }, - { "SOCDEM", int(Polit::GOV_SOCDEM) }, - { "EARTHMILDICT", int(Polit::GOV_EARTHMILDICT) }, - { "MILDICT1", int(Polit::GOV_MILDICT1) }, - { "MILDICT2", int(Polit::GOV_MILDICT2) }, - { "EMPIREMILDICT", int(Polit::GOV_EMPIREMILDICT) }, - { "COMMUNIST", int(Polit::GOV_COMMUNIST) }, - { "PLUTOCRATIC", int(Polit::GOV_PLUTOCRATIC) }, - { "DISORDER", int(Polit::GOV_DISORDER) }, - { 0, 0 }, -}; - -const struct EnumItem ENUM_ShipTypeThruster[] = { - { "REVERSE", int(Thruster::THRUSTER_REVERSE) }, - { "FORWARD", int(Thruster::THRUSTER_FORWARD) }, - { "UP", int(Thruster::THRUSTER_UP) }, - { "DOWN", int(Thruster::THRUSTER_DOWN) }, - { "LEFT", int(Thruster::THRUSTER_LEFT) }, - { "RIGHT", int(Thruster::THRUSTER_RIGHT) }, - { 0, 0 }, -}; - -const struct EnumItem ENUM_PropulsionFuelStatus[] = { - { "OK", int(Propulsion::FUEL_OK) }, - { "WARNING", int(Propulsion::FUEL_WARNING) }, - { "EMPTY", int(Propulsion::FUEL_EMPTY) }, - { 0, 0 }, -}; - const struct EnumItem ENUM_ShipFlightState[] = { { "FLYING", int(Ship::FLYING) }, { "DOCKING", int(Ship::DOCKING) }, @@ -138,6 +79,7 @@ const struct EnumItem ENUM_ShipAlertStatus[] = { { "NONE", int(Ship::ALERT_NONE) }, { "SHIP_NEARBY", int(Ship::ALERT_SHIP_NEARBY) }, { "SHIP_FIRING", int(Ship::ALERT_SHIP_FIRING) }, + { "MISSILE_DETECTED", int(Ship::ALERT_MISSILE_DETECTED) }, { 0, 0 }, }; @@ -153,20 +95,6 @@ const struct EnumItem ENUM_ShipAICmdName[] = { { 0, 0 }, }; -const struct EnumItem ENUM_ShipControllerFlightControlState[] = { - { "CONTROL_MANUAL", int(FlightControlState::CONTROL_MANUAL) }, - { "CONTROL_FIXSPEED", int(FlightControlState::CONTROL_FIXSPEED) }, - { "CONTROL_FIXHEADING_FORWARD", int(FlightControlState::CONTROL_FIXHEADING_FORWARD) }, - { "CONTROL_FIXHEADING_BACKWARD", int(FlightControlState::CONTROL_FIXHEADING_BACKWARD) }, - { "CONTROL_FIXHEADING_NORMAL", int(FlightControlState::CONTROL_FIXHEADING_NORMAL) }, - { "CONTROL_FIXHEADING_ANTINORMAL", int(FlightControlState::CONTROL_FIXHEADING_ANTINORMAL) }, - { "CONTROL_FIXHEADING_RADIALLY_INWARD", int(FlightControlState::CONTROL_FIXHEADING_RADIALLY_INWARD) }, - { "CONTROL_FIXHEADING_RADIALLY_OUTWARD", int(FlightControlState::CONTROL_FIXHEADING_RADIALLY_OUTWARD) }, - { "CONTROL_FIXHEADING_KILLROT", int(FlightControlState::CONTROL_FIXHEADING_KILLROT) }, - { "CONTROL_AUTOPILOT", int(FlightControlState::CONTROL_AUTOPILOT) }, - { 0, 0 }, -}; - const struct EnumItem ENUM_DualLaserOrientation[] = { { "HORIZONTAL", int(ShipType::DUAL_LASERS_HORIZONTAL) }, { "VERTICAL", int(ShipType::DUAL_LASERS_VERTICAL) }, @@ -181,6 +109,36 @@ const struct EnumItem ENUM_ShipTypeTag[] = { { 0, 0 }, }; +const struct EnumItem ENUM_ProjectableTypes[] = { + { "NONE", int(Projectable::NONE) }, + { "OBJECT", int(Projectable::OBJECT) }, + { "L4", int(Projectable::L4) }, + { "L5", int(Projectable::L5) }, + { "APOAPSIS", int(Projectable::APOAPSIS) }, + { "PERIAPSIS", int(Projectable::PERIAPSIS) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_ProjectableBases[] = { + { "SYSTEMBODY", int(Projectable::SYSTEMBODY) }, + { "BODY", int(Projectable::BODY) }, + { "SHIP", int(Projectable::SHIP) }, + { "PLAYER", int(Projectable::PLAYER) }, + { "PLANNER", int(Projectable::PLANNER) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_SystemViewColorIndex[] = { + { "GRID", int(SystemView::GRID) }, + { "SYSTEMBODY", int(SystemView::SYSTEMBODY) }, + { "SYSTEMBODY_ORBIT", int(SystemView::SYSTEMBODY_ORBIT) }, + { "PLAYER_ORBIT", int(SystemView::PLAYER_ORBIT) }, + { "PLANNER_ORBIT", int(SystemView::PLANNER_ORBIT) }, + { "SELECTED_SHIP_ORBIT", int(SystemView::SELECTED_SHIP_ORBIT) }, + { "SHIP_ORBIT", int(SystemView::SHIP_ORBIT) }, + { 0, 0 }, +}; + const struct EnumItem ENUM_EconType[] = { { "MINING", int(GalacticEconomy::ECON_MINING) }, { "AGRICULTURE", int(GalacticEconomy::ECON_AGRICULTURE) }, @@ -223,6 +181,35 @@ const struct EnumItem ENUM_CommodityType[] = { { 0, 0 }, }; +const struct EnumItem ENUM_PolitEcon[] = { + { "NONE", int(Polit::ECON_NONE) }, + { "VERY_CAPITALIST", int(Polit::ECON_VERY_CAPITALIST) }, + { "CAPITALIST", int(Polit::ECON_CAPITALIST) }, + { "MIXED", int(Polit::ECON_MIXED) }, + { "PLANNED", int(Polit::ECON_PLANNED) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_PolitGovType[] = { + { "NONE", int(Polit::GOV_NONE) }, + { "EARTHCOLONIAL", int(Polit::GOV_EARTHCOLONIAL) }, + { "EARTHDEMOC", int(Polit::GOV_EARTHDEMOC) }, + { "EMPIRERULE", int(Polit::GOV_EMPIRERULE) }, + { "CISLIBDEM", int(Polit::GOV_CISLIBDEM) }, + { "CISSOCDEM", int(Polit::GOV_CISSOCDEM) }, + { "LIBDEM", int(Polit::GOV_LIBDEM) }, + { "CORPORATE", int(Polit::GOV_CORPORATE) }, + { "SOCDEM", int(Polit::GOV_SOCDEM) }, + { "EARTHMILDICT", int(Polit::GOV_EARTHMILDICT) }, + { "MILDICT1", int(Polit::GOV_MILDICT1) }, + { "MILDICT2", int(Polit::GOV_MILDICT2) }, + { "EMPIREMILDICT", int(Polit::GOV_EMPIREMILDICT) }, + { "COMMUNIST", int(Polit::GOV_COMMUNIST) }, + { "PLUTOCRATIC", int(Polit::GOV_PLUTOCRATIC) }, + { "DISORDER", int(Polit::GOV_DISORDER) }, + { 0, 0 }, +}; + const struct EnumItem ENUM_BodyType[] = { { "GRAVPOINT", int(SystemBody::TYPE_GRAVPOINT) }, { "BROWN_DWARF", int(SystemBody::TYPE_BROWN_DWARF) }, @@ -286,6 +273,29 @@ const struct EnumItem ENUM_GameUIFaceFlags[] = { { 0, 0 }, }; +const struct EnumItem ENUM_DetailLevel[] = { + { "VERY_LOW", int(LuaEngine::DETAIL_VERY_LOW) }, + { "LOW", int(LuaEngine::DETAIL_LOW) }, + { "MEDIUM", int(LuaEngine::DETAIL_MEDIUM) }, + { "HIGH", int(LuaEngine::DETAIL_HIGH) }, + { "VERY_HIGH", int(LuaEngine::DETAIL_VERY_HIGH) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_FileSystemRoot[] = { + { "USER", int(LuaFileSystem::ROOT_USER) }, + { "DATA", int(LuaFileSystem::ROOT_DATA) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_PiGUIFaceFlags[] = { + { "RAND", int(PiGUI::Face::RAND) }, + { "MALE", int(PiGUI::Face::MALE) }, + { "FEMALE", int(PiGUI::Face::FEMALE) }, + { "ARMOUR", int(PiGUI::Face::ARMOUR) }, + { 0, 0 }, +}; + const struct EnumItem ENUM_ModelDebugFlags[] = { { "NONE", int(SceneGraph::Model::DEBUG_NONE) }, { "BBOX", int(SceneGraph::Model::DEBUG_BBOX) }, @@ -296,6 +306,37 @@ const struct EnumItem ENUM_ModelDebugFlags[] = { { 0, 0 }, }; +const struct EnumItem ENUM_ShipTypeThruster[] = { + { "REVERSE", int(Thruster::THRUSTER_REVERSE) }, + { "FORWARD", int(Thruster::THRUSTER_FORWARD) }, + { "UP", int(Thruster::THRUSTER_UP) }, + { "DOWN", int(Thruster::THRUSTER_DOWN) }, + { "LEFT", int(Thruster::THRUSTER_LEFT) }, + { "RIGHT", int(Thruster::THRUSTER_RIGHT) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_PropulsionFuelStatus[] = { + { "OK", int(Propulsion::FUEL_OK) }, + { "WARNING", int(Propulsion::FUEL_WARNING) }, + { "EMPTY", int(Propulsion::FUEL_EMPTY) }, + { 0, 0 }, +}; + +const struct EnumItem ENUM_ShipControllerFlightControlState[] = { + { "CONTROL_MANUAL", int(FlightControlState::CONTROL_MANUAL) }, + { "CONTROL_FIXSPEED", int(FlightControlState::CONTROL_FIXSPEED) }, + { "CONTROL_FIXHEADING_FORWARD", int(FlightControlState::CONTROL_FIXHEADING_FORWARD) }, + { "CONTROL_FIXHEADING_BACKWARD", int(FlightControlState::CONTROL_FIXHEADING_BACKWARD) }, + { "CONTROL_FIXHEADING_NORMAL", int(FlightControlState::CONTROL_FIXHEADING_NORMAL) }, + { "CONTROL_FIXHEADING_ANTINORMAL", int(FlightControlState::CONTROL_FIXHEADING_ANTINORMAL) }, + { "CONTROL_FIXHEADING_RADIALLY_INWARD", int(FlightControlState::CONTROL_FIXHEADING_RADIALLY_INWARD) }, + { "CONTROL_FIXHEADING_RADIALLY_OUTWARD", int(FlightControlState::CONTROL_FIXHEADING_RADIALLY_OUTWARD) }, + { "CONTROL_FIXHEADING_KILLROT", int(FlightControlState::CONTROL_FIXHEADING_KILLROT) }, + { "CONTROL_AUTOPILOT", int(FlightControlState::CONTROL_AUTOPILOT) }, + { 0, 0 }, +}; + const struct EnumItem ENUM_UIAlignDirection[] = { { "TOP_LEFT", int(UI::Align::TOP_LEFT) }, { "TOP", int(UI::Align::TOP) }, @@ -479,26 +520,30 @@ const struct EnumItem ENUM_UIFont[] = { const struct EnumTable ENUM_TABLES[] = { { "ShipAIError", ENUM_ShipAIError }, - { "DetailLevel", ENUM_DetailLevel }, - { "FileSystemRoot", ENUM_FileSystemRoot }, { "PhysicsObjectType", ENUM_PhysicsObjectType }, - { "PolitEcon", ENUM_PolitEcon }, - { "PolitGovType", ENUM_PolitGovType }, - { "ShipTypeThruster", ENUM_ShipTypeThruster }, - { "PropulsionFuelStatus", ENUM_PropulsionFuelStatus }, { "ShipFlightState", ENUM_ShipFlightState }, { "ShipJumpStatus", ENUM_ShipJumpStatus }, { "ShipAlertStatus", ENUM_ShipAlertStatus }, { "ShipAICmdName", ENUM_ShipAICmdName }, - { "ShipControllerFlightControlState", ENUM_ShipControllerFlightControlState }, { "DualLaserOrientation", ENUM_DualLaserOrientation }, { "ShipTypeTag", ENUM_ShipTypeTag }, + { "ProjectableTypes", ENUM_ProjectableTypes }, + { "ProjectableBases", ENUM_ProjectableBases }, + { "SystemViewColorIndex", ENUM_SystemViewColorIndex }, { "EconType", ENUM_EconType }, { "CommodityType", ENUM_CommodityType }, + { "PolitEcon", ENUM_PolitEcon }, + { "PolitGovType", ENUM_PolitGovType }, { "BodyType", ENUM_BodyType }, { "BodySuperType", ENUM_BodySuperType }, { "GameUIFaceFlags", ENUM_GameUIFaceFlags }, + { "DetailLevel", ENUM_DetailLevel }, + { "FileSystemRoot", ENUM_FileSystemRoot }, + { "PiGUIFaceFlags", ENUM_PiGUIFaceFlags }, { "ModelDebugFlags", ENUM_ModelDebugFlags }, + { "ShipTypeThruster", ENUM_ShipTypeThruster }, + { "PropulsionFuelStatus", ENUM_PropulsionFuelStatus }, + { "ShipControllerFlightControlState", ENUM_ShipControllerFlightControlState }, { "UIAlignDirection", ENUM_UIAlignDirection }, { "UIAnimationType", ENUM_UIAnimationType }, { "UIAnimationEasing", ENUM_UIAnimationEasing }, @@ -523,26 +568,30 @@ const struct EnumTable ENUM_TABLES[] = { const struct EnumTable ENUM_TABLES_PUBLIC[] = { { "ShipAIError", ENUM_ShipAIError }, - { "DetailLevel", ENUM_DetailLevel }, - { "FileSystemRoot", ENUM_FileSystemRoot }, { "PhysicsObjectType", ENUM_PhysicsObjectType }, - { "PolitEcon", ENUM_PolitEcon }, - { "PolitGovType", ENUM_PolitGovType }, - { "ShipTypeThruster", ENUM_ShipTypeThruster }, - { "PropulsionFuelStatus", ENUM_PropulsionFuelStatus }, { "ShipFlightState", ENUM_ShipFlightState }, { "ShipJumpStatus", ENUM_ShipJumpStatus }, { "ShipAlertStatus", ENUM_ShipAlertStatus }, { "ShipAICmdName", ENUM_ShipAICmdName }, - { "ShipControllerFlightControlState", ENUM_ShipControllerFlightControlState }, { "DualLaserOrientation", ENUM_DualLaserOrientation }, { "ShipTypeTag", ENUM_ShipTypeTag }, + { "ProjectableTypes", ENUM_ProjectableTypes }, + { "ProjectableBases", ENUM_ProjectableBases }, + { "SystemViewColorIndex", ENUM_SystemViewColorIndex }, { "EconType", ENUM_EconType }, { "CommodityType", ENUM_CommodityType }, + { "PolitEcon", ENUM_PolitEcon }, + { "PolitGovType", ENUM_PolitGovType }, { "BodyType", ENUM_BodyType }, { "BodySuperType", ENUM_BodySuperType }, { "GameUIFaceFlags", ENUM_GameUIFaceFlags }, + { "DetailLevel", ENUM_DetailLevel }, + { "FileSystemRoot", ENUM_FileSystemRoot }, + { "PiGUIFaceFlags", ENUM_PiGUIFaceFlags }, { "ModelDebugFlags", ENUM_ModelDebugFlags }, + { "ShipTypeThruster", ENUM_ShipTypeThruster }, + { "PropulsionFuelStatus", ENUM_PropulsionFuelStatus }, + { "ShipControllerFlightControlState", ENUM_ShipControllerFlightControlState }, { "UIAlignDirection", ENUM_UIAlignDirection }, { "UIAnimationType", ENUM_UIAnimationType }, { "UIAnimationEasing", ENUM_UIAnimationEasing }, diff --git a/src/enum_table.h b/src/enum_table.h index 776805f87..16200da26 100644 --- a/src/enum_table.h +++ b/src/enum_table.h @@ -17,26 +17,30 @@ struct EnumTable { }; extern const struct EnumItem ENUM_ShipAIError[]; -extern const struct EnumItem ENUM_DetailLevel[]; -extern const struct EnumItem ENUM_FileSystemRoot[]; extern const struct EnumItem ENUM_PhysicsObjectType[]; -extern const struct EnumItem ENUM_PolitEcon[]; -extern const struct EnumItem ENUM_PolitGovType[]; -extern const struct EnumItem ENUM_ShipTypeThruster[]; -extern const struct EnumItem ENUM_PropulsionFuelStatus[]; extern const struct EnumItem ENUM_ShipFlightState[]; extern const struct EnumItem ENUM_ShipJumpStatus[]; extern const struct EnumItem ENUM_ShipAlertStatus[]; extern const struct EnumItem ENUM_ShipAICmdName[]; -extern const struct EnumItem ENUM_ShipControllerFlightControlState[]; extern const struct EnumItem ENUM_DualLaserOrientation[]; extern const struct EnumItem ENUM_ShipTypeTag[]; +extern const struct EnumItem ENUM_ProjectableTypes[]; +extern const struct EnumItem ENUM_ProjectableBases[]; +extern const struct EnumItem ENUM_SystemViewColorIndex[]; extern const struct EnumItem ENUM_EconType[]; extern const struct EnumItem ENUM_CommodityType[]; +extern const struct EnumItem ENUM_PolitEcon[]; +extern const struct EnumItem ENUM_PolitGovType[]; extern const struct EnumItem ENUM_BodyType[]; extern const struct EnumItem ENUM_BodySuperType[]; extern const struct EnumItem ENUM_GameUIFaceFlags[]; +extern const struct EnumItem ENUM_DetailLevel[]; +extern const struct EnumItem ENUM_FileSystemRoot[]; +extern const struct EnumItem ENUM_PiGUIFaceFlags[]; extern const struct EnumItem ENUM_ModelDebugFlags[]; +extern const struct EnumItem ENUM_ShipTypeThruster[]; +extern const struct EnumItem ENUM_PropulsionFuelStatus[]; +extern const struct EnumItem ENUM_ShipControllerFlightControlState[]; extern const struct EnumItem ENUM_UIAlignDirection[]; extern const struct EnumItem ENUM_UIAnimationType[]; extern const struct EnumItem ENUM_UIAnimationEasing[]; diff --git a/src/lua/Lua.cpp b/src/lua/Lua.cpp index 13768e3cb..8e88cbf4e 100644 --- a/src/lua/Lua.cpp +++ b/src/lua/Lua.cpp @@ -31,6 +31,7 @@ #include "Ship.h" #include "SpaceStation.h" #include "Star.h" +#include "SystemView.h" #include "galaxy/StarSystem.h" #include "gameui/Lua.h" @@ -71,6 +72,7 @@ namespace Lua { LuaObject::RegisterClass(); LuaObject::RegisterClass(); + LuaObject::RegisterClass(); LuaObject::RegisterClass(); LuaObject::RegisterClass(); LuaObject::RegisterClass(); diff --git a/src/lua/LuaEngine.cpp b/src/lua/LuaEngine.cpp index 674a82e3d..7ecbb229b 100644 --- a/src/lua/LuaEngine.cpp +++ b/src/lua/LuaEngine.cpp @@ -336,6 +336,14 @@ static int l_engine_set_fullscreen(lua_State *l) return 0; } +static int l_engine_get_enum_value(lua_State *l) +{ + auto enum_name = LuaPull(l, 1); + auto enum_tag = LuaPull(l, 2); + LuaPush(l, EnumStrings::GetValue(enum_name, enum_tag)); + return 1; +} + static int l_engine_get_disable_screenshot_info(lua_State *l) { LuaPush(l, Pi::config->Int("DisableScreenshotInfo") != 0); @@ -1195,16 +1203,14 @@ void LuaEngine::Register() { "SectorMapMoveRouteItemUp", l_engine_sector_map_move_route_item_up }, { "SectorMapMoveRouteItemDown", l_engine_sector_map_move_route_item_down }, { "SectorMapRemoveRouteItem", l_engine_sector_map_remove_route_item }, - { "SectorMapClearRoute", l_engine_sector_map_clear_route }, { "SectorMapAddToRoute", l_engine_sector_map_add_to_route }, - { "SearchNearbyStarSystemsByName", l_engine_search_nearby_star_systems_by_name }, - { "ShipSpaceToScreenSpace", l_engine_ship_space_to_screen_space }, { "CameraSpaceToScreenSpace", l_engine_camera_space_to_screen_space }, { "WorldSpaceToScreenSpace", l_engine_world_space_to_screen_space }, { "WorldSpaceToShipSpace", l_engine_world_space_to_ship_space }, + { "GetEnumValue", l_engine_get_enum_value }, { 0, 0 } }; diff --git a/src/lua/LuaGame.cpp b/src/lua/LuaGame.cpp index e09d2997d..21687b7f2 100644 --- a/src/lua/LuaGame.cpp +++ b/src/lua/LuaGame.cpp @@ -336,6 +336,28 @@ static int l_game_attr_system(lua_State *l) return 1; } +/* + * Attribute: systemView + * + * The object for the system map view class + * + * Availability: + * + * February 2020 + * + * Status: + * + * experiment + */ +static int l_game_attr_systemview(lua_State *l) +{ + if (!Pi::game) + lua_pushnil(l); + else + LuaObject::PushToLua(Pi::game->GetSystemView()); + return 1; +} + /* * Attribute: time * @@ -613,7 +635,7 @@ static int l_game_get_hyperspace_travelled_percentage(lua_State *l) static int l_game_get_parts_from_date_time(lua_State *l) { - float time = LuaPull(l, 1); + double time = LuaPull(l, 1); Time::DateTime t(time); int year, month, day, hour, minute, second; t.GetDateParts(&year, &month, &day); @@ -662,6 +684,7 @@ void LuaGame::Register() static const luaL_Reg l_attrs[] = { { "player", l_game_attr_player }, { "system", l_game_attr_system }, + { "systemView", l_game_attr_systemview }, { "time", l_game_attr_time }, { "paused", l_game_attr_paused }, { 0, 0 } diff --git a/src/lua/LuaSystemBody.cpp b/src/lua/LuaSystemBody.cpp index 3f7b85078..0c306c5db 100644 --- a/src/lua/LuaSystemBody.cpp +++ b/src/lua/LuaSystemBody.cpp @@ -7,6 +7,7 @@ #include "LuaObject.h" #include "LuaUtils.h" #include "Pi.h" +#include "SectorView.h" #include "Space.h" #include "galaxy/Galaxy.h" #include "galaxy/StarSystem.h" @@ -655,6 +656,27 @@ static int l_sbody_attr_children(lua_State *l) return 1; } +static int l_sbody_attr_is_moon(lua_State *l) +{ + LuaPush(l, LuaObject::CheckFromLua(1)->IsMoon()); + return 1; +} + +static int l_sbody_attr_physics_body(lua_State *l) +{ + SystemBody *b = LuaObject::CheckFromLua(1); + Body *physbody = nullptr; + SystemPath headpath = Pi::game->GetSectorView()->GetSelected().SystemOnly(); + SystemPath gamepath = Pi::game->GetSpace()->GetStarSystem()->GetPath(); + if (headpath == gamepath) { + RefCountedPtr ss = Pi::game->GetGalaxy()->GetStarSystem(headpath); + SystemPath path = ss->GetPathOf(b); + physbody = Pi::game->GetSpace()->FindBodyForPath(&path); + } + LuaObject::PushToLua(physbody); + return 1; +} + template <> const char *LuaObject::s_type = "SystemBody"; @@ -694,6 +716,8 @@ void LuaObject::RegisterClass() { "path", l_sbody_attr_path }, { "body", l_sbody_attr_body }, { "children", l_sbody_attr_children }, + { "isMoon", l_sbody_attr_is_moon }, + { "physicsBody", l_sbody_attr_physics_body }, { 0, 0 } }; diff --git a/src/lua/LuaSystemView.cpp b/src/lua/LuaSystemView.cpp new file mode 100644 index 000000000..6832dbe85 --- /dev/null +++ b/src/lua/LuaSystemView.cpp @@ -0,0 +1,436 @@ +// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details +// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt + +#include "EnumStrings.h" +#include "Game.h" +#include "LuaColor.h" +#include "LuaObject.h" +#include "LuaVector.h" +#include "LuaVector2.h" +#include "Pi.h" +#include "Player.h" +#include "SystemView.h" +#include "graphics/Graphics.h" + +LuaTable projectable_to_lua_row(Projectable &p, lua_State *l) +{ + LuaTable proj_table(l, 0, 3); + proj_table.Set("type", int(p.type)); + if (p.type == Projectable::NONE) return proj_table; + proj_table.Set("base", int(p.base)); + if (p.base == Projectable::SYSTEMBODY) + proj_table.Set("ref", const_cast(p.ref.sbody)); + else + proj_table.Set("ref", const_cast(p.ref.body)); + return proj_table; +} + +static int l_systemview_set_color(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + auto color_index = static_cast(EnumStrings::GetValue("SystemViewColorIndex", LuaPull(l, 2))); + auto color_value = LuaColor::CheckFromLua(l, 3); + sv->SetColor(color_index, color_value); + return 0; +} + +static int l_systemview_set_selected_object(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + Projectable::types type = static_cast(luaL_checkinteger(l, 2)); + Projectable::bases base = static_cast(luaL_checkinteger(l, 3)); + if (base == Projectable::SYSTEMBODY) + sv->SetSelectedObject(type, base, LuaObject::CheckFromLua(4)); + else + sv->SetSelectedObject(type, base, LuaObject::CheckFromLua(4)); + return 0; +} + +bool too_near(const vector3d &a, const vector3d &b, const vector2d &gain) +{ + return std::abs(a.x - b.x) < gain.x && std::abs(a.y - b.y) < gain.y + // we don’t want to group objects that simply overlap and are located at different distances + // therefore, depth is also taken into account, we have z_NDC (normalized device coordinates) + // in order to make a strict translation of delta z_NDC into delta "pixels", one also needs to know + // the z coordinates in the camera space. I plan to implement this later + // at the moment I just picked up a number that works well (6.0) + && std::abs(a.z - b.z) * Graphics::GetScreenWidth() * 6.0 < gain.x; +}; + +/* + * Method: GetProjectedGrouped + * + * Get a table of projected point objects from the SystemView class, having + * previously grouped them. + * + * In the process of rendering the current frame in a SystemView class, an + * array of visible point objects (centers of planets, ships, special points + * of orbits) is created. This function creates a lua table based on this + * array, after grouping them according to certain criteria. + * + * Resulting table: + * + * { + * *** ORBIT ICONS (apoapsis, periapsis) *** + * + * { screenCoordinates: vector2d + * mainObject (see struct Projectable in SystemView.h) + * { type: Projectable::types + * base: Projectable::bases + * ref: SystemBody* or Body* + * } + * objects (if multiple only, main object is duplicated there) + * { + * {type, base, ref} + * {type, base, ref} + * ... + * } + * hasPlayer: boolean + * hasCombatTarget: boolean + * hasNavTarget: boolean + * } + * { screencoordinates, mainobject, ... } + * { screencoordinates, mainobject, ... } + * ... + * + * *** LAGRANGE ICONS *** + * { screenCoordinates, mainObject, ... } + * { screenCoordinates, mainObject, ... } + * ... + * + * *** BODY ICONS (stars, planets, ships) *** + * { screenCoordinates, mainObject, ... } + * { screenCoordinates, mainObject, ... } + * ... + * + * } + * + * + * Availability: + * + * 2020-03 + * + * Status: + * + * experimental + */ + +static int l_systemview_get_projected_grouped(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + const vector2d gap = LuaPull(l, 2); + + std::vector projected = sv->GetProjected(); + + // types of special object + const int NOT_SPECIAL = -1; + const int SO_PLAYER = 0; + const int SO_COMBATTARGET = 1; + const int SO_NAVTARGET = 2; + const int NUMBER_OF_SO_TYPES = 3; + Projectable *special_object[NUMBER_OF_SO_TYPES] = { nullptr, nullptr, nullptr }; + const char *special_object_lua_name[NUMBER_OF_SO_TYPES] = { "hasPlayer", "hasCombatTarget", "hasNavTarget" }; + + struct GroupInfo { + Projectable m_mainObject; + std::vector m_objects; + bool m_hasSpecialObject[NUMBER_OF_SO_TYPES] = { false, false, false }; + + GroupInfo(Projectable p) : + m_mainObject(p) + { + m_objects.push_back(p); + } + }; + + // use forward_list to concatenate + std::vector bodyIcons; + std::vector orbitIcons; + std::vector lagrangeIcons; + + const Body *nav_target = Pi::game->GetPlayer()->GetNavTarget(); + const Body *combat_target = Pi::game->GetPlayer()->GetCombatTarget(); + const Body *player_body = static_cast(Pi::game->GetPlayer()); + + for (Projectable &p : projected) { + // --- icons--- + if (p.type == Projectable::APOAPSIS || p.type == Projectable::PERIAPSIS) + // orbit icons - just take all + orbitIcons.push_back(GroupInfo(p)); + else if (p.type == Projectable::L4 || p.type == Projectable::L5) { + // lagrange icons - take only those who don't intersect with other lagrange icons + bool intersect = false; + for (GroupInfo &group : lagrangeIcons) { + if (too_near(p.screenpos, group.m_mainObject.screenpos, gap)) { + intersect = true; + break; + } + } + if (!intersect) lagrangeIcons.push_back(GroupInfo(p)); + } else { + // --- real objects --- + int object_type = NOT_SPECIAL; + bool inserted = false; + // check if p is special object, and remember it's type + if (p.base == Projectable::SYSTEMBODY) { + if (nav_target && p.ref.sbody == nav_target->GetSystemBody()) object_type = SO_NAVTARGET; + //system body can't be a combat target and can't be a player + } else { + if (nav_target && p.ref.body == nav_target) + object_type = SO_NAVTARGET; + else if (combat_target && p.ref.body == combat_target) + object_type = SO_COMBATTARGET; + else if (p.base == Projectable::PLAYER) + object_type = SO_PLAYER; + } + for (GroupInfo &group : bodyIcons) { + if (too_near(p.screenpos, group.m_mainObject.screenpos, gap)) { + // object inside group boundaries + // special object is not added + // special objects must be added to nearest group, this group could be not nearest + if (object_type == NOT_SPECIAL) { + group.m_objects.push_back(p); + } else + // remember it separately + special_object[object_type] = &p; + inserted = true; + break; + } + } + if (!inserted) { + // object is not inside a group + // special object is nearest to itself, so we remember it as a new group + // create new group + GroupInfo newgroup(p); + if (object_type != NOT_SPECIAL) newgroup.m_hasSpecialObject[object_type] = true; + bodyIcons.push_back(std::move(newgroup)); + } + } + } // for (Projectable &p : projected) + + // adding overlapping special object to nearest group + for (int object_type = 0; object_type < NUMBER_OF_SO_TYPES; object_type++) + if (special_object[object_type]) { + std::vector touchedGroups; + // first we get all groups, touched this object + for (GroupInfo &group : bodyIcons) + if (too_near(special_object[object_type]->screenpos, group.m_mainObject.screenpos, gap)) + // object inside group boundaries: remember this group + touchedGroups.push_back(&group); + //now select the nearest group (if have) + if (touchedGroups.size()) { + GroupInfo *nearest; + double min_length = 1e64; + for (GroupInfo *&g : touchedGroups) { + double this_length = (g->m_mainObject.screenpos - special_object[object_type]->screenpos).Length(); + if (this_length < min_length) { + nearest = g; + min_length = this_length; + } + } + nearest->m_hasSpecialObject[object_type] = true; + nearest->m_objects.push_back(*special_object[object_type]); + } else { + //don't touching any group, create a new one + GroupInfo newgroup(*special_object[object_type]); + newgroup.m_hasSpecialObject[object_type] = true; + bodyIcons.push_back(std::move(newgroup)); + } + } + + //no need to sort, because the bodies are so recorded in good order + //because they are written recursively starting from the root + //body of the system, and ships go after the system bodies + + LuaTable result(l, orbitIcons.size() + lagrangeIcons.size() + bodyIcons.size(), 0); + int index = 1; + //the sooner is displayed, the more in the background + // so it goes orbitIcons->lagrangeIcons->bodies + for (auto groups : { orbitIcons, lagrangeIcons, bodyIcons }) { + for (GroupInfo &group : groups) { + LuaTable info_table(l, 0, 6); + info_table.Set("screenCoordinates", group.m_mainObject.screenpos); + info_table.Set("mainObject", projectable_to_lua_row(group.m_mainObject, l)); + lua_pop(l, 1); + if (group.m_objects.size() > 1) { + LuaTable objects_table(l, group.m_objects.size(), 0); + int objects_table_index = 1; + for (Projectable &pj : group.m_objects) { + objects_table.Set(objects_table_index++, projectable_to_lua_row(pj, l)); + lua_pop(l, 1); + } + info_table.Set("objects", objects_table); + lua_pop(l, 1); + } + for (int object_type = 0; object_type < NUMBER_OF_SO_TYPES; object_type++) + info_table.Set(special_object_lua_name[object_type], group.m_hasSpecialObject[object_type]); + result.Set(index++, info_table); + lua_pop(l, 1); + } + } + LuaPush(l, result); + return 1; +} + +static int l_systemview_get_selected_object(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + Projectable *p = sv->GetSelectedObject(); + LuaPush(l, projectable_to_lua_row(*p, l)); + return 1; +} + +static int l_systemview_set_visibility(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + sv->SetVisibility(LuaPull(l, 2)); + return 0; +} + +static int l_systemview_get_orbit_planner_start_time(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + double t = sv->GetOrbitPlannerStartTime(); + if (std::fabs(t) < 1.) + lua_pushnil(l); + else + LuaPush(l, t); + return 1; +} + +static int l_systemview_get_orbit_planner_time(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + double t = sv->GetOrbitPlannerTime(); + LuaPush(l, t); + return 1; +} + +static int l_systemview_accelerate_time(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + if (lua_isnil(l, 2)) + sv->SetRealTime(); + else { + double step = LuaPull(l, 2); + sv->AccelerateTime(step); + } + return 0; +} + +static int l_systemview_set_rotate_mode(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + bool b = LuaPull(l, 2); + sv->SetRotateMode(b); + return 0; +} + +static int l_systemview_set_zoom_mode(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + bool b = LuaPull(l, 2); + sv->SetZoomMode(b); + return 0; +} + +static int l_systemview_transfer_planner_get(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + std::string key = LuaPull(l, 2); + + TransferPlanner *planner = sv->GetTransferPlanner(); + if (key == "prograde") { + LuaPush(l, planner->GetDv(BurnDirection::PROGRADE)); + } else if (key == "normal") { + LuaPush(l, planner->GetDv(BurnDirection::NORMAL)); + } else if (key == "radial") { + LuaPush(l, planner->GetDv(BurnDirection::RADIAL)); + } else if (key == "starttime") { + LuaPush(l, planner->GetStartTime()); + } else if (key == "factor") { + LuaPush(l, planner->GetFactor() * 10); // factor is shown as "x 10" + } else { + Warning("Unknown transfer planner key %s\n", key.c_str()); + lua_pushnil(l); + } + return 1; +} + +static int l_systemview_transfer_planner_add(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + std::string key = LuaPull(l, 2); + double delta = LuaPull(l, 3); + + TransferPlanner *planner = sv->GetTransferPlanner(); + if (key == "prograde") { + planner->AddDv(BurnDirection::PROGRADE, delta); + } else if (key == "normal") { + planner->AddDv(BurnDirection::NORMAL, delta); + } else if (key == "radial") { + planner->AddDv(BurnDirection::RADIAL, delta); + } else if (key == "starttime") { + planner->AddStartTime(delta); + } else if (key == "factor") { + if (delta > 0) + planner->IncreaseFactor(); + else + planner->DecreaseFactor(); + } else { + Warning("Unknown transfer planner key %s\n", key.c_str()); + } + return 0; +} + +static int l_systemview_transfer_planner_reset(lua_State *l) +{ + SystemView *sv = LuaObject::CheckFromLua(1); + std::string key = LuaPull(l, 2); + + TransferPlanner *planner = sv->GetTransferPlanner(); + if (key == "prograde") { + planner->ResetDv(BurnDirection::PROGRADE); + } else if (key == "normal") { + planner->ResetDv(BurnDirection::NORMAL); + } else if (key == "radial") { + planner->ResetDv(BurnDirection::RADIAL); + } else if (key == "starttime") { + planner->ResetStartTime(); + } else if (key == "factor") { + planner->ResetFactor(); + } else { + Warning("Unknown transfer planner key %s\n", key.c_str()); + } + + return 0; +} + +template <> +const char *LuaObject::s_type = "SystemView"; + +template <> +void LuaObject::RegisterClass() +{ + static const luaL_Reg l_methods[] = { + + { "GetProjectedGrouped", l_systemview_get_projected_grouped }, + { "GetSelectedObject", l_systemview_get_selected_object }, + { "GetOrbitPlannerStartTime", l_systemview_get_orbit_planner_start_time }, + { "GetOrbitPlannerTime", l_systemview_get_orbit_planner_time }, + { "AccelerateTime", l_systemview_accelerate_time }, + { "SetSelectedObject", l_systemview_set_selected_object }, + { "SetVisibility", l_systemview_set_visibility }, + { "SetColor", l_systemview_set_color }, + { "SetRotateMode", l_systemview_set_rotate_mode }, + { "SetZoomMode" , l_systemview_set_zoom_mode }, + + { "TransferPlannerAdd", l_systemview_transfer_planner_add }, + { "TransferPlannerGet", l_systemview_transfer_planner_get }, + { "TransferPlannerReset", l_systemview_transfer_planner_reset }, + + { NULL, NULL } + }; + + LuaObjectBase::CreateClass(s_type, nullptr, l_methods, 0, 0); +} From ac7e98248ea331c8bc492c264c572335394d13f5 Mon Sep 17 00:00:00 2001 From: Gliese852 Date: Sat, 4 Apr 2020 11:16:58 +0300 Subject: [PATCH 2/2] Additional fixes related (almost) to System Map - Now only those orbits whose radius is less than 1% of the screen width are not shown. - Add smooth transition when click object. - Improve system bodies orbits. - Fix that ..apsis and lagrange points were displayed in the wrong place. - After rescanning enums, an error was found in the pigui/Face.h, fixed. fixes #4801 - Some indentations to pass clang - Added static_cast to Space.cpp, because it caused a warning at compilation. --- src/Space.cpp | 8 ++++---- src/SystemView.cpp | 37 ++++++++++++++++++++++++++++--------- src/SystemView.h | 5 +++++ src/lua/LuaEngine.cpp | 3 ++- src/pigui/Face.h | 6 +++--- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/Space.cpp b/src/Space.cpp index 8fdcca93b..57861f137 100644 --- a/src/Space.cpp +++ b/src/Space.cpp @@ -428,7 +428,7 @@ static void RelocateStarportIfNecessary(SystemBody *sbody, Planet *planet, vecto double bestVariation = 1e10; // any high value matrix3x3d rotNotUnderwaterWithLeastVariation = rot; vector3d posNotUnderwaterWithLeastVariation = pos; - const double heightVariationCheckThreshold = 0.008; // max variation to radius radius ratio to check for local slope, ganymede is around 0.01 + const double heightVariationCheckThreshold = 0.008; // max variation to radius radius ratio to check for local slope, ganymede is around 0.01 const double terrainHeightVariation = planet->GetMaxFeatureRadius(); //in radii //Output("%s: terrain height variation %f\n", sbody->name.c_str(), terrainHeightVariation); @@ -437,8 +437,8 @@ static void RelocateStarportIfNecessary(SystemBody *sbody, Planet *planet, vecto // points must stay within max height variation to be accepted // 1. delta should be chosen such that it a distance from the starport center that encloses landing pads for the largest starport // 2. maxSlope should be set so maxHeightVariation is less than the height of the landing pads - const double delta = 20.0 / radius; // in radii - const double maxSlope = 0.2; // 0.0 to 1.0 + const double delta = 20.0 / radius; // in radii + const double maxSlope = 0.2; // 0.0 to 1.0 const double maxHeightVariation = maxSlope * delta * radius; // in m matrix3x3d rot_ = rot; @@ -1033,7 +1033,7 @@ static void DebugDumpFrame(FrameId fId, bool details, unsigned int indent) Frame *f = Frame::GetFrame(fId); Frame *parent = Frame::GetFrame(f->GetParent()); - Output("%.*s%2i) %p (%s)%s\n", indent, space, fId, static_cast(f), f->GetLabel().c_str(), f->IsRotFrame() ? " [rotating]" : " [non rotating]"); + Output("%.*s%2i) %p (%s)%s\n", indent, space, static_cast(fId), static_cast(f), f->GetLabel().c_str(), f->IsRotFrame() ? " [rotating]" : " [non rotating]"); if (f->GetParent().valid()) Output("%.*s parent %p (%s)\n", indent + 3, space, static_cast(parent), parent->GetLabel().c_str()); if (f->GetBody()) diff --git a/src/SystemView.cpp b/src/SystemView.cpp index f945713c1..ddeeb43b2 100644 --- a/src/SystemView.cpp +++ b/src/SystemView.cpp @@ -35,6 +35,7 @@ static const float ZOOM_IN_SPEED = 3; static const float ZOOM_OUT_SPEED = 3; static const float WHEEL_SENSITIVITY = .1f; // Should be a variable in user settings. static const double DEFAULT_VIEW_DISTANCE = 10.0; +static const int MAX_TRANSITION_FRAMES = 60; TransferPlanner::TransferPlanner() : m_position(0., 0., 0.), @@ -228,7 +229,9 @@ SystemView::SystemView(Game *game) : m_game(game), m_gridDrawing(GridDrawing::OFF), m_shipDrawing(OFF), - m_showL4L5(LAG_OFF) + m_showL4L5(LAG_OFF), + m_trans(0.0), + m_transTo(0.0) { m_rot_y = 0; m_rot_x = 50; @@ -278,15 +281,18 @@ void SystemView::ResetViewpoint() m_zoomTo = 1.0f / float(AU); m_timeStep = 1.0f; m_time = m_game->GetTime(); + m_animateTransition = MAX_TRANSITION_FRAMES; } template void SystemView::PutOrbit(Projectable::bases base, RefType *ref, const Orbit *orbit, const vector3d &offset, const Color &color, const double planetRadius, const bool showLagrange) { + double ecc = orbit->GetEccentricity(); + double timeshift = ecc > 0.6 ? 0.0 : 0.5; double maxT = 1.; unsigned short num_vertices = 0; for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { - const double t = double(i) / double(N_VERTICES_MAX); + const double t = (double(i) + timeshift) / double(N_VERTICES_MAX); const vector3d pos = orbit->EvenSpacedPosTrajectory(t); if (pos.Length() < planetRadius) { maxT = t; @@ -298,9 +304,9 @@ void SystemView::PutOrbit(Projectable::bases base, RefType *ref, const Orbit *or static const float fadedColorParameter = 0.8; Uint16 fadingColors = 0; - const double tMinust0 = m_time - m_game->GetTime(); + const double tMinust0 = GetOrbitTime(m_time, ref); for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { - const double t = double(i) / double(N_VERTICES_MAX) * maxT; + const double t = (double(i) + timeshift) / double(N_VERTICES_MAX) * maxT; if (fadingColors == 0 && t >= startTrailPercent * maxT) fadingColors = i; const vector3d pos = orbit->EvenSpacedPosTrajectory(t, tMinust0); @@ -322,8 +328,8 @@ void SystemView::PutOrbit(Projectable::bases base, RefType *ref, const Orbit *or if (num_vertices > 1) { m_orbits.SetData(num_vertices, m_orbitVts.get(), m_orbitColors.get()); - // don't close the loop for hyperbolas and parabolas and crashed ellipses - if (maxT < 1. || (orbit->GetEccentricity() > 1.0)) { + //close the loop for thin ellipses + if (maxT < 1. || ecc > 1.0 || ecc < 0.6) { m_orbits.Draw(m_renderer, m_lineState, LINE_STRIP); } else { m_orbits.Draw(m_renderer, m_lineState, LINE_LOOP); @@ -391,7 +397,8 @@ void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matr continue; const double axisZoom = kid->GetOrbit().GetSemiMajorAxis() * m_zoom; - if (axisZoom < DEFAULT_VIEW_DISTANCE) { + //semimajor axis radius should be at least 1% of screen width to show the orbit + if (ProjectedSize(axisZoom, offset) > 0.01) { const SystemBody::BodySuperType bst = kid->GetSuperType(); const bool showLagrange = (bst == SystemBody::SUPERTYPE_ROCKY_PLANET || bst == SystemBody::SUPERTYPE_GAS_GIANT); PutOrbit(Projectable::SYSTEMBODY, kid, &(kid->GetOrbit()), offset, svColor[SYSTEMBODY_ORBIT], 0.0, showLagrange); @@ -502,8 +509,20 @@ void SystemView::Draw3D() m_cameraSpace.Rotate(DEG2RAD(m_rot_y), 0, 1, 0); m_renderer->SetTransform(m_cameraSpace); - vector3d pos(0, 0, 0); - if (m_selectedObject) GetTransformTo(m_selectedObject, pos); + // smooth transition animation + m_transTo *= 0.0; + if (m_selectedObject.type != Projectable::NONE) GetTransformTo(m_selectedObject, m_transTo); + if (m_animateTransition) { + const float ft = Pi::GetFrameTime(); + m_animateTransition--; + AnimationCurves::Approach(m_trans.x, m_transTo.x, ft); + AnimationCurves::Approach(m_trans.y, m_transTo.y, ft); + AnimationCurves::Approach(m_trans.z, m_transTo.z, ft); + } else { + m_trans = m_transTo; + } + + vector3d pos = m_trans * m_zoom; // glLineWidth(2); if (!m_system->GetUnexplored() && m_system->GetRootBody()) { diff --git a/src/SystemView.h b/src/SystemView.h index fbf335a7e..f1bca97e5 100644 --- a/src/SystemView.h +++ b/src/SystemView.h @@ -43,6 +43,7 @@ enum ShowLagrange { LAG_OFF }; + class TransferPlanner { public: TransferPlanner(); @@ -129,6 +130,7 @@ public: void SetVisibility(std::string param); void SetZoomMode(bool enable); void SetRotateMode(bool enable); + double ProjectedSize(double size, vector3d pos); // all used colors. defined in system-view-ui.lua enum ColorIndex { // @@ -188,6 +190,9 @@ private: float m_rot_x, m_rot_y; float m_rot_x_to, m_rot_y_to; float m_zoom, m_zoomTo; + int m_animateTransition; + vector3d m_trans; + vector3d m_transTo; double m_time; bool m_realtime; double m_timeStep; diff --git a/src/lua/LuaEngine.cpp b/src/lua/LuaEngine.cpp index 7ecbb229b..3b4ccb60d 100644 --- a/src/lua/LuaEngine.cpp +++ b/src/lua/LuaEngine.cpp @@ -11,6 +11,7 @@ #include "Intro.h" #include "KeyBindings.h" #include "Lang.h" +#include "LuaColor.h" #include "LuaConstants.h" #include "LuaObject.h" #include "LuaPiGui.h" @@ -1085,7 +1086,7 @@ static int l_engine_get_sector_map_factions(lua_State *l) lua_setfield(l, -2, "faction"); lua_pushboolean(l, hidden.count(f) == 0); lua_setfield(l, -2, "visible"); // inner table - lua_settable(l, -3); // outer table + lua_settable(l, -3); // outer table } return 1; } diff --git a/src/pigui/Face.h b/src/pigui/Face.h index 6c5d7c980..b471a0333 100644 --- a/src/pigui/Face.h +++ b/src/pigui/Face.h @@ -5,8 +5,8 @@ #define PIGUI_FACE_H #include "FaceParts.h" -#include "SmartPtr.h" #include "Pi.h" +#include "SmartPtr.h" #include "graphics/Drawables.h" #include "graphics/Texture.h" @@ -14,12 +14,12 @@ namespace PiGUI { class Face : public RefCounted { public: - Face(FaceParts::FaceDescriptor& face, Uint32 seed = 0); + Face(FaceParts::FaceDescriptor &face, Uint32 seed = 0); Uint32 GetTextureId(); vector2f GetTextureSize(); - enum Flags { // + enum Flags { // RAND = 0, MALE = (1 << 0), FEMALE = (1 << 1),