/// <summary> /// Draws the province labels for a given country. Note that it will update cached textmesh objects if labels are already drawn. Used internally. /// </summary> void DrawProvinceLabelsInt(Country country) { if (!Application.isPlaying || !_showProvinceNames || !gameObject.activeInHierarchy || country == null || country.hidden || provinces == null || country.provinces == null) { return; } countryProvincesLabelsShown = country; // Set colors provLabelsFont.material.color = _provinceLabelsColor; provLabelsShadowMaterial.color = _provinceLabelsShadowColor; // Create texts GameObject overlay = GetOverlayLayer(true); Transform t = overlay.transform.Find(OVERLAY_TEXT_PROVINCE_ROOT); if (t == null) { textProvinceRoot = new GameObject(OVERLAY_TEXT_PROVINCE_ROOT); if (disposalManager != null) { disposalManager.MarkForDisposal(textProvinceRoot); // textProvinceRoot.hideFlags = HideFlags.DontSave; } textProvinceRoot.layer = overlay.layer; } else { textProvinceRoot = t.gameObject; } if (meshRects == null) { meshRects = new List <MeshRect> (country.provinces.Length); } else { meshRects.Clear(); } float mw = mapWidth; float mh = mapHeight; for (int p = 0; p < country.provinces.Length; p++) { Province province = country.provinces[p]; if (province.regions == null) { ReadProvincePackedString(province); } if (province == null || province.hidden || !province.labelVisible || province.regions == null || province.mainRegionIndex < 0 || province.mainRegionIndex >= province.regions.Count) { continue; } if (_provinceLabelsVisibility == PROVINCE_LABELS_VISIBILITY.Automatic && !_showAllCountryProvinceNames && province != _provinceHighlighted) { continue; } Vector2 center = new Vector2(province.center.x * mapWidth, province.center.y * mh) + province.labelOffset; Region region = province.regions[province.mainRegionIndex]; // Adjusts province name length string provinceName = province.customLabel != null ? province.customLabel : province.name.ToUpper(); bool introducedCarriageReturn = false; if (provinceName.Length > 15) { int spaceIndex = provinceName.IndexOf(' ', provinceName.Length / 2); if (spaceIndex >= 0) { provinceName = provinceName.Substring(0, spaceIndex) + "\n" + provinceName.Substring(spaceIndex + 1); introducedCarriageReturn = true; } } // add caption GameObject textObj; TextMesh tm; Renderer tmRenderer; TextMesh tmShadow = null; if (province.labelTextMeshGO == null) { Color labelColor = province.labelColorOverride ? province.labelColor : _provinceLabelsColor; Font customFont = province.labelFontOverride ?? provLabelsFont; Material customLabelShadowMaterial = province.labelFontShadowMaterial ?? provLabelsShadowMaterial; tm = Drawing.CreateText(provinceName, null, center, customFont, labelColor, _showProvinceLabelsShadow, customLabelShadowMaterial, _provinceLabelsShadowColor, out tmShadow); textObj = tm.gameObject; province.labelTextMesh = tm; province.labelTextMeshGO = tm.gameObject; tmRenderer = textObj.GetComponent <Renderer>(); Bounds bounds = tmRenderer.bounds; province.labelMeshWidth = bounds.size.x; province.labelMeshHeight = bounds.size.y; province.labelMeshCenter = center; textObj.transform.SetParent(textProvinceRoot.transform, false); textObj.transform.localPosition = center; textObj.layer = textProvinceRoot.gameObject.layer; if (_showProvinceLabelsShadow) { province.labelShadowTextMesh = tmShadow; province.labelShadowTextMesh.gameObject.layer = textObj.layer; } } else { tm = province.labelTextMesh; textObj = tm.gameObject; textObj.transform.localPosition = center; tmRenderer = textObj.GetComponent <Renderer>(); } float meshWidth = province.labelMeshWidth; float meshHeight = province.labelMeshHeight; // adjusts caption Rect rect = new Rect(region.rect2D.xMin * mw, region.rect2D.yMin * mh, region.rect2D.width * mw, region.rect2D.height * mh); float absoluteHeight; if (province.labelRotation > 0) { textObj.transform.localRotation = Quaternion.Euler(0, 0, province.labelRotation); absoluteHeight = Mathf.Min(rect.height * _provinceLabelsSize, rect.width); } else if (rect.height > rect.width * 1.45f) { float angle; if (rect.height > rect.width * 1.5f) { angle = 90; } else { angle = Mathf.Atan2(rect.height, rect.width) * Mathf.Rad2Deg; } textObj.transform.localRotation = Quaternion.Euler(0, 0, angle); absoluteHeight = Mathf.Min(rect.width * _provinceLabelsSize, rect.height); } else { absoluteHeight = Mathf.Min(rect.height * _provinceLabelsSize, rect.width); } // adjusts scale to fit width in rect float adjustedMeshHeight = introducedCarriageReturn ? meshHeight * 0.5f : meshHeight; float scale = absoluteHeight / adjustedMeshHeight; if (province.labelFontSizeOverride) { scale = province.labelFontSize; } else { float desiredWidth = meshWidth * scale; if (desiredWidth > rect.width) { scale = rect.width / meshWidth; } if (adjustedMeshHeight * scale < _provinceLabelsAbsoluteMinimumSize) { scale = _provinceLabelsAbsoluteMinimumSize / adjustedMeshHeight; } } // stretchs out the caption float displayedMeshWidth = meshWidth * scale; float displayedMeshHeight = meshHeight * scale; string wideName; int times = Mathf.FloorToInt(rect.width * 0.45f / (meshWidth * scale)); if (times > 10) { times = 10; } if (times > 0) { StringBuilder sb = new StringBuilder(); string spaces = new string(' ', times * 2); for (int c = 0; c < provinceName.Length; c++) { sb.Append(provinceName[c]); if (c < provinceName.Length - 1) { sb.Append(spaces); } } wideName = sb.ToString(); } else { wideName = provinceName; } if (tm.text.Length != wideName.Length) { tm.text = wideName; displayedMeshWidth = tmRenderer.bounds.size.x * scale; displayedMeshHeight = tmRenderer.bounds.size.y * scale; if (_showProvinceLabelsShadow) { tmShadow.text = wideName; } } // apply scale textObj.transform.localScale = new Vector3(scale, scale, 1); // Save mesh rect for overlapping checking if (province.labelOffset == Misc.Vector2zero) { int provinceIndex = GetProvinceIndex(province); float xMin = center.x - displayedMeshWidth * 0.5f; float yMin = center.y - displayedMeshHeight * 0.5f; float xMax = xMin + displayedMeshWidth; float yMax = yMin + displayedMeshHeight; MeshRect mr = new MeshRect(provinceIndex, new Vector4(xMin, yMin, xMax, yMax)); // MeshRect mr = new MeshRect(provinceIndex, new Rect(center.x - displayedMeshWidth * 0.5f, center.y - displayedMeshHeight * 0.5f, displayedMeshWidth, displayedMeshHeight)); meshRects.Add(mr); } } // Simple-fast overlapping checking int cont = 0; bool needsResort = true; int meshRectsCount = meshRects.Count; while (needsResort && ++cont < 10) { meshRects.Sort(overlapComparer); for (int c = 1; c < meshRectsCount; c++) { Vector4 r1 = meshRects[c].rect; for (int prevc = c - 1; prevc >= 0; prevc--) { Vector4 r2 = meshRects[prevc].rect; bool overlaps = !(r2.x > r1.z || r2.z <r1.x || r2.y> r1.w || r2.w < r1.y); if (overlaps) { needsResort = true; int thisProvinceIndex = meshRects[c].entityIndex; Province province = _provinces[thisProvinceIndex]; GameObject thisLabel = province.labelTextMeshGO; // displaces this label float offsety = r1.w - r2.y; offsety = Mathf.Min(province.regions[province.mainRegionIndex].rect2D.height * mh * 0.35f, offsety); thisLabel.transform.localPosition = new Vector3(province.labelMeshCenter.x, province.labelMeshCenter.y - offsety, thisLabel.transform.localPosition.z); // r1 = new Rect(thisLabel.transform.localPosition.x - r1.width * 0.5f, // thisLabel.transform.localPosition.y - r1.height * 0.5f, // r1.width, r1.height); // meshRects[c].rect = r1; float width = r1.z - r1.x; float height = r1.w - r1.y; float xMin = thisLabel.transform.localPosition.x - width * 0.5f; float yMin = thisLabel.transform.localPosition.y - height * 0.5f; float xMax = xMin + width; float yMax = yMin + height; r1 = new Vector4(xMin, yMin, xMax, yMax); meshRects [c].rect = r1; } } } } // Adjusts parent textProvinceRoot.transform.SetParent(overlay.transform, false); textProvinceRoot.transform.localPosition = new Vector3(0, 0, -0.001f); textProvinceRoot.transform.localRotation = Misc.QuaternionZero; textProvinceRoot.transform.localScale = new Vector3(1.0f / mw, 1.0f / mh, 1); // Adjusts alpha based on distance to camera if (Application.isPlaying) { FadeProvinceLabels(); } }
/// <summary> /// Adds a new ticker text to a ticker line. /// </summary> public void AddTickerText(TickerText tickerText) { if (tickerText == null) { Debug.LogWarning("Tried to add an empty ticker. Ignoring."); return; } if (tickerBands == null) { Debug.LogWarning("Tickers has not been initialized properly."); return; } if (tickerText.tickerLine < 0 || tickerText.tickerLine >= tickerBands.Length) { Debug.LogWarning("Ticker line " + tickerText.tickerLine + " doesn't exist."); return; } TickerBand tickerBand = tickerBands[tickerText.tickerLine]; GameObject tickerBandObj = tickerBand.gameObject; if (tickerBandObj == null) { Debug.LogWarning("Ticker band " + tickerText.tickerLine + " has been destroyed. Can't add text."); return; } Font customFont = tickerText.font ?? defaultFont; Material customShadowMaterial = tickerText.shadowMaterial ?? defaultShadowMaterial; // Creates TextMesh Object Vector2 pos = new Vector2(tickerText.horizontalOffset, 0); TickerTextAnimator[] previous = tickerBandObj.GetComponentsInChildren <TickerTextAnimator>(); GameObject tickerTextObj = Drawing.CreateText(tickerText.text, null, pos, customFont, tickerText.textColor, tickerText.drawTextShadow, customShadowMaterial, tickerText.shadowColor, tickerText.anchor).gameObject; tickerTextObj.layer = tickerBandObj.layer; if (tickerText.drawTextShadow) { tickerTextObj.transform.Find("shadow").gameObject.layer = tickerTextObj.layer; } tickerText.gameObject = tickerTextObj; tickerText.textMeshSize = tickerTextObj.GetComponent <Renderer>().bounds.size; tickerTextObj.transform.SetParent(tickerBandObj.transform, false); // Apply scale (text size) Vector3 parentSize = new Vector3(WMSK.mapWidth, tickerBand.verticalSize * WMSK.mapHeight, 1.0f); float textScale = 0.003f * tickerText.textMeshSize.y * tickerText.textScale; tickerTextObj.transform.localScale = new Vector3(textScale * parentSize.y / parentSize.x, textScale, 1.0f); tickerText.textMeshSize = new Vector2(WMSK.mapWidth * tickerBandObj.transform.localScale.x * tickerText.textMeshSize.x * tickerTextObj.transform.localScale.x, WMSK.mapHeight * tickerBandObj.transform.localScale.y * tickerText.textMeshSize.y * tickerTextObj.transform.localScale.y); tickerTextObj.AddComponent <TickerTextAnimator>().tickerText = tickerText; // Position the text float x = pos.x; if (tickerBand.scrollSpeed != 0) { x = 0.5f + 0.5f * tickerText.textMeshSize.x / parentSize.x; // Adds other previous tickertexts on the band float widthSum = 0; for (int p = 0; p < previous.Length; p++) { widthSum += previous[p].tickerText.textMeshSize.x / parentSize.x; } if (widthSum > 0) { x = x + 0.01f + widthSum; } if (tickerBand.scrollSpeed > 0) { x = -x; } } pos = new Vector3(x, tickerTextObj.transform.localPosition.y); tickerTextObj.transform.localPosition = new Vector3(pos.x, 0.06f, _overlayMode ? -0.0001f : -0.002f); }
void DrawUnityStandardTextLabels() { ResetDefaultCountryLabelOffset(); if (meshRects == null) { meshRects = new List <MeshRect> (_countries.Length); } else { meshRects.Clear(); } float mw = mapWidth; float mh = mapHeight; for (int countryIndex = 0; countryIndex < _countries.Length; countryIndex++) { Country country = _countries [countryIndex]; if (country.hidden || !country.labelVisible || country.mainRegionIndex < 0 || country.mainRegionIndex >= country.regions.Count) { continue; } Vector2 center = new Vector2(country.center.x * mapWidth, country.center.y * mh) + country.labelOffset; center += GetDefaultCountryLabelOffset(countryIndex); Region region = country.regions [country.mainRegionIndex]; // Adjusts country name length string countryName = country.customLabel != null ? country.customLabel : country.name.ToUpper(); bool introducedCarriageReturn = false; if (countryName.Length > 15) { countryName = BreakOneLineString(countryName); introducedCarriageReturn = true; } // add caption GameObject textObj; TextMesh tm; Renderer tmRenderer; TextMesh tmShadow = null; if (country.labelTextMeshGO == null) { Color labelColor = country.labelColorOverride ? country.labelColor : _countryLabelsColor; Font customFont = country.labelFontOverride ?? labelsFont; if ((object)customFont == null) { continue; } Material customLabelShadowMaterial = country.labelFontShadowMaterial ?? labelsShadowMaterial; tm = Drawing.CreateText(countryName, null, center, customFont, labelColor, _showLabelsShadow, customLabelShadowMaterial, _countryLabelsShadowColor, out tmShadow); textObj = tm.gameObject; country.labelTextMesh = tm; country.labelTextMeshGO = tm.gameObject; tmRenderer = textObj.GetComponent <Renderer> (); Bounds bounds = tmRenderer.bounds; country.labelMeshWidth = bounds.size.x; country.labelMeshHeight = bounds.size.y; country.labelMeshCenter = center; textObj.transform.SetParent(textRoot.transform, false); textObj.transform.localPosition = center; textObj.layer = textRoot.gameObject.layer; if (_showLabelsShadow) { country.labelShadowTextMesh = tmShadow; //textObj.transform.Find ("shadow").GetComponent<TextMesh> (); country.labelShadowTextMesh.gameObject.layer = textObj.layer; } } else { tm = country.labelTextMesh; textObj = tm.gameObject; textObj.transform.localPosition = center; tmRenderer = textObj.GetComponent <Renderer> (); } float meshWidth = country.labelMeshWidth; float meshHeight = country.labelMeshHeight; // adjusts caption Rect rect = new Rect(region.rect2D.xMin * mw, region.rect2D.yMin * mh, region.rect2D.width * mw, region.rect2D.height * mh); float absoluteHeight; if (country.labelRotation > 0) { textObj.transform.localRotation = Quaternion.Euler(0, 0, country.labelRotation); absoluteHeight = Mathf.Min(rect.height * _countryLabelsSize, rect.width); } else if (rect.height > rect.width * 1.45f) { float angle; if (rect.height > rect.width * 1.5f) { angle = 90; } else { angle = Mathf.Atan2(rect.height, rect.width) * Mathf.Rad2Deg; } textObj.transform.localRotation = Quaternion.Euler(0, 0, angle); absoluteHeight = Mathf.Min(rect.width * _countryLabelsSize, rect.height); } else { absoluteHeight = Mathf.Min(rect.height * _countryLabelsSize, rect.width); } // adjusts scale to fit width in rect float adjustedMeshHeight = introducedCarriageReturn ? meshHeight * 0.5f : meshHeight; float scale = absoluteHeight / adjustedMeshHeight; if (country.labelFontSizeOverride) { scale = country.labelFontSize; } else { float desiredWidth = meshWidth * scale; if (desiredWidth > rect.width) { scale = rect.width / meshWidth; } if (adjustedMeshHeight * scale < _countryLabelsAbsoluteMinimumSize) { scale = _countryLabelsAbsoluteMinimumSize / adjustedMeshHeight; } } // stretchs out the caption float displayedMeshWidth = meshWidth * scale; float displayedMeshHeight = meshHeight * scale; string wideName; int times = Mathf.FloorToInt(rect.width * 0.45f / (meshWidth * scale)); if (times > 10) { times = 10; } if (times > 0) { StringBuilder sb = new StringBuilder(); string spaces = new string (' ', times * 2); for (int c = 0; c < countryName.Length; c++) { sb.Append(countryName [c]); if (c < countryName.Length - 1) { sb.Append(spaces); } } wideName = sb.ToString(); } else { wideName = countryName; } if (tm.text.Length != wideName.Length) { tm.text = wideName; displayedMeshWidth = tmRenderer.bounds.size.x * scale; displayedMeshHeight = tmRenderer.bounds.size.y * scale; if (_showLabelsShadow) { tmShadow.text = wideName; } } // apply scale textObj.transform.localScale = new Vector3(scale, scale, 1); // Save mesh rect for overlapping checking if (country.labelOffset == Misc.Vector2zero) { float xMin = center.x - displayedMeshWidth * 0.5f; float yMin = center.y - displayedMeshHeight * 0.5f; float xMax = xMin + displayedMeshWidth; float yMax = yMin + displayedMeshHeight; MeshRect mr = new MeshRect(countryIndex, new Vector4(xMin, yMin, xMax, yMax)); meshRects.Add(mr); } } // Simple-fast overlapping checking int cont = 0; bool needsResort = true; int meshRectsCount = meshRects.Count; while (needsResort && ++cont < 10) { meshRects.Sort(overlapComparer); needsResort = false; for (int c = 1; c < meshRectsCount; c++) { Vector4 r1 = meshRects [c].rect; for (int prevc = c - 1; prevc >= 0; prevc--) { Vector4 r2 = meshRects [prevc].rect; bool overlaps = !(r2.x > r1.z || r2.z <r1.x || r2.y> r1.w || r2.w < r1.y); if (overlaps) { needsResort = true; int thisCountryIndex = meshRects [c].entityIndex; Country country = _countries [thisCountryIndex]; GameObject thisLabel = country.labelTextMeshGO; // displaces this label float offsety = r1.w - r2.y; offsety = Mathf.Min(country.regions [country.mainRegionIndex].rect2D.height * mh * 0.35f, offsety); thisLabel.transform.localPosition = new Vector3(country.labelMeshCenter.x, country.labelMeshCenter.y - offsety, thisLabel.transform.localPosition.z); float width = r1.z - r1.x; float height = r1.w - r1.y; float xMin = thisLabel.transform.localPosition.x - width * 0.5f; float yMin = thisLabel.transform.localPosition.y - height * 0.5f; float xMax = xMin + width; float yMax = yMin + height; r1 = new Vector4(xMin, yMin, xMax, yMax); meshRects [c].rect = r1; } } } } }