Various dead-end attempts at font loading and rendering
parent
ecb3eccfe5
commit
f9d9c228ae
@ -0,0 +1,57 @@
|
||||
PART
|
||||
{
|
||||
name = conformaldecals-text
|
||||
module = Part
|
||||
author = Andrew Cassidy
|
||||
MODEL
|
||||
{
|
||||
model = ConformalDecals/Assets/decal-blank
|
||||
scale = 1.0, 1.0, 1.0
|
||||
}
|
||||
rescaleFactor = 1
|
||||
|
||||
// Attachment
|
||||
attachRules = 1,1,0,0,1
|
||||
node_attach = 0.0, 0.0, 0.1, 0.0, 0.0, -1.0
|
||||
|
||||
// Tech
|
||||
TechRequired = start
|
||||
|
||||
// Info
|
||||
cost = 75
|
||||
category = Structural
|
||||
|
||||
// CDL-F Flag Decal
|
||||
title = Conformal Text
|
||||
|
||||
// Peel-N-Stik Adhesive Decals
|
||||
manufacturer = #LOC_ConformalDecals_agent-peel-n-stick_title
|
||||
|
||||
// A simple switchable flag. Can either use the mission flag or select a specific flag to use.
|
||||
description = #LOC_ConformalDecals_flag-description
|
||||
|
||||
// conformal decal sticker flag
|
||||
tags = #LOC_ConformalDecals_flag-tags
|
||||
|
||||
bulkheadProfiles = srf
|
||||
|
||||
// Parameters
|
||||
mass = 0.0005
|
||||
dragModel = NONE
|
||||
angularDrag = 0.0
|
||||
crashTolerance = 10
|
||||
maxTemp = 2000
|
||||
breakingForce = 350
|
||||
breakingTorque = 150
|
||||
physicalSignificance = NONE
|
||||
|
||||
MODULE
|
||||
{
|
||||
name = ModuleConformalText
|
||||
|
||||
useBaseNormal = true
|
||||
|
||||
defaultDepth = 0.2
|
||||
defaultCutoff = 0
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,41 @@
|
||||
using ConformalDecals.Util;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals {
|
||||
public class ModuleConformalText: ModuleConformalDecal {
|
||||
private const string DefaultFlag = "Squad/Flags/default";
|
||||
|
||||
[KSPField(isPersistant = true)] public string text = "Hello World!";
|
||||
|
||||
public override void OnLoad(ConfigNode node) {
|
||||
base.OnLoad(node);
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
public override void OnStart(StartState state) {
|
||||
base.OnStart(state);
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
private void SetText(string newText) {
|
||||
if (!HighLogic.LoadedSceneIsEditor) return;
|
||||
|
||||
this.Log("Rendering text for part");
|
||||
var fonts = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
|
||||
|
||||
foreach (var font in fonts) {
|
||||
this.Log($"Font: {font.name}");
|
||||
foreach (var fallback in font.fallbackFontAssets) {
|
||||
this.Log($" Fallback: {fallback.name}");
|
||||
}
|
||||
}
|
||||
|
||||
materialProperties.AddOrGetTextureProperty("_Decal", true).Texture = TextRenderer.RenderToTexture(fonts[0], newText);
|
||||
|
||||
UpdateMaterials();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.Text {
|
||||
public class DecalFont : ScriptableObject {
|
||||
[SerializeField] public string foo1;
|
||||
[SerializeField] public string foo2;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals.Text {
|
||||
|
||||
[DatabaseLoaderAttrib(new[] {"kspfont"})]
|
||||
public class FontLoader : DatabaseLoader<GameDatabase.TextureInfo> {
|
||||
public static List<TMP_FontAsset> fonts;
|
||||
|
||||
public override IEnumerator Load(UrlDir.UrlFile urlFile, FileInfo fileInfo) {
|
||||
fonts ??= new List<TMP_FontAsset>();
|
||||
|
||||
Debug.Log($"[ConformalDecals] '{urlFile.fullPath}'");
|
||||
var bundle = AssetBundle.LoadFromFile(urlFile.fullPath);
|
||||
if (!bundle) {
|
||||
Debug.Log($"[ConformalDecals] could not load font asset {urlFile.fullPath}");
|
||||
}
|
||||
else {
|
||||
var loadedFoo = bundle.LoadAllAssets<DecalFont>();
|
||||
Debug.Log(loadedFoo[0].foo1);
|
||||
Debug.Log(loadedFoo[0].foo2);
|
||||
var loadedFonts = bundle.LoadAllAssets<TMP_FontAsset>();
|
||||
foreach (var font in loadedFonts) {
|
||||
Debug.Log($"[ConformalDecals] adding font {font.name}" );
|
||||
fonts.Add(font);
|
||||
Debug.Log($"ConformalDecals] isReadable: {font.atlas.isReadable}");
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using ConformalDecals.Util;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ConformalDecals {
|
||||
public class TextRenderer {
|
||||
private struct GlyphInfo {
|
||||
public TMP_Glyph glyph;
|
||||
public Vector2Int size;
|
||||
public Vector2Int position;
|
||||
public int fontIndex;
|
||||
public bool needsResample;
|
||||
}
|
||||
|
||||
private struct FontInfo {
|
||||
public TMP_FontAsset font;
|
||||
public Texture2D fontAtlas;
|
||||
public Color32[] fontAtlasColors;
|
||||
}
|
||||
|
||||
public static Texture2D RenderToTexture(TMP_FontAsset font, string text) {
|
||||
Debug.Log($"Rendering text: {text}");
|
||||
var charArray = text.ToCharArray();
|
||||
var glyphInfoArray = new GlyphInfo[charArray.Length];
|
||||
var fontInfoArray = new FontInfo[charArray.Length];
|
||||
|
||||
var baseScale = font.fontInfo.Scale;
|
||||
|
||||
var padding = (int) font.fontInfo.Padding;
|
||||
var ascender = (int) font.fontInfo.Ascender;
|
||||
var descender = (int) font.fontInfo.Descender;
|
||||
var baseline = (int) baseScale * (descender + padding);
|
||||
Debug.Log($"baseline: {baseline}");
|
||||
Debug.Log($"ascender: {ascender}");
|
||||
Debug.Log($"descender: {descender}");
|
||||
Debug.Log($"baseScale: {baseScale}");
|
||||
|
||||
fontInfoArray[0].font = font;
|
||||
|
||||
int xAdvance = 0;
|
||||
for (var i = 0; i < charArray.Length; i++) {
|
||||
|
||||
var glyphFont = TMP_FontUtilities.SearchForGlyph(font, charArray[i], out var glyph);
|
||||
|
||||
if (glyphFont == font) {
|
||||
glyphInfoArray[i].fontIndex = 0;
|
||||
}
|
||||
else {
|
||||
for (int f = 1; i < charArray.Length; i++) {
|
||||
if (fontInfoArray[f].font == null) {
|
||||
fontInfoArray[f].font = glyphFont;
|
||||
glyphInfoArray[i].fontIndex = f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fontInfoArray[f].font == glyphFont) {
|
||||
glyphInfoArray[i].fontIndex = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"getting font info for character: '{charArray[i]}'");
|
||||
Debug.Log($"character font: {glyphFont.name}");
|
||||
|
||||
glyphInfoArray[i].glyph = glyph;
|
||||
glyphInfoArray[i].needsResample = false;
|
||||
|
||||
float elementScale = glyph.scale;
|
||||
|
||||
if (glyphFont == font) {
|
||||
if (!Mathf.Approximately(elementScale, 1)) {
|
||||
glyphInfoArray[i].needsResample = true;
|
||||
}
|
||||
|
||||
elementScale *= baseScale;
|
||||
}
|
||||
else {
|
||||
var fontScale = glyphFont.fontInfo.Scale / glyphFont.fontInfo.PointSize;
|
||||
if (!Mathf.Approximately(fontScale, baseScale)) {
|
||||
glyphInfoArray[i].needsResample = true;
|
||||
}
|
||||
|
||||
elementScale *= fontScale;
|
||||
}
|
||||
|
||||
Debug.Log($"character scale: {glyphFont.fontInfo.Scale / glyphFont.fontInfo.PointSize}");
|
||||
Debug.Log($"character needs resampling: {glyphInfoArray[i].needsResample}");
|
||||
|
||||
glyphInfoArray[i].size.x = (int) ((glyph.width + (padding * 2)) * elementScale);
|
||||
glyphInfoArray[i].size.y = (int) ((glyph.height + (padding * 2)) * elementScale);
|
||||
glyphInfoArray[i].position.x = (int) ((xAdvance + glyph.xOffset - padding) * elementScale);
|
||||
glyphInfoArray[i].position.y = (int) ((baseline + glyph.yOffset - padding) * elementScale);
|
||||
|
||||
Debug.Log($"character size: {glyphInfoArray[i].size}");
|
||||
Debug.Log($"character position: {glyphInfoArray[i].position}");
|
||||
}
|
||||
|
||||
// calculate texture bounds
|
||||
int xOffset = glyphInfoArray[0].position.x;
|
||||
var textureWidth = (glyphInfoArray[charArray.Length - 1].position.x + glyphInfoArray[charArray.Length - 1].size.x) - xOffset;
|
||||
var textureHeight = (int) baseScale * (ascender + descender + padding * 2);
|
||||
|
||||
// ensure texture sizes are powers of 2
|
||||
textureWidth = Mathf.NextPowerOfTwo(textureWidth);
|
||||
textureHeight = Mathf.NextPowerOfTwo(textureHeight);
|
||||
Debug.Log($"texture is {textureWidth} x {textureHeight}");
|
||||
|
||||
var texture = new Texture2D(textureWidth, textureHeight, TextureFormat.Alpha8, true);
|
||||
|
||||
var colors = new Color32[textureWidth * textureHeight];
|
||||
|
||||
for (var i = 0; i < fontInfoArray.Length; i++) {
|
||||
if (fontInfoArray[i].font == null) break;
|
||||
fontInfoArray[i].fontAtlas = fontInfoArray[i].font.atlas;
|
||||
fontInfoArray[i].fontAtlasColors = fontInfoArray[i].fontAtlas.GetPixels32();
|
||||
}
|
||||
|
||||
for (int i = 0; i < charArray.Length; i++) {
|
||||
var glyphInfo = glyphInfoArray[i];
|
||||
var glyph = glyphInfo.glyph;
|
||||
var fontInfo = fontInfoArray[glyphInfo.fontIndex];
|
||||
|
||||
var srcPos = new Vector2Int((int) glyph.x, (int) glyph.y);
|
||||
var dstPos = glyphInfo.position;
|
||||
dstPos.x += xOffset;
|
||||
var dstSize = glyphInfo.size;
|
||||
|
||||
Debug.Log($"rendering character number {i}");
|
||||
|
||||
if (glyphInfo.needsResample) {
|
||||
var srcSize = new Vector2(glyph.width, glyph.height);
|
||||
TextureUtils.BlitRectBilinearAlpha(fontInfo.fontAtlas, srcPos, srcSize, texture, colors, dstPos, dstSize, TextureUtils.BlitMode.Add);
|
||||
}
|
||||
else {
|
||||
TextureUtils.BlitRectAlpha(fontInfo.fontAtlas, fontInfo.fontAtlasColors, srcPos, texture, colors, dstPos, dstSize, TextureUtils.BlitMode.Add);
|
||||
}
|
||||
}
|
||||
|
||||
texture.Apply(true);
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue