public void Start() { // If we're not in the correct location, there's no point doing anything. if (!InstallationPathWarning.Warn()) { return; } if (HighLogic.LoadedSceneIsEditor) { return; } try { // Install the calculator module. RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); comp.UpdateDataRefreshRate(refreshDataRate); persistence = new PersistenceAccessor(internalProp); // Loading the font... List <Texture2D> fontTexture = new List <Texture2D>(); fontTexture.Add(LoadFont(this, internalProp, fontTransform)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).renderer.material; foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, screenTexture, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) { activePage = newPage; } pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; int activePageID = persistence.GetVar(persistentVarName, pages.Count); if (activePageID < pages.Count) { activePage = pages[activePageID]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) { SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); // One last thing to make sure of: If our pod is transparent, we're always active. ourPodIsTransparent = JUtil.IsPodTransparent(part); // And if the try block never completed, startupComplete will never be true. startupComplete = true; } catch { JUtil.AnnoyUser(this); startupFailed = true; // We can also disable ourselves, that should help. enabled = false; // And now that we notified the user that config is borked, we rethrow the exception so that // it gets logged and we can debug. throw; } }
public bool RenderCamera(RenderTexture screen, float cameraAspect) { // Just in case. if (!HighLogic.LoadedSceneIsFlight) { return(false); } if (cameras.Count < 1) { return(false); } var activeCamera = cameras[currentCamera]; if (string.IsNullOrEmpty(activeCamera.cameraTransform)) { return(false); } if (cameraObject == null) { cameraObject = new FlyingCamera(part, screen, cameraAspect); cameraObject.PointCamera(activeCamera.cameraTransform, activeCamera.currentFoV); } cameraObject.FOV = activeCamera.currentFoV; // Negate pitch - the camera object treats a negative pitch as "up" if (cameraObject.Render(activeCamera.currentYaw, -activeCamera.currentPitch)) { ITargetable target = FlightGlobals.fetch.VesselTarget; bool drawSomething = ((gizmoTexture != null && target != null && showTargetIcon) || homeCrosshairMaterial.color.a > 0); if (drawSomething) { GL.PushMatrix(); GL.LoadPixelMatrix(0, screen.width, screen.height, 0); } if (gizmoTexture != null && target != null && showTargetIcon) { // Figure out which direction the target is. Vector3 targetDisplacement = target.GetTransform().position - cameraObject.GetTransform().position; targetDisplacement.Normalize(); // Transform it using the active camera's rotation. var targetDisp = GetNormalizedScreenPosition(activeCamera, targetDisplacement, cameraAspect); var iconCenter = new Vector2(screen.width * targetDisp.x, screen.height * targetDisp.y); // Apply some clamping values to force the icon to stay on screen iconCenter.x = Math.Max(iconPixelSize * 0.5f, iconCenter.x); iconCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, iconCenter.x); iconCenter.y = Math.Max(iconPixelSize * 0.5f, iconCenter.y); iconCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, iconCenter.y); var position = new Rect(iconCenter.x - iconPixelSize * 0.5f, iconCenter.y - iconPixelSize * 0.5f, iconPixelSize, iconPixelSize); Graphics.DrawTexture(position, gizmoTexture, GizmoIcons.GetIconLocation(GizmoIcons.IconType.TARGETPLUS), 0, 0, 0, 0, iconMaterial); } if (homeCrosshairMaterial.color.a > 0) { // Mihara: Reference point cameras are different enough to warrant it. var cameraForward = cameraObject.GetTransformForward(); var crossHairCenter = GetNormalizedScreenPosition(activeCamera, cameraForward, cameraAspect); crossHairCenter.x *= screen.width; crossHairCenter.y *= screen.height; crossHairCenter.x = Math.Max(iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.y = Math.Max(iconPixelSize * 0.5f, crossHairCenter.y); crossHairCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, crossHairCenter.y); float zoomAdjustedIconSize = iconPixelSize * Mathf.Tan(Mathf.Deg2Rad * activeCamera.fovLimits.y * 0.5f) / Mathf.Tan(Mathf.Deg2Rad * activeCamera.currentFoV * 0.5f); homeCrosshairMaterial.SetPass(0); GL.Begin(GL.LINES); GL.Vertex3(crossHairCenter.x - zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x + zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y - zoomAdjustedIconSize * 0.5f, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y + zoomAdjustedIconSize * 0.5f, 0.0f); GL.End(); } if (drawSomething) { GL.PopMatrix(); } return(true); } return(false); }
/// <summary> /// Initialize the renderable game objects for the HUD. /// </summary> /// <param name="screenWidth"></param> /// <param name="screenHeight"></param> void InitializeRenderables(RenderTexture screen) { float screenWidth = (float)screen.width; float screenHeight = (float)screen.height; Shader displayShader = JUtil.LoadInternalShader("RPM-DisplayShader"); if (!string.IsNullOrEmpty(cameraTransform)) { cameraObject = new FlyingCamera(part, screen, hudCamera.aspect); cameraObject.PointCamera(cameraTransform, hudFov); } if (!string.IsNullOrEmpty(staticOverlay)) { Material overlayMaterial = new Material(displayShader); overlayMaterial.color = Color.white; Texture overlayTexture = GameDatabase.Instance.GetTexture(staticOverlay.EnforceSlashes(), false); overlayMaterial.mainTexture = overlayTexture; overlayMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayOverlay" + hudCamera.GetInstanceID(), screenWidth * 0.5f, drawingLayer); overlayMesh.transform.position = new Vector3(0, 0, 1.0f); overlayMesh.renderer.material = overlayMaterial; overlayMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, overlayMesh); } if (!string.IsNullOrEmpty(horizonTexture)) { Shader ladderShader = JUtil.LoadInternalShader("RPM-CroppedDisplayShader"); Material ladderMaterial = new Material(ladderShader); // _CropBound is in device normalized coordinates (-1 - +1) Vector4 cropBound = new Vector4(-horizonSize.x / screenWidth, -horizonSize.y / screenHeight, horizonSize.x / screenWidth, horizonSize.y / screenHeight); ladderMaterial.SetVector("_CropBound", cropBound); ladderMaterial.color = Color.white; ladderMaterial.mainTexture = GameDatabase.Instance.GetTexture(horizonTexture.EnforceSlashes(), false); if (ladderMaterial.mainTexture != null) { horizonTextureSize.x = 0.5f * (horizonTextureSize.x / ladderMaterial.mainTexture.width); horizonTextureSize.y = 0.5f * (horizonTextureSize.y / ladderMaterial.mainTexture.height); ladderMaterial.mainTexture.wrapMode = TextureWrapMode.Clamp; ladderMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayLadder" + hudCamera.GetInstanceID(), new Vector2(horizonSize.x * 0.5f, horizonSize.y * 0.5f), new Rect(0.0f, 0.0f, 1.0f, 1.0f), drawingLayer); ladderMesh.transform.position = new Vector3(0, 0, 1.4f); ladderMesh.renderer.material = ladderMaterial; ladderMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, ladderMesh); if (progradeColorValue.a > 0.0f && showLadderPrograde) { Material progradeIconMaterial = new Material(displayShader); progradeIconMaterial.color = Color.white; Rect texCoord; if (string.IsNullOrEmpty(ladderProgradeTexture)) { progradeIconMaterial.mainTexture = JUtil.GetGizmoTexture(); texCoord = GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE); } else { Texture2D progradeTexture = GameDatabase.Instance.GetTexture(ladderProgradeTexture.EnforceSlashes(), false); if (progradeTexture == null) { JUtil.LogErrorMessage(this, "Failed to find ladder prograde texture \"{0}\".", ladderProgradeTexture); } progradeIconMaterial.mainTexture = progradeTexture; texCoord = new Rect(0.0f, 0.0f, 1.0f, 1.0f); } progradeIconMaterial.SetVector("_Color", progradeColorValue); progradeLadderIcon = JUtil.CreateSimplePlane("JSIHeadsUpDisplayLadderProgradeIcon" + hudCamera.GetInstanceID(), new Vector2(iconPixelSize * 0.5f, iconPixelSize * 0.5f), texCoord, drawingLayer); progradeLadderIcon.transform.position = new Vector3(0.0f, 0.0f, 1.35f); progradeLadderIcon.renderer.material = progradeIconMaterial; progradeLadderIcon.transform.parent = cameraBody.transform; } } } if (!string.IsNullOrEmpty(headingBar)) { Material headingMaterial = new Material(displayShader); headingMaterial.color = Color.white; headingMaterial.mainTexture = GameDatabase.Instance.GetTexture(headingBar.EnforceSlashes(), false); if (headingMaterial.mainTexture != null) { headingBarTextureWidth = 0.5f * (headingBarWidth / (float)headingMaterial.mainTexture.width); headingMaterial.mainTexture.wrapMode = TextureWrapMode.Repeat; headingMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayHeading" + hudCamera.GetInstanceID(), new Vector2(headingBarPosition.z * 0.5f, headingBarPosition.w * 0.5f), new Rect(0.0f, 0.0f, 1.0f, 1.0f), drawingLayer); headingMesh.transform.position = new Vector3(headingBarPosition.x + 0.5f * (headingBarPosition.z - screenWidth), 0.5f * (screenHeight - headingBarPosition.w) - headingBarPosition.y, 1.4f); headingMesh.renderer.material = headingMaterial; headingMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, headingMesh); if (progradeColorValue.a > 0.0f && showHeadingBarPrograde) { Material progradeIconMaterial = new Material(displayShader); progradeIconMaterial.color = Color.white; Rect texCoord; if (string.IsNullOrEmpty(headingBarProgradeTexture)) { progradeIconMaterial.mainTexture = JUtil.GetGizmoTexture(); texCoord = GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE); } else { Texture2D progradeTexture = GameDatabase.Instance.GetTexture(headingBarProgradeTexture.EnforceSlashes(), false); if (progradeTexture == null) { JUtil.LogErrorMessage(this, "Failed to find heading bar prograde texture \"{0}\".", headingBarProgradeTexture); } progradeIconMaterial.mainTexture = progradeTexture; texCoord = new Rect(0.0f, 0.0f, 1.0f, 1.0f); } progradeIconMaterial.SetVector("_Color", progradeColorValue); progradeHeadingIconOrigin = headingBarPosition.x + 0.5f * (headingBarPosition.z - screenWidth); progradeHeadingIcon = JUtil.CreateSimplePlane("JSIHeadsUpDisplayHeadingProgradeIcon" + hudCamera.GetInstanceID(), new Vector2(iconPixelSize * 0.5f, iconPixelSize * 0.5f), texCoord, drawingLayer); progradeHeadingIcon.transform.position = new Vector3(progradeHeadingIconOrigin, 0.5f * (screenHeight - headingBarPosition.w) - headingBarPosition.y, 1.35f); progradeHeadingIcon.renderer.material = progradeIconMaterial; progradeHeadingIcon.transform.parent = headingMesh.transform; } } } if (!string.IsNullOrEmpty(verticalBar)) { ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("JSIHUD_VERTICAL_BAR"); string[] vBars = verticalBar.Split(';'); for (int i = 0; i < vBars.Length; ++i) { for (int j = 0; j < nodes.Length; ++j) { if (nodes[j].HasValue("name") && vBars[i].Trim() == nodes[j].GetValue("name")) { try { VerticalBar vb = new VerticalBar(nodes[j], screenWidth, screenHeight, drawingLayer, displayShader, cameraBody); verticalBars.Add(vb); } catch (Exception e) { JUtil.LogErrorMessage(this, "Error parsing JSIHUD_VERTICAL_BAR: {0}", e); } break; } } } } }
public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor) { ourMonitor = thatMonitor; screenWidth = ourMonitor.screenWidth; screenHeight = ourMonitor.screenHeight; cameraAspect = ourMonitor.cameraAspect; cameraObject = thatMonitor.cameraStructure; defaultColor = ourMonitor.defaultFontTintValue; screenXMin = 0; screenYMin = 0; pageNumber = idNum; isMutable = false; if (!node.HasData) { throw new ArgumentException("Empty page?"); } if (node.HasValue("name")) { string value = node.GetValue("name").Trim(); if (!IsValidPageName(value)) { JUtil.LogMessage(ourMonitor, "Warning, name given for page #{0} is invalid, ignoring.", pageNumber); } else { name = value; } } else { JUtil.LogMessage(ourMonitor, "Warning, page #{0} has no name. It's much better if it does.", pageNumber); } isDefault |= node.HasValue("default"); if (node.HasValue("button")) { SmarterButton.CreateButton(thatMonitor.internalProp, node.GetValue("button"), this, thatMonitor.PageButtonClick); } // Page locking system -- simple locking: simpleLockingPage |= node.HasValue("lockingPage"); // and name-based locking. if (node.HasValue("disableSwitchingTo")) { string[] tokens = node.GetValue("disableSwitchingTo").Split(','); foreach (string token in tokens) { disableSwitchingTo.Add(token.Trim()); } } unlocker |= node.HasValue("unlockerPage"); if (node.HasValue("localMargins")) { Vector4 margindata = ConfigNode.ParseVector4(node.GetValue("localMargins")); screenXMin = (int)margindata.x; screenYMin = (int)margindata.y; screenWidth = screenWidth - (int)margindata.z - screenXMin; screenHeight = screenHeight - (int)margindata.w - screenYMin; } pageFont = node.GetInt("defaultFontNumber") ?? 0; if (node.HasValue("defaultFontTint")) { defaultColor = ConfigNode.ParseColor32(node.GetValue("defaultFontTint")); } if (node.HasValue("techsRequired")) { techsRequired = node.GetValue("techsRequired").Split(new[] { ' ', ',', ';', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } if (node.HasValue("fallbackOnNoTech")) { fallbackPageName = node.GetValue("fallbackOnNoTech").Trim(); } if (node.HasNode("CONTEXTREDIRECT")) { ConfigNode[] redirectnodes = node.GetNodes("CONTEXTREDIRECT"); for (int i = 0; i < redirectnodes.Length; ++i) { string[] redirects = redirectnodes[i].GetValues("redirect"); for (int j = 0; j < redirects.Length; ++j) { string[] tokens = redirects[j].Split(','); if (tokens.Length > 2 || !IsValidPageName(tokens[0].Trim()) || !IsValidPageName(tokens[1].Trim())) { JUtil.LogMessage(ourMonitor, "Warning, invalid page redirect statement on page #{0}.", pageNumber); continue; } redirectPages[tokens[0].Trim()] = tokens[1].Trim(); } string[] renumbers = redirectnodes[i].GetValues("renumber"); for (int j = 0; j < renumbers.Length; ++j) { string[] tokens = renumbers[j].Split(','); if (tokens.Length > 2) { JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: requires two arguments.", pageNumber); continue; } int from, to; if (!int.TryParse(tokens[0], out from) || !int.TryParse(tokens[1], out to)) { JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: something isn't a number", pageNumber); continue; } redirectGlobals[from] = to; } } JUtil.LogMessage(this, "Page '{2}' (#{0}) registers {1} page redirects and {3} global button redirects.", idNum, redirectPages.Count, name, redirectGlobals.Count); } foreach (ConfigNode handlerNode in node.GetNodes("PAGEHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { pageHandlerMethod = (Func <int, int, string>)Delegate.CreateDelegate(typeof(Func <int, int, string>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the page handler method {0}", handlerModule.name); break; } pageHandlerS = supportMethods; isMutable = true; pageHandlerModule = handlerModule; break; } } if (pageHandlerMethod == null) { if (node.HasValue("text")) { text = JUtil.LoadPageDefinition(node.GetValue("text")); isMutable |= text.IndexOf("$&$", StringComparison.Ordinal) != -1; } } if (node.HasValue("textOverlay")) { textOverlay = JUtil.LoadPageDefinition(node.GetValue("textOverlay")); } foreach (ConfigNode handlerNode in node.GetNodes("BACKGROUNDHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { backgroundHandlerMethod = (Func <RenderTexture, float, bool>)Delegate.CreateDelegate(typeof(Func <RenderTexture, float, bool>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the background handler method {0}", handlerModule.name); break; } backgroundHandlerS = supportMethods; isMutable = true; showNoSignal = node.HasValue("showNoSignal"); background = BackgroundType.Handler; backgroundHandlerModule = handlerModule; break; } } if (background == BackgroundType.None) { if (node.HasValue("cameraTransform")) { isMutable = true; background = BackgroundType.Camera; camera = node.GetValue("cameraTransform"); cameraFOV = defaultFOV; cameraFlickerChance = node.GetFloat("flickerChance") ?? 0; cameraFlickerRange = node.GetInt("flickerRange") ?? 0; if (node.HasValue("fov")) { float fov; cameraFOV = float.TryParse(node.GetValue("fov"), out fov) ? fov : defaultFOV; } else if (node.HasValue("zoomFov") && node.HasValue("zoomButtons")) { Vector3 zoomFov = ConfigNode.ParseVector3(node.GetValue("zoomFov")); Vector2 zoomButtons = ConfigNode.ParseVector2(node.GetValue("zoomButtons")); if ((int)zoomFov.z != 0 && ((int)zoomButtons.x != (int)zoomButtons.y)) { maxFOV = Math.Max(zoomFov.x, zoomFov.y); minFOV = Math.Min(zoomFov.x, zoomFov.y); zoomSteps = (int)zoomFov.z; zoomUpButton = (int)zoomButtons.x; zoomDownButton = (int)zoomButtons.y; zoomSkip = (maxFOV - minFOV) / zoomSteps; currentZoom = 0; cameraFOV = maxFOV; } else { JUtil.LogMessage(ourMonitor, "Ignored invalid camera zoom settings on page {0}.", pageNumber); } } } } if (background == BackgroundType.None) { if (node.HasValue("textureURL")) { string textureURL = node.GetValue("textureURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { backgroundTexture = GameDatabase.Instance.GetTexture(textureURL, false); background = BackgroundType.Texture; } } } if (node.HasValue("textureInterlayURL")) { string textureURL = node.GetValue("textureInterlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { interlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Interlay texture {0} could not be loaded.", textureURL); } } if (node.HasValue("textureOverlayURL")) { string textureURL = node.GetValue("textureOverlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { overlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Overlay texture {0} could not be loaded.", textureURL); } } }
public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor) { ourMonitor = thatMonitor; screenWidth = ourMonitor.screenWidth; screenHeight = ourMonitor.screenHeight; cameraAspect = ourMonitor.cameraAspect; cameraObject = thatMonitor.cameraStructure; defaultColor = ourMonitor.defaultFontTintValue; screenXMin = 0; screenYMin = 0; pageNumber = idNum; isMutable = false; if (!node.HasData) { throw new ArgumentException("Empty page?"); } if (node.HasValue("name")) { string value = node.GetValue("name").Trim(); if (!IsValidPageName(value)) { JUtil.LogMessage(ourMonitor, "Warning, name given for page #{0} is invalid, ignoring.", pageNumber); } else { name = value; } } else { JUtil.LogMessage(ourMonitor, "Warning, page #{0} has no name. It's much better if it does.", pageNumber); } isDefault |= node.HasValue("default"); if (node.HasValue("button")) { SmarterButton.CreateButton(thatMonitor.internalProp, node.GetValue("button"), this, thatMonitor.PageButtonClick); } // Page locking system -- simple locking: simpleLockingPage |= node.HasValue("lockingPage"); // and name-based locking. if (node.HasValue("disableSwitchingTo")) { string[] tokens = node.GetValue("disableSwitchingTo").Split(','); foreach (string token in tokens) { disableSwitchingTo.Add(token.Trim()); } } unlocker |= node.HasValue("unlockerPage"); if (node.HasValue("localMargins")) { Vector4 margindata = ConfigNode.ParseVector4(node.GetValue("localMargins")); screenXMin = (int)margindata.x; screenYMin = (int)margindata.y; screenWidth = screenWidth - (int)margindata.z - screenXMin; screenHeight = screenHeight - (int)margindata.w - screenYMin; } pageFont = node.GetInt("defaultFontNumber") ?? 0; if (node.HasValue("defaultFontTint")) { defaultColor = ConfigNode.ParseColor32(node.GetValue("defaultFontTint")); } if (node.HasValue("techsRequired")) { techsRequired = node.GetValue("techsRequired").Split(new[] { ' ', ',', ';', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } if (node.HasValue("fallbackOnNoTech")) { fallbackPageName = node.GetValue("fallbackOnNoTech").Trim(); } if (node.HasNode("CONTEXTREDIRECT")) { foreach (string content in node.GetNode("CONTEXTREDIRECT").GetValues("redirect")) { string[] tokens = content.Split(','); if (tokens.Length > 2 || !IsValidPageName(tokens[0].Trim()) || !IsValidPageName(tokens[1].Trim())) { JUtil.LogMessage(ourMonitor, "Warning, invalid page redirect statement on page #{0}.", pageNumber); continue; } redirectPages[tokens[0].Trim()] = tokens[1].Trim(); } const string valueError = "Warning, invalid global button redirect statement on page #{0}: {1}"; foreach (string content in node.GetNode("CONTEXTREDIRECT").GetValues("renumber")) { string[] tokens = content.Split(','); if (tokens.Length > 2) { JUtil.LogMessage(ourMonitor, valueError, pageNumber, "requires two arguments."); continue; } int from, to; if (!int.TryParse(tokens[0], out from) || !int.TryParse(tokens[1], out to)) { JUtil.LogMessage(ourMonitor, valueError, pageNumber, "something isn't a number."); continue; } redirectGlobals[from] = to; } JUtil.LogMessage(this, "Page '{2}' (#{0}) registers {1} page redirects and {3} global button redirects.", idNum, redirectPages.Count, name, redirectGlobals.Count); } foreach (ConfigNode handlerNode in node.GetNodes("PAGEHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { pageHandlerMethod = (Func<int, int, string>)Delegate.CreateDelegate(typeof(Func<int, int, string>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the page handler method {0}", handlerModule.name); break; } pageHandlerS = supportMethods; isMutable = true; pageHandlerModule = handlerModule; break; } } if (pageHandlerMethod == null) { if (node.HasValue("text")) { text = JUtil.LoadPageDefinition(node.GetValue("text")); isMutable |= text.IndexOf("$&$", StringComparison.Ordinal) != -1; } } if (node.HasValue("textOverlay")) { textOverlayBuffer = JUtil.LoadPageDefinition(node.GetValue("textOverlay")).Split(JUtil.LineSeparator, StringSplitOptions.None); } foreach (ConfigNode handlerNode in node.GetNodes("BACKGROUNDHANDLER")) { MonoBehaviour handlerModule; HandlerSupportMethods supportMethods; MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods); if (handlerMethod != null && handlerModule != null) { try { backgroundHandlerMethod = (Func<RenderTexture, float, bool>)Delegate.CreateDelegate(typeof(Func<RenderTexture, float, bool>), handlerModule, handlerMethod); } catch { JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the background handler method {0}", handlerModule.name); break; } backgroundHandlerS = supportMethods; isMutable = true; showNoSignal = node.HasValue("showNoSignal"); background = BackgroundType.Handler; backgroundHandlerModule = handlerModule; break; } } if (background == BackgroundType.None) { if (node.HasValue("cameraTransform")) { isMutable = true; background = BackgroundType.Camera; camera = node.GetValue("cameraTransform"); cameraFOV = defaultFOV; cameraFlickerChance = node.GetFloat("flickerChance") ?? 0; cameraFlickerRange = node.GetInt("flickerRange") ?? 0; if (node.HasValue("fov")) { float fov; cameraFOV = float.TryParse(node.GetValue("fov"), out fov) ? fov : defaultFOV; } else if (node.HasValue("zoomFov") && node.HasValue("zoomButtons")) { Vector3 zoomFov = ConfigNode.ParseVector3(node.GetValue("zoomFov")); Vector2 zoomButtons = ConfigNode.ParseVector2(node.GetValue("zoomButtons")); if ((int)zoomFov.z != 0 && ((int)zoomButtons.x != (int)zoomButtons.y)) { maxFOV = Math.Max(zoomFov.x, zoomFov.y); minFOV = Math.Min(zoomFov.x, zoomFov.y); zoomSteps = (int)zoomFov.z; zoomUpButton = (int)zoomButtons.x; zoomDownButton = (int)zoomButtons.y; zoomSkip = (maxFOV - minFOV) / zoomSteps; currentZoom = 0; cameraFOV = maxFOV; } else { JUtil.LogMessage(ourMonitor, "Ignored invalid camera zoom settings on page {0}.", pageNumber); } } } } if (background == BackgroundType.None) { if (node.HasValue("textureURL")) { string textureURL = node.GetValue("textureURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { backgroundTexture = GameDatabase.Instance.GetTexture(textureURL, false); background = BackgroundType.Texture; } } } if (node.HasValue("textureInterlayURL")) { string textureURL = node.GetValue("textureInterlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { interlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Interlay texture could not be loaded."); } } if (node.HasValue("textureOverlayURL")) { string textureURL = node.GetValue("textureOverlayURL").EnforceSlashes(); if (GameDatabase.Instance.ExistsTexture(textureURL)) { overlayTexture = GameDatabase.Instance.GetTexture(textureURL, false); } else { JUtil.LogErrorMessage(ourMonitor, "Overlay texture {0} could not be loaded.", textureURL); } } }
public bool RenderHUD(RenderTexture screen, float cameraAspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) return false; // Clear the background, if configured. GL.Clear(true, true, backgroundColorValue); // Configure the camera, if configured. // MOARdV: Might be worthwhile to refactor the flying camera so // it is created in Start (like new FlyingCamera(part, cameraTransform)), // and pass the screen, FoV, and aspect ratio (or just screen and // FoV) as Render parameters, so there's no need to test if the // camera's been created every render call. if (cameraObject == null && !string.IsNullOrEmpty(cameraTransform)) { cameraObject = new FlyingCamera(part, screen, cameraAspect); cameraObject.PointCamera(cameraTransform, hudFov); } // Draw the camera's view, if configured. if (cameraObject != null) { cameraObject.Render(); } // Configure the matrix so that the origin is the center of the screen. GL.PushMatrix(); // Draw the HUD ladder // MOARdV note, 2014/03/19: swapping the y values, to invert the // coordinates so the prograde icon is right-side up. GL.LoadPixelMatrix(-horizonSize.x * 0.5f, horizonSize.x * 0.5f, horizonSize.y * 0.5f, -horizonSize.y * 0.5f); GL.Viewport(new Rect((screen.width - horizonSize.x) * 0.5f, (screen.height - horizonSize.y) * 0.5f, horizonSize.x, horizonSize.y)); Vector3 coM = vessel.findWorldCenterOfMass(); Vector3 up = (coM - vessel.mainBody.position).normalized; Vector3 forward = vessel.GetTransform().up; Vector3 right = vessel.GetTransform().right; Vector3 top = Vector3.Cross(right, forward); Vector3 north = Vector3.Exclude(up, (vessel.mainBody.position + (Vector3d)vessel.mainBody.transform.up * vessel.mainBody.Radius) - coM).normalized; Vector3d velocityVesselSurface = vessel.orbit.GetVel() - vessel.mainBody.getRFrmVel(coM); Vector3 velocityVesselSurfaceUnit = velocityVesselSurface.normalized; if (ladderMaterial) { // Figure out the texture coordinate scaling for the ladder. float ladderTextureOffset = horizonTextureSize.y / ladderMaterial.mainTexture.height; float cosUp = Vector3.Dot(forward, up); float cosRoll = Vector3.Dot(top, up); float sinRoll = Vector3.Dot(right, up); var normalizedRoll = new Vector2(cosRoll, sinRoll); normalizedRoll.Normalize(); if (normalizedRoll.magnitude < 0.99f) { // If we're hitting +/- 90 nearly perfectly, the sin and cos will // be too far out of whack to normalize. Arbitrarily pick // a roll of 0.0. normalizedRoll.x = 1.0f; normalizedRoll.y = 0.0f; } cosRoll = normalizedRoll.x; sinRoll = normalizedRoll.y; // Mihara: I'm pretty sure this was negative of what it should actually be, at least according to my mockup. float pitch = -(Mathf.Asin(cosUp) * Mathf.Rad2Deg); float ladderMidpointCoord; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; ladderMidpointCoord = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; ladderMidpointCoord = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch); } ladderMaterial.SetPass(0); GL.Begin(GL.QUADS); // transform -x -y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x + sinRoll * horizonSize.y, -sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x -y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x + sinRoll * horizonSize.y, sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x +y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x - sinRoll * horizonSize.y, sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); // transform -x +y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x - sinRoll * horizonSize.y, -sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); GL.End(); float AoA = velocityVesselSurfaceUnit.AngleInPlane(right, forward); float AoATC; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; AoATC = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch + AoA); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; AoATC = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch + AoA); } float Ypos = JUtil.DualLerp( -horizonSize.y, horizonSize.y, ladderMidpointCoord - ladderTextureOffset, ladderMidpointCoord + ladderTextureOffset, AoATC); // Placing the icon on the (0, Ypos) location, so simplify the transform. DrawIcon(-sinRoll * Ypos, -cosRoll * Ypos, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } // Draw the rest of the HUD stuff (0,0) is the top left corner of the screen. GL.LoadPixelMatrix(0, screen.width, screen.height, 0); GL.Viewport(new Rect(0, 0, screen.width, screen.height)); if (headingMaterial != null) { Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.GetTransform().rotation) * rotationSurface); float headingTexture = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y); float headingTextureOffset = (headingBarWidth / headingMaterial.mainTexture.width) / 2; headingMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(headingTexture - headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.TexCoord2(headingTexture - headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.End(); if (showHeadingBarPrograde) { float slipAngle = velocityVesselSurfaceUnit.AngleInPlane(up, forward); float slipTC = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y + slipAngle); float slipIconX = JUtil.DualLerp(headingBarPosition.x, headingBarPosition.x + headingBarPosition.z, headingTexture - headingTextureOffset, headingTexture + headingTextureOffset, slipTC); DrawIcon(slipIconX, headingBarPosition.y + headingBarPosition.w * 0.5f, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } } if (vertBar1Material != null) { float value = comp.ProcessVariable(vertBar1Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar1UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar1TexCoord = JUtil.DualLerp(vertBar1TextureLimit.x, vertBar1TextureLimit.y, vertBar1Limit.x, vertBar1Limit.y, value); vertBar1Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.End(); } if (vertBar2Material != null) { float value = comp.ProcessVariable(vertBar2Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar2UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar2TexCoord = JUtil.DualLerp(vertBar2TextureLimit.x, vertBar2TextureLimit.y, vertBar2Limit.x, vertBar2Limit.y, value); vertBar2Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.End(); } if (overlayMaterial != null) { overlayMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0.0f, 0.0f, 0.0f); GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(screen.width, 0.0f, 0.0f); GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(screen.width, screen.height, 0.0f); GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0.0f, screen.height, 0.0f); GL.End(); } GL.PopMatrix(); return true; }
public bool RenderCamera(RenderTexture screen, float cameraAspect) { // Just in case. if (HighLogic.LoadedSceneIsEditor) { return false; } if(cameras.Count < 1) { return false; } var activeCamera = cameras[currentCamera]; if (string.IsNullOrEmpty(activeCamera.cameraTransform)) { return false; } if (cameraObject == null) { cameraObject = new FlyingCamera(part, screen, cameraAspect); cameraObject.PointCamera(activeCamera.cameraTransform, activeCamera.currentFoV); } cameraObject.FOV = activeCamera.currentFoV; // Negate pitch - the camera object treats a negative pitch as "up" if (cameraObject.Render(activeCamera.currentYaw, -activeCamera.currentPitch)) { ITargetable target = FlightGlobals.fetch.VesselTarget; bool drawSomething = ((gizmoTexture != null && target != null && showTargetIcon) || homeCrosshairMaterial.color.a > 0); if (drawSomething) { GL.PushMatrix(); GL.LoadPixelMatrix(0, screen.width, screen.height, 0); } if (gizmoTexture != null && target != null && showTargetIcon) { // Figure out which direction the target is. Vector3 targetDisplacement = target.GetTransform().position - cameraObject.GetTransform().position; targetDisplacement.Normalize(); // Transform it using the active camera's rotation. var targetDisp = GetNormalizedScreenPosition(activeCamera, targetDisplacement, cameraAspect); var iconCenter = new Vector2(screen.width * targetDisp.x, screen.height * targetDisp.y); // Apply some clamping values to force the icon to stay on screen iconCenter.x = Math.Max(iconPixelSize * 0.5f, iconCenter.x); iconCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, iconCenter.x); iconCenter.y = Math.Max(iconPixelSize * 0.5f, iconCenter.y); iconCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, iconCenter.y); var position = new Rect(iconCenter.x - iconPixelSize * 0.5f, iconCenter.y - iconPixelSize * 0.5f, iconPixelSize, iconPixelSize); Graphics.DrawTexture(position, gizmoTexture, GizmoIcons.GetIconLocation(GizmoIcons.IconType.TARGETPLUS), 0, 0, 0, 0, iconMaterial); } if (homeCrosshairMaterial.color.a > 0) { // Mihara: Reference point cameras are different enough to warrant it. var cameraForward = cameraObject.GetTransformForward(); var crossHairCenter = GetNormalizedScreenPosition(activeCamera, cameraForward, cameraAspect); crossHairCenter.x *= screen.width; crossHairCenter.y *= screen.height; crossHairCenter.x = Math.Max(iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.y = Math.Max(iconPixelSize * 0.5f, crossHairCenter.y); crossHairCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, crossHairCenter.y); float zoomAdjustedIconSize = iconPixelSize * Mathf.Tan(Mathf.Deg2Rad * activeCamera.fovLimits.y * 0.5f) / Mathf.Tan(Mathf.Deg2Rad * activeCamera.currentFoV * 0.5f); homeCrosshairMaterial.SetPass(0); GL.Begin(GL.LINES); GL.Vertex3(crossHairCenter.x - zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x + zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y - zoomAdjustedIconSize * 0.5f, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y + zoomAdjustedIconSize * 0.5f, 0.0f); GL.End(); } if (drawSomething) { GL.PopMatrix(); } return true; } return false; }
public bool RenderCamera(RenderTexture screen, float cameraAspect) { // Just in case. if (HighLogic.LoadedSceneIsEditor) { return(false); } if (cameras.Count < 1) { return(false); } var activeCamera = cameras[currentCamera]; if (string.IsNullOrEmpty(activeCamera.cameraTransform)) { return(false); } if (cameraObject == null) { cameraObject = new FlyingCamera(part, cameraAspect); cameraObject.PointCamera(activeCamera.cameraTransform, activeCamera.currentFoV); } cameraObject.FOV = activeCamera.currentFoV; if (rentexWidth == 0) { rentexWidth = screen.width; rentexHeight = screen.height; // Note to self: when rentex dims != screen dims, the FOV seems to be wrong (like FOV is smaller). } if (renderTex == null) { renderTex = new RenderTexture(rentexWidth, rentexHeight, screen.depth); renderTex.Create(); } // Negate pitch - the camera object treats a negative pitch as "up" if (cameraObject.Render(renderTex, activeCamera.currentYaw, -activeCamera.currentPitch)) { if (cameraEffectMaterial != null) { cameraEffectMaterial.SetVector("_ImageDims", new Vector4((float)renderTex.width, (float)renderTex.height, 1.0f / (float)renderTex.width, 1.0f / (float)renderTex.height)); for (int i = 0; i < ceVariables.Count; ++i) { float value = ceVariables[i].value.AsFloat(); cameraEffectMaterial.SetFloat(ceVariables[i].variable, value); } Graphics.Blit(renderTex, screen, cameraEffectMaterial); } else { Graphics.Blit(renderTex, screen); } renderTex.DiscardContents(); ITargetable target = FlightGlobals.fetch.VesselTarget; bool drawSomething = ((gizmoTexture != null && target != null && showTargetIcon) || homeCrosshairMaterial.color.a > 0); if (drawSomething) { GL.PushMatrix(); GL.LoadPixelMatrix(0, screen.width, screen.height, 0); } if (gizmoTexture != null && target != null && showTargetIcon) { // Figure out which direction the target is. Vector3 targetDisplacement = target.GetTransform().position - cameraObject.GetTransform().position; targetDisplacement.Normalize(); // Transform it using the active camera's rotation. var targetDisp = GetNormalizedScreenPosition(activeCamera, targetDisplacement, cameraAspect); var iconCenter = new Vector2(screen.width * targetDisp.x, screen.height * targetDisp.y); // Apply some clamping values to force the icon to stay on screen iconCenter.x = Math.Max(iconPixelSize * 0.5f, iconCenter.x); iconCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, iconCenter.x); iconCenter.y = Math.Max(iconPixelSize * 0.5f, iconCenter.y); iconCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, iconCenter.y); var position = new Rect(iconCenter.x - iconPixelSize * 0.5f, iconCenter.y - iconPixelSize * 0.5f, iconPixelSize, iconPixelSize); Graphics.DrawTexture(position, gizmoTexture, GizmoIcons.GetIconLocation(GizmoIcons.IconType.TARGETPLUS), 0, 0, 0, 0, iconMaterial); } if (homeCrosshairMaterial.color.a > 0) { // Mihara: Reference point cameras are different enough to warrant it. var cameraForward = cameraObject.GetTransformForward(); var crossHairCenter = GetNormalizedScreenPosition(activeCamera, cameraForward, cameraAspect); crossHairCenter.x *= screen.width; crossHairCenter.y *= screen.height; crossHairCenter.x = Math.Max(iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.y = Math.Max(iconPixelSize * 0.5f, crossHairCenter.y); crossHairCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, crossHairCenter.y); float zoomAdjustedIconSize = iconPixelSize * Mathf.Tan(Mathf.Deg2Rad * activeCamera.fovLimits.y * 0.5f) / Mathf.Tan(Mathf.Deg2Rad * activeCamera.currentFoV * 0.5f); homeCrosshairMaterial.SetPass(0); GL.Begin(GL.LINES); GL.Vertex3(crossHairCenter.x - zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x + zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y - zoomAdjustedIconSize * 0.5f, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y + zoomAdjustedIconSize * 0.5f, 0.0f); GL.End(); } if (drawSomething) { GL.PopMatrix(); } return(true); } else if (skipMissingCameras) { // This will handle cameras getting ejected while in use. SelectNextCamera(); } return(false); }
/// <summary> /// Initialize the renderable game objects for the HUD. /// </summary> /// <param name="screenWidth"></param> /// <param name="screenHeight"></param> void InitializeRenderables(RenderTexture screen) { float screenWidth = (float)screen.width; float screenHeight = (float)screen.height; Shader displayShader = JUtil.LoadInternalShader("RPM-DisplayShader"); if (!string.IsNullOrEmpty(cameraTransform)) { cameraObject = new FlyingCamera(part, screen, hudCamera.aspect); cameraObject.PointCamera(cameraTransform, hudFov); } if (!string.IsNullOrEmpty(staticOverlay)) { Material overlayMaterial = new Material(displayShader); overlayMaterial.color = Color.white; Texture overlayTexture = GameDatabase.Instance.GetTexture(staticOverlay.EnforceSlashes(), false); overlayMaterial.mainTexture = overlayTexture; overlayMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayOverlay" + hudCamera.GetInstanceID(), screenWidth * 0.5f, drawingLayer); overlayMesh.transform.position = new Vector3(0, 0, 1.0f); overlayMesh.GetComponent <Renderer>().material = overlayMaterial; overlayMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, overlayMesh); } if (!string.IsNullOrEmpty(horizonTexture)) { Shader ladderShader = JUtil.LoadInternalShader("RPM-CroppedDisplayShader"); Material ladderMaterial = new Material(ladderShader); // _CropBound is in device normalized coordinates (-1 - +1) Vector4 cropBound = new Vector4(-horizonSize.x / screenWidth, -horizonSize.y / screenHeight, horizonSize.x / screenWidth, horizonSize.y / screenHeight); ladderMaterial.SetVector("_CropBound", cropBound); ladderMaterial.color = Color.white; ladderMaterial.mainTexture = GameDatabase.Instance.GetTexture(horizonTexture.EnforceSlashes(), false); if (ladderMaterial.mainTexture != null) { float diagonal = horizonSize.magnitude / Mathf.Min(horizonSize.x, horizonSize.y) * 0.5f; Vector2 horizonDrawSize = diagonal * horizonSize; horizonTextureSize.x = 0.5f * (horizonTextureSize.x / ladderMaterial.mainTexture.width); horizonTextureSize.y = 0.5f * (horizonTextureSize.y / ladderMaterial.mainTexture.height); ladderMaterial.mainTexture.wrapMode = TextureWrapMode.Clamp; ladderMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayLadder" + hudCamera.GetInstanceID(), horizonDrawSize, new Rect(0.0f, 0.0f, 1.0f, 1.0f), drawingLayer); ladderMesh.transform.position = new Vector3(0, 0, 1.45f); ladderMesh.GetComponent <Renderer>().material = ladderMaterial; ladderMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, ladderMesh); if (progradeColorValue.a > 0.0f && showLadderPrograde) { Material progradeIconMaterial = new Material(displayShader); progradeIconMaterial.color = Color.white; Rect texCoord; if (string.IsNullOrEmpty(ladderProgradeTexture)) { progradeIconMaterial.mainTexture = JUtil.GetGizmoTexture(); texCoord = GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE); } else { Texture2D progradeTexture = GameDatabase.Instance.GetTexture(ladderProgradeTexture.EnforceSlashes(), false); if (progradeTexture == null) { JUtil.LogErrorMessage(this, "Failed to find ladder prograde texture \"{0}\".", ladderProgradeTexture); } progradeIconMaterial.mainTexture = progradeTexture; texCoord = new Rect(0.0f, 0.0f, 1.0f, 1.0f); } progradeIconMaterial.SetVector("_Color", progradeColorValue); progradeLadderIcon = JUtil.CreateSimplePlane("JSIHeadsUpDisplayLadderProgradeIcon" + hudCamera.GetInstanceID(), new Vector2(iconPixelSize * 0.5f, iconPixelSize * 0.5f), texCoord, drawingLayer); progradeLadderIcon.transform.position = new Vector3(0.0f, 0.0f, 1.41f); progradeLadderIcon.GetComponent <Renderer>().material = progradeIconMaterial; progradeLadderIcon.transform.parent = cameraBody.transform; } } } if (!string.IsNullOrEmpty(headingBar)) { Material headingMaterial = new Material(displayShader); headingMaterial.color = Color.white; headingMaterial.mainTexture = GameDatabase.Instance.GetTexture(headingBar.EnforceSlashes(), false); if (headingMaterial.mainTexture != null) { headingBarTextureWidth = 0.5f * (headingBarWidth / (float)headingMaterial.mainTexture.width); headingMaterial.mainTexture.wrapMode = TextureWrapMode.Repeat; headingMesh = JUtil.CreateSimplePlane("JSIHeadsUpDisplayHeading" + hudCamera.GetInstanceID(), new Vector2(headingBarPosition.z * 0.5f, headingBarPosition.w * 0.5f), new Rect(0.0f, 0.0f, 1.0f, 1.0f), drawingLayer); headingMesh.transform.position = new Vector3(headingBarPosition.x + 0.5f * (headingBarPosition.z - screenWidth), 0.5f * (screenHeight - headingBarPosition.w) - headingBarPosition.y, 1.4f); headingMesh.GetComponent <Renderer>().material = headingMaterial; headingMesh.transform.parent = cameraBody.transform; JUtil.ShowHide(false, headingMesh); if (progradeColorValue.a > 0.0f && showHeadingBarPrograde) { Material progradeIconMaterial = new Material(displayShader); progradeIconMaterial.color = Color.white; Rect texCoord; if (string.IsNullOrEmpty(headingBarProgradeTexture)) { progradeIconMaterial.mainTexture = JUtil.GetGizmoTexture(); texCoord = GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE); } else { Texture2D progradeTexture = GameDatabase.Instance.GetTexture(headingBarProgradeTexture.EnforceSlashes(), false); if (progradeTexture == null) { JUtil.LogErrorMessage(this, "Failed to find heading bar prograde texture \"{0}\".", headingBarProgradeTexture); } progradeIconMaterial.mainTexture = progradeTexture; texCoord = new Rect(0.0f, 0.0f, 1.0f, 1.0f); } progradeIconMaterial.SetVector("_Color", progradeColorValue); progradeHeadingIconOrigin = headingBarPosition.x + 0.5f * (headingBarPosition.z - screenWidth); progradeHeadingIcon = JUtil.CreateSimplePlane("JSIHeadsUpDisplayHeadingProgradeIcon" + hudCamera.GetInstanceID(), new Vector2(iconPixelSize * 0.5f, iconPixelSize * 0.5f), texCoord, drawingLayer); progradeHeadingIcon.transform.position = new Vector3(progradeHeadingIconOrigin, 0.5f * (screenHeight - headingBarPosition.w) - headingBarPosition.y, 1.35f); progradeHeadingIcon.GetComponent <Renderer>().material = progradeIconMaterial; progradeHeadingIcon.transform.parent = headingMesh.transform; } } } if (!string.IsNullOrEmpty(verticalBar)) { ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("JSIHUD_VERTICAL_BAR"); string[] vBars = verticalBar.Split(';'); for (int i = 0; i < vBars.Length; ++i) { for (int j = 0; j < nodes.Length; ++j) { if (nodes[j].HasValue("name") && vBars[i].Trim() == nodes[j].GetValue("name")) { try { VerticalBar vb = new VerticalBar(nodes[j], screenWidth, screenHeight, drawingLayer, displayShader, cameraBody); verticalBars.Add(vb); } catch (Exception e) { JUtil.LogErrorMessage(this, "Error parsing JSIHUD_VERTICAL_BAR: {0}", e); } break; } } } } if (!string.IsNullOrEmpty(horizontalBar)) { ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("JSIHUD_HORIZONTAL_BAR"); string[] hBars = horizontalBar.Split(';'); for (int i = 0; i < hBars.Length; ++i) { for (int j = 0; j < nodes.Length; ++j) { if (nodes[j].HasValue("name") && hBars[i].Trim() == nodes[j].GetValue("name")) { try { HorizontalBar hb = new HorizontalBar(nodes[j], screenWidth, screenHeight, drawingLayer, displayShader, cameraBody); horizontalBars.Add(hb); } catch (Exception e) { JUtil.LogErrorMessage(this, "Error parsing JSIHUD_HORIZONTAL_BAR: {0}", e); } break; } } } } }
public bool RenderHUD(RenderTexture screen, float cameraAspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } // Clear the background, if configured. GL.Clear(true, true, backgroundColorValue); // Configure the camera, if configured. // MOARdV: Might be worthwhile to refactor the flying camera so // it is created in Start (like new FlyingCamera(part, cameraTransform)), // and pass the screen, FoV, and aspect ratio (or just screen and // FoV) as Render parameters, so there's no need to test if the // camera's been created every render call. if (cameraObject == null && !string.IsNullOrEmpty(cameraTransform)) { cameraObject = new FlyingCamera(part, screen, cameraAspect); cameraObject.PointCamera(cameraTransform, hudFov); } // Draw the camera's view, if configured. if (cameraObject != null) { cameraObject.Render(); } // Configure the matrix so that the origin is the center of the screen. GL.PushMatrix(); // Draw the HUD ladder // MOARdV note, 2014/03/19: swapping the y values, to invert the // coordinates so the prograde icon is right-side up. GL.LoadPixelMatrix(-horizonSize.x * 0.5f, horizonSize.x * 0.5f, horizonSize.y * 0.5f, -horizonSize.y * 0.5f); GL.Viewport(new Rect((screen.width - horizonSize.x) * 0.5f, (screen.height - horizonSize.y) * 0.5f, horizonSize.x, horizonSize.y)); Vector3 coM = vessel.findWorldCenterOfMass(); Vector3 up = (coM - vessel.mainBody.position).normalized; Vector3 forward = vessel.GetTransform().up; Vector3 right = vessel.GetTransform().right; Vector3 top = Vector3.Cross(right, forward); Vector3 north = Vector3.Exclude(up, (vessel.mainBody.position + (Vector3d)vessel.mainBody.transform.up * vessel.mainBody.Radius) - coM).normalized; Vector3d velocityVesselSurface = vessel.orbit.GetVel() - vessel.mainBody.getRFrmVel(coM); Vector3 velocityVesselSurfaceUnit = velocityVesselSurface.normalized; if (ladderMaterial) { // Figure out the texture coordinate scaling for the ladder. float ladderTextureOffset = horizonTextureSize.y / ladderMaterial.mainTexture.height; float cosUp = Vector3.Dot(forward, up); float cosRoll = Vector3.Dot(top, up); float sinRoll = Vector3.Dot(right, up); var normalizedRoll = new Vector2(cosRoll, sinRoll); normalizedRoll.Normalize(); if (normalizedRoll.magnitude < 0.99f) { // If we're hitting +/- 90 nearly perfectly, the sin and cos will // be too far out of whack to normalize. Arbitrarily pick // a roll of 0.0. normalizedRoll.x = 1.0f; normalizedRoll.y = 0.0f; } cosRoll = normalizedRoll.x; sinRoll = normalizedRoll.y; // Mihara: I'm pretty sure this was negative of what it should actually be, at least according to my mockup. float pitch = -(Mathf.Asin(cosUp) * Mathf.Rad2Deg); float ladderMidpointCoord; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; ladderMidpointCoord = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; ladderMidpointCoord = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch); } ladderMaterial.SetPass(0); GL.Begin(GL.QUADS); // transform -x -y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x + sinRoll * horizonSize.y, -sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x -y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x + sinRoll * horizonSize.y, sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x +y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x - sinRoll * horizonSize.y, sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); // transform -x +y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x - sinRoll * horizonSize.y, -sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); GL.End(); float AoA = velocityVesselSurfaceUnit.AngleInPlane(right, forward); float AoATC; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; AoATC = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch + AoA); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; AoATC = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch + AoA); } float Ypos = JUtil.DualLerp( -horizonSize.y, horizonSize.y, ladderMidpointCoord - ladderTextureOffset, ladderMidpointCoord + ladderTextureOffset, AoATC); // Placing the icon on the (0, Ypos) location, so simplify the transform. DrawIcon(-sinRoll * Ypos, -cosRoll * Ypos, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } // Draw the rest of the HUD stuff (0,0) is the top left corner of the screen. GL.LoadPixelMatrix(0, screen.width, screen.height, 0); GL.Viewport(new Rect(0, 0, screen.width, screen.height)); if (headingMaterial != null) { Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.GetTransform().rotation) * rotationSurface); float headingTexture = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y); float headingTextureOffset = (headingBarWidth / headingMaterial.mainTexture.width) / 2; headingMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(headingTexture - headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.TexCoord2(headingTexture - headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.End(); if (showHeadingBarPrograde) { float slipAngle = velocityVesselSurfaceUnit.AngleInPlane(up, forward); float slipTC = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y + slipAngle); float slipIconX = JUtil.DualLerp(headingBarPosition.x, headingBarPosition.x + headingBarPosition.z, headingTexture - headingTextureOffset, headingTexture + headingTextureOffset, slipTC); DrawIcon(slipIconX, headingBarPosition.y + headingBarPosition.w * 0.5f, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } } if (vertBar1Material != null) { float value = comp.ProcessVariable(vertBar1Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar1UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar1TexCoord = JUtil.DualLerp(vertBar1TextureLimit.x, vertBar1TextureLimit.y, vertBar1Limit.x, vertBar1Limit.y, value); vertBar1Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.End(); } if (vertBar2Material != null) { float value = comp.ProcessVariable(vertBar2Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar2UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar2TexCoord = JUtil.DualLerp(vertBar2TextureLimit.x, vertBar2TextureLimit.y, vertBar2Limit.x, vertBar2Limit.y, value); vertBar2Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.End(); } if (overlayMaterial != null) { overlayMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0.0f, 0.0f, 0.0f); GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(screen.width, 0.0f, 0.0f); GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(screen.width, screen.height, 0.0f); GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0.0f, screen.height, 0.0f); GL.End(); } GL.PopMatrix(); return(true); }
public void Start() { // If we're not in the correct location, there's no point doing anything. if (!InstallationPathWarning.Warn()) { return; } if (HighLogic.LoadedSceneIsEditor) { return; } try { rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true); JUtil.LogMessage(this, "Attaching monitor {2}-{1} to {0}", rpmComp.RPMCid, internalProp.propID, internalProp.internalModel.internalName); // Install the calculator module. rpmComp.UpdateDataRefreshRate(refreshDataRate); // Loading the font... List<Texture2D> fontTexture = new List<Texture2D>(); fontTexture.Add(LoadFont(this, internalProp, fontTransform)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).GetComponent<Renderer>().material; foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) activePage = newPage; pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; int activePageID = rpmComp.GetPersistentVariable(persistentVarName, pages.Count, false).MassageToInt(); if (activePageID < pages.Count) { activePage = pages[activePageID]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); if (needsElectricCharge) { del = (Action<bool>)Delegate.CreateDelegate(typeof(Action<bool>), this, "ResourceDepletedCallback"); rpmComp.RegisterResourceCallback(resourceName, del); } // And if the try block never completed, startupComplete will never be true. startupComplete = true; } catch { JUtil.AnnoyUser(this); // We can also disable ourselves, that should help. enabled = false; // And now that we notified the user that config is borked, we rethrow the exception so that // it gets logged and we can debug. throw; } }
public void Start() { // If we're not in the correct location, there's no point doing anything. if (!InstallationPathWarning.Warn()) return; try { // Install the calculator module. comp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateRefreshRates(refreshTextRate, refreshDataRate); // Loading the font... fontTexture.Add(LoadFont(this, internalProp, fontTransform, false)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) emptyColorValue = ConfigNode.ParseColor32(emptyColor); if (!string.IsNullOrEmpty(defaultFontTint)) defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // We can pre-compute the rectangles the font characters will be copied from, this seems to make it slightly quicker... // although I'm not sure I'm not seeing things by this point. int fontLettersX = (fontTexture[0].width / fontLetterWidth); int fontLettersY = (fontTexture[0].height / fontLetterHeight); float letterSpanX = 1f / fontLettersX; float letterSpanY = 1f / fontLettersY; int lastCharacter = fontLettersX * fontLettersY; if (lastCharacter != fontDefinitionString.Length) { JUtil.LogMessage(this, "Warning, number of letters in the font definition does not match font bitmap size."); } for (int i = 0; i < lastCharacter && i < fontDefinitionString.Length; i++) { int xSource = i % fontLettersX; int ySource = (i - xSource) / fontLettersX; if (!fontCharacters.ContainsKey(fontDefinitionString[i])) fontCharacters[fontDefinitionString[i]] = new Rect(letterSpanX * xSource, letterSpanY * (fontLettersY - ySource - 1), letterSpanX, letterSpanY); } // And a little optimisation for superscript/subscript: fontLetterHalfHeight = fontLetterHeight / 2f; fontLetterHalfWidth = fontLetterWidth / 2f; fontLetterDoubleWidth = fontLetterWidth * 2f; // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).renderer.material; foreach (string layerID in textureLayerID.Split()) screenMat.SetTexture(layerID.Trim(), screenTexture); if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, screenTexture, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes ("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) activePage = newPage; pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value, true)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; persistence = new PersistenceAccessor(part); int? activePageID = persistence.GetVar(persistentVarName); if (activePageID != null && activePageID.Value < pages.Count) { activePage = pages[activePageID.Value]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); // One last thing to make sure of: If our pod is transparent, we're always active. ourPodIsTransparent = JUtil.IsPodTransparent(part); // And if the try block never completed, startupComplete will never be true. startupComplete = true; } catch { JUtil.AnnoyUser(this); startupFailed = true; // We can also disable ourselves, that should help. enabled = false; // And now that we notified the user that config is borked, we rethrow the exception so that // it gets logged and we can debug. throw; } }
public bool RenderCamera(RenderTexture screen, float cameraAspect) { // Just in case. if (HighLogic.LoadedSceneIsEditor) { return false; } if (cameras.Count < 1) { return false; } var activeCamera = cameras[currentCamera]; if (string.IsNullOrEmpty(activeCamera.cameraTransform)) { return false; } if (cameraObject == null) { cameraObject = new FlyingCamera(part, cameraAspect); cameraObject.PointCamera(activeCamera.cameraTransform, activeCamera.currentFoV); } cameraObject.FOV = activeCamera.currentFoV; if (rentexWidth == 0) { rentexWidth = screen.width; rentexHeight = screen.height; // Note to self: when rentex dims != screen dims, the FOV seems to be wrong (like FOV is smaller). } if (renderTex == null) { renderTex = new RenderTexture(rentexWidth, rentexHeight, screen.depth); renderTex.Create(); } // Negate pitch - the camera object treats a negative pitch as "up" if (cameraObject.Render(renderTex, activeCamera.currentYaw, -activeCamera.currentPitch)) { if (cameraEffectMaterial != null) { cameraEffectMaterial.SetVector("_ImageDims", new Vector4((float)renderTex.width, (float)renderTex.height, 1.0f / (float)renderTex.width, 1.0f / (float)renderTex.height)); for (int i = 0; i < ceVariables.Count; ++i) { float value = ceVariables[i].value.AsFloat(); cameraEffectMaterial.SetFloat(ceVariables[i].variable, value); } Graphics.Blit(renderTex, screen, cameraEffectMaterial); } else { Graphics.Blit(renderTex, screen); } renderTex.DiscardContents(); ITargetable target = FlightGlobals.fetch.VesselTarget; bool drawSomething = ((gizmoTexture != null && target != null && showTargetIcon) || homeCrosshairMaterial.color.a > 0); if (drawSomething) { GL.PushMatrix(); GL.LoadPixelMatrix(0, screen.width, screen.height, 0); } if (gizmoTexture != null && target != null && showTargetIcon) { // Figure out which direction the target is. Vector3 targetDisplacement = target.GetTransform().position - cameraObject.GetTransform().position; targetDisplacement.Normalize(); // Transform it using the active camera's rotation. var targetDisp = GetNormalizedScreenPosition(activeCamera, targetDisplacement, cameraAspect); var iconCenter = new Vector2(screen.width * targetDisp.x, screen.height * targetDisp.y); // Apply some clamping values to force the icon to stay on screen iconCenter.x = Math.Max(iconPixelSize * 0.5f, iconCenter.x); iconCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, iconCenter.x); iconCenter.y = Math.Max(iconPixelSize * 0.5f, iconCenter.y); iconCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, iconCenter.y); var position = new Rect(iconCenter.x - iconPixelSize * 0.5f, iconCenter.y - iconPixelSize * 0.5f, iconPixelSize, iconPixelSize); Graphics.DrawTexture(position, gizmoTexture, GizmoIcons.GetIconLocation(GizmoIcons.IconType.TARGETPLUS), 0, 0, 0, 0, iconMaterial); } if (homeCrosshairMaterial.color.a > 0) { // Mihara: Reference point cameras are different enough to warrant it. var cameraForward = cameraObject.GetTransformForward(); var crossHairCenter = GetNormalizedScreenPosition(activeCamera, cameraForward, cameraAspect); crossHairCenter.x *= screen.width; crossHairCenter.y *= screen.height; crossHairCenter.x = Math.Max(iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.x = Math.Min(screen.width - iconPixelSize * 0.5f, crossHairCenter.x); crossHairCenter.y = Math.Max(iconPixelSize * 0.5f, crossHairCenter.y); crossHairCenter.y = Math.Min(screen.height - iconPixelSize * 0.5f, crossHairCenter.y); float zoomAdjustedIconSize = iconPixelSize * Mathf.Tan(Mathf.Deg2Rad * activeCamera.fovLimits.y * 0.5f) / Mathf.Tan(Mathf.Deg2Rad * activeCamera.currentFoV * 0.5f); homeCrosshairMaterial.SetPass(0); GL.Begin(GL.LINES); GL.Vertex3(crossHairCenter.x - zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x + zoomAdjustedIconSize * 0.5f, crossHairCenter.y, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y - zoomAdjustedIconSize * 0.5f, 0.0f); GL.Vertex3(crossHairCenter.x, crossHairCenter.y + zoomAdjustedIconSize * 0.5f, 0.0f); GL.End(); } if (drawSomething) { GL.PopMatrix(); } return true; } else if (skipMissingCameras) { // This will handle cameras getting ejected while in use. SelectNextCamera(); } return false; }
public void Start() { InstallationPathWarning.Warn(); // Install the calculator module. comp = RasterPropMonitorComputer.Instantiate(internalProp); comp.UpdateRefreshRates(refreshTextRate, refreshDataRate); // Loading the font... fontTexture.Add(LoadFont(this, internalProp, fontTransform, false)); // Damn KSP's config parser!!! if (!string.IsNullOrEmpty(emptyColor)) { emptyColorValue = ConfigNode.ParseColor32(emptyColor); } if (!string.IsNullOrEmpty(defaultFontTint)) { defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint); } if (!string.IsNullOrEmpty(fontDefinition)) { JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition); fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0]; } // We can pre-compute the rectangles the font characters will be copied from, this seems to make it slightly quicker... // although I'm not sure I'm not seeing things by this point. int fontLettersX = (fontTexture[0].width / fontLetterWidth); int fontLettersY = (fontTexture[0].height / fontLetterHeight); float letterSpanX = 1f / fontLettersX; float letterSpanY = 1f / fontLettersY; int lastCharacter = fontLettersX * fontLettersY; if (lastCharacter != fontDefinitionString.Length) { JUtil.LogMessage(this, "Warning, number of letters in the font definition does not match font bitmap size."); } for (int i = 0; i < lastCharacter && i < fontDefinitionString.Length; i++) { int xSource = i % fontLettersX; int ySource = (i - xSource) / fontLettersX; if (!fontCharacters.ContainsKey(fontDefinitionString[i])) { fontCharacters[fontDefinitionString[i]] = new Rect(letterSpanX * xSource, letterSpanY * (fontLettersY - ySource - 1), letterSpanX, letterSpanY); } } // And a little optimisation for superscript/subscript: fontLetterHalfHeight = fontLetterHeight / 2f; fontLetterHalfWidth = fontLetterWidth / 2f; fontLetterDoubleWidth = fontLetterWidth * 2f; // Now that is done, proceed to setting up the screen. screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32); screenMat = internalProp.FindModelTransform(screenTransform).renderer.material; foreach (string layerID in textureLayerID.Split()) { screenMat.SetTexture(layerID.Trim(), screenTexture); } if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes())) { noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false); } // Create camera instance... cameraStructure = new FlyingCamera(part, screenTexture, cameraAspect); // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work. // Well, we don't need it. GameDatabase, gimme config nodes for all props! foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP")) { // Now, we know our own prop name. if (node.GetValue("name") == internalProp.propName) { // So this is the configuration of our prop in memory. Nice place. // We know it contains at least one MODULE node, us. // And we know our moduleID, which is the number in order of being listed in the prop. // Therefore the module by that number is our module's own config node. ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID]; ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE"); // Which we can now parse for page definitions. for (int i = 0; i < pageNodes.Length; i++) { // Mwahahaha. try { var newPage = new MonitorPage(i, pageNodes[i], this); activePage = activePage ?? newPage; if (newPage.isDefault) { activePage = newPage; } pages.Add(newPage); } catch (ArgumentException e) { JUtil.LogMessage(this, "Warning - {0}", e); } } // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts. foreach (string value in moduleConfig.GetValues("extraFont")) { fontTexture.Add(LoadFont(this, internalProp, value, true)); } break; } } JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count); // Load our state from storage... persistentVarName = "activePage" + internalProp.propID; persistence = new PersistenceAccessor(part); int?activePageID = persistence.GetVar(persistentVarName); if (activePageID != null && activePageID.Value < pages.Count) { activePage = pages[activePageID.Value]; } activePage.Active(true); // If we have global buttons, set them up. if (!string.IsNullOrEmpty(globalButtons)) { string[] tokens = globalButtons.Split(','); for (int i = 0; i < tokens.Length; i++) { string buttonName = tokens[i].Trim(); // Notice that holes in the global button list ARE legal. if (!string.IsNullOrEmpty(buttonName)) { SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease); } } } audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false); startupComplete = true; }