/// <summary> /// The following script text is experimental /// it is based on JyC. /// It provide direct access to C# methods and objects /// but it may not be the most intuitive for our users /// It is accessbile through tags <@# .... @> /// /// </summary> public static void EvalScriptText (TTFText tm, string s, ref TTFTextInternal.LineLayout ll) { #if! TTFTEXT_LITE // TTFTextStyle ts = tm.CurrentTextStyle; Jyc.Expr.Parser ep = new Jyc.Expr.Parser (); Jyc.Expr.Tree tree; try { tree = ep.Parse (s); Jyc.Expr.Evaluator evaluater = new Jyc.Expr.Evaluator (); Jyc.Expr.ParameterVariableHolder pvh = new Jyc.Expr.ParameterVariableHolder (); pvh.Parameters ["T"] = pvh.Parameters ["text"] = new Jyc.Expr.Parameter (tm); pvh.Parameters ["S"] = pvh.Parameters ["style"] = new Jyc.Expr.Parameter (ts); pvh.Parameters ["L"] = pvh.Parameters ["linelayout"] = new Jyc.Expr.Parameter (ll); //pvh.Parameters ["I"] = pvh.Parameters ["img"] = new Jyc.Expr.Parameter(TTFTextInternal.Get); evaluater.VariableHolder = pvh; ts = (TTFTextStyle)evaluater.Eval (tree); if (ts != null) { //Debug.Log ( ts.Size); tm.CurrentTextStyle = ts; } } catch (System.Exception e) { Debug.LogError (e); } #endif }
// EASY MARKUP public static void EvalEasyMarkUp (TTFText tm, string bs, ref TTFTextInternal.LineLayout ll) { // Debug.Log("Eval "+bs); #if TTFTEXT_LITE if (tm.DemoMode) { #endif TTFTextStyle ts = tm.CurrentTextStyle; try { bs = bs.Trim (); if (bs [0] == '#') { EvalScriptText (tm, bs.Substring (1), ref ll); } char [] separators = {'|'}; foreach (string s in bs.Split(separators)) { if (s.Contains ("=")) { char [] seps = {'='}; string [] vals = s.Split (seps); string lval = vals [0].Trim (); string rval = vals [1].Trim (); if (lval == "style") { if (rval.Contains ("<")) { // probably invalid return; } ts = ts.PushF (rval, tm.autoCreateStyles, ref tm.nonFoundStyles); } else { if (!lval.Contains ("#")) { // we modify our component System.Type tp = typeof(TTFTextStyle); System.Reflection.PropertyInfo pi = tp.GetProperty (lval); string tpn = pi.PropertyType.Name; ts = ts.Push (); if (tpn == tpn_float) { if (rval [0] == '+') { pi.SetValue (ts, ((float)pi.GetValue (ts, null)) + System.Single.Parse (rval.Substring (1)), null); } else { if (rval [0] == '*') { pi.SetValue (ts, ((float)pi.GetValue (ts, null)) * System.Single.Parse (rval.Substring (1)), null); } else { pi.SetValue (ts, System.Single.Parse (rval), null); } } } else { if (tpn == tpn_bool) { pi.SetValue (ts, System.Boolean.Parse (rval), null); } else { if (tpn == tpn_int) { pi.SetValue (ts, System.Int32.Parse (rval), null); } else { if (tpn == tpn_string) { pi.SetValue (ts, rval, null); } else { Debug.LogWarning (pi.PropertyType.Name + " : Behaviour not defined"); } } } } } else { int isharp = lval.IndexOf ('#'); string comppart = lval.Substring (0, isharp); string fieldname = lval.Substring (isharp + 1); object o = (object)tm.gameObject.GetComponent (comppart); System.Type tp = o.GetType (); System.Reflection.FieldInfo fi = tp.GetField (fieldname); string tpn = fi.FieldType.Name; if (tpn == tpn_float) { if (rval [0] == '+') { fi.SetValue (o, ((float)fi.GetValue (o)) + System.Single.Parse (rval.Substring (1))); } else { if (rval [0] == '*') { fi.SetValue (o, ((float)fi.GetValue (o)) * System.Single.Parse (rval.Substring (1))); } else { fi.SetValue (o, System.Single.Parse (rval)); } } } else { if (tpn == tpn_bool) { fi.SetValue (o, System.Boolean.Parse (rval)); } else { if (tpn == tpn_int) { fi.SetValue (o, System.Int32.Parse (rval)); } else { if (tpn == tpn_string) { fi.SetValue (o, rval); } else { Debug.LogWarning (fi.FieldType.Name + " : Behaviour not defined"); } } } } } } } else { if ((s.ToLower () == "end") || (s.ToLower () == "pop")) { ts = ts.Pop (); } else { Debug.LogError ("(TTFText) Unknown command : " + s); } } // Debug.Log("Setting ts fontid : "+ts.FontId+" getid : " +ts.getid()); tm.CurrentTextStyle = ts; } } catch (System.Exception e) { Debug.LogError (e); } #if TTFTEXT_LITE } #endif }
/// <summary> /// Subdivides line into individual characters /// </summary> /// <returns> /// The one per char. /// </returns> /// <param name='l'> /// L. /// </param> static IEnumerable<TTFTextInternal.LineLayout> EOnePerChar (TTFTextInternal.LineLayout l) { int i = 0; float sa = 0; foreach (char c in l.line) { TTFTextInternal.LineLayout r = new TTFTextInternal.LineLayout ("" + c, l.tm, false); r.charadvances = new float[1]; r.charpositions = new float[1]; r.charstyleindex = new int[1]; r.charmetadata = new object[1]; r.charadvances [0] = l.charadvances [i]; r.charpositions [0] = 0; r.charstyleindex [0] = l.charstyleindex [i]; r.charmetadata [0] = l.charmetadata [i]; r.prevadvance = l.prevadvance + sa; r.linewidth = l.GetCharStyle (i).LineWidth; r.lineno = l.lineno; if (i + 1 < l.line.Length) { r.advancelen = l.charpositions [i + 1] - l.charpositions [i]; } else { r.advancelen = l.advancelen - l.charpositions [i]; } yield return r; sa += r.advancelen; i += 1; } }
static void FinalizeLL (ref TTFTextInternal.LineLayout ll, float firstlineoffset) { ll.offset = 0; if (((ll.align != TTFText.ParagraphAlignmentEnum.Right)) && ((ll.align != TTFText.ParagraphAlignmentEnum.Center))) { ll.offset = firstlineoffset; } ll.ComputeCharacterPositions (); if ((ll.align == TTFText.ParagraphAlignmentEnum.Right)) { // Debug.Log(System.String.Format("{0} {1}",ll.linewidth, ll.GetActualLinewidth())); ll.offset = ll.linewidth - ll.GetActualLinewidth (); } else { if ((ll.align == TTFText.ParagraphAlignmentEnum.Center)) { ll.offset = (ll.linewidth - ll.GetActualLinewidth ()) / 2; } else { ll.offset = firstlineoffset; } } }
/// <summary> /// The layout atoms are line /// </summary> /// <returns> /// The one per line. /// </returns> /// <param name='l'> /// L. /// </param> static IEnumerable<TTFTextInternal.LineLayout> EOnePerLine (TTFTextInternal.LineLayout l) { yield return l; }
/// <summary> /// Subdivide lines into words /// </summary> /// <returns> /// The one per line. /// </returns> /// <param name='l'> /// L. /// </param> static IEnumerable<TTFTextInternal.LineLayout> EOnePerWord (TTFTextInternal.LineLayout l) { char[] seps = new char[] { ' ' }; string[] words = l.line.Split (seps, System.StringSplitOptions.RemoveEmptyEntries); int p = 0; float sa = 0; foreach (string w in words) { int wlen = w.Length; int p0 = p; while (l.line[p] != w[0]) p++; // <- skipping spaces : BUG TO BE FIXED ! TTFTextInternal.LineLayout r = new TTFTextInternal.LineLayout (w, l.tm, false); r.prevadvance = l.prevadvance + sa; if (wlen > 0) { r.linewidth = l.GetCharStyle (p).LineWidth; } r.charadvances = new float[w.Length]; r.charpositions = new float[w.Length]; r.charstyleindex = new int[w.Length]; r.charmetadata = new object[w.Length]; for (int i = 0; i < wlen; i++) { r.charadvances [i] = l.charadvances [p + i]; r.charpositions [i] = l.charpositions [p + i] - l.charpositions [p0]; r.charstyleindex [i] = l.charstyleindex [p + i]; r.charmetadata [i] = l.charmetadata [p + i]; } if (p + wlen < l.line.Length) { r.advancelen = l.charpositions [p + wlen] - l.charpositions [p0]; } else { r.advancelen = l.advancelen - l.charpositions [p0]; } r.lineno = l.lineno; yield return r; sa += r.advancelen; p += wlen; } }
static TTFTextOutline[] MakeBevelOutlines (TTFTextInternal.LineLayout ll, TTFText tm, TTFTextStyle ts) { //Vector3 min=Vector3.zero; Vector3 max=Vector3.zero; //Vector3 min_; Vector3 max_; int NS = tm.NbDiv; if (NS < 2) { NS = 2; } TTFTextOutline[] outlines = new TTFTextOutline[NS * 2]; //Vector3[] szs = new Vector3[NS*2]; float bevelDepth = ts.BevelDepth * ts.ExtrusionDepth / 2; for (int i = 0; i < NS; ++i) { float f = ((float)i) / ((float)NS - 1); // [0,1] float embold = ts.Embold + Mathf.Sin (Mathf.Acos (1 - f)) * ts.BevelForce; TTFTextOutline o = MakeOutline (ll, embold, tm); o.Slant (ts.Slant); outlines [i] = o; outlines [2 * NS - 1 - i] = new TTFTextOutline (o); //outlines[i].GetMinMax(out min_, out max_); //szs[i]=max_-min_; float z = f * bevelDepth; outlines [i].Translate (Vector3.forward * z); outlines [2 * NS - 1 - i].Translate (Vector3.forward * (ts.ExtrusionDepth - z)); //szs[2*NS-1-i]=max_-min_; //min = Vector3.Min(min, min_); //max = Vector3.Max(max, max_); } //Vector3 sz=max-min; //for (int i=0;i<(2*NS);i++) { // outlines[i].Translate((sz-szs[i])/2); //} return outlines; }
public static TTFTextOutline MakeOutline (TTFTextInternal.LineLayout ll, float embold, TTFText tm) { return MakeOutline (ll.line, ll.hspacing, embold, tm, tm.OrientationReversed, ll.charpositions, ll.charstyleindex, ll.charmetadata); }
static TTFTextOutline[] MakeBentOutlines (TTFTextInternal.LineLayout ll, TTFText tm, TTFTextStyle ts) { //Vector3 min=Vector3.zero; Vector3 max=Vector3.zero; int NS = ts.ExtrusionSteps.Length; TTFTextOutline[] outlines = new TTFTextOutline[NS]; //Vector3 [] szs = new Vector3[NS]; for (int i = 0; i < NS; i++) { //Vector3 min_, max_; float embold = ts.Embold + ts.BevelForce * Mathf.Sin (i * Mathf.PI / (NS - 1)); // wierd error with poly2tri/embold for the backface if (i == NS - 1) { embold = ts.Embold; } outlines [i] = MakeOutline (ll, embold, tm); float z = (ts.ExtrusionSteps [i] - 0.5f) * ts.ExtrusionDepth;// - tm.exstrusionDepth / 2; outlines [i].Translate (Vector3.forward * z); if (ts.Slant != 0) { outlines [i].Slant (ts.Slant); } //outlines[i].GetMinMax(out min_, out max_); //szs[i]=max_-min_; //min = Vector3.Min(min, min_); //max = Vector3.Max(max, max_); } //Vector3 sz=max-min; //for (int i=0;i<NS;i++) { // outlines[i].Translate((sz-szs[i])/2); //} return outlines; }
// FreeHand Curve Extrusion public static TTFTextOutline[] MakeFreeHandOutlines (TTFTextInternal.LineLayout ll, TTFText tm, TTFTextStyle ts) { //Vector3 min=Vector3.zero; Vector3 max=Vector3.zero; Keyframe[] keys = ts.FreeHandCurve.keys; int NS = keys.Length; TTFTextOutline[] outlines = new TTFTextOutline[NS]; float[] z = new float[NS]; //min = Vector3.zero; //max = Vector3.zero; //Vector3 [] szs = new Vector3[NS]; for (int i=0; i<NS; i++) { // Vector3 min_, max_; z [i] = keys [i].time * ts.ExtrusionDepth; outlines [i] = MakeOutline (ll, ts.Embold + keys [i].value * ts.BevelForce, tm); outlines [i].Translate (Vector3.forward * z [i]); if (ts.Slant != 0) { outlines [i].Slant (ts.Slant); } //outlines[i].GetMinMax(out min_, out max_); //szs[i]=max_-min_; //min = Vector3.Min(min, min_); //max = Vector3.Max(max, max_); } //Vector3 sz=max-min; //for (int i=0;i<NS;i++) { // outlines[i].Translate((sz-szs[i])/2); //} return outlines; }
// Simple extrusion public static TTFTextOutline[] MakeSimpleOutlines (TTFTextInternal.LineLayout ll, TTFText tm, TTFTextStyle ts) { TTFTextOutline o = MakeOutline (ll, ts.Embold, tm); if (ts.Slant != 0) { o.Slant (ts.Slant); } TTFTextOutline[] outlines = new TTFTextOutline[2]; outlines [0] = o; outlines [1] = new TTFTextOutline (o); outlines [0].Translate (Vector3.forward * (-ts.ExtrusionDepth) / 2); outlines [1].Translate (Vector3.forward * ts.ExtrusionDepth / 2); return outlines; }
public static Mesh BuildMesh (ref Mesh mesh, TTFTextInternal.LineLayout ll, TTFText tm, out Vector3 advance) { Mesh front = null; Mesh back = null; TTFTextOutline[] outlines = {}; bool[] mask; advance = Vector3.zero; TTFTextStyle ts = tm.InitTextStyle; object charmetadata = null; if ((ll.charstyleindex != null) && (ll.charstyleindex [0] != -1)) { ts = ll.GetCharStyle (0); charmetadata = ll.charmetadata [0]; } if ((charmetadata != null) || (ts.ExtrusionMode == TTFText.ExtrusionModeEnum.None)) { // No extrusion TTFTextOutline o = MakeOutline (ll, ts.Embold, tm); charmetadata = ll.charmetadata [0]; o = o.Simplify (ts.SimplifyAmount, ts.Size); if (ts.Slant != 0) { o.Slant (ts.Slant); } advance = o.advance; front = TTFTextInternal.Tesselators.Triangulate (o, tm.DynamicTextRuntimeTriangulationMethod == TTFText.DynamicTextRuntimeTriangulationMethodEnum.CSharpLibs); if (tm.DynamicTextRuntimeTriangulationMethod == TTFText.DynamicTextRuntimeTriangulationMethodEnum.CSharpLibs) { TTFTextInternal.Utilities.ReverseTriangles (front); } if (tm.BackFace) { back = new Mesh (); back.vertices = front.vertices; back.triangles = front.triangles; TTFTextInternal.Utilities.ReverseTriangles (back); CombineInstance[] combine = new CombineInstance[2]; combine [0].mesh = front; combine [1].mesh = back; mesh.CombineMeshes (combine, false, false); Utilities.DestroyObj (front); Utilities.DestroyObj (back); } else { CombineInstance[] combine = new CombineInstance[1]; combine [0].mesh = front; mesh.CombineMeshes (combine, false, false); Utilities.DestroyObj (front); } } else if (ts.ExtrusionMode == TTFText.ExtrusionModeEnum.Pipe) { #if TTFTEXT_LITE if (tm.DemoMode) { #endif TTFTextOutline o = MakeOutline (ll, ts.Embold, tm); o = o.Simplify (ts.SimplifyAmount, ts.Size); if (ts.Slant != 0) { o.Slant (ts.Slant); } advance = o.advance; TTFTextInternalMeshGenerators.Piped (ref mesh, o, ts.Radius, ts.NumPipeEdges); #if TTFTEXT_LITE } #endif } else { switch (ts.ExtrusionMode) { case TTFText.ExtrusionModeEnum.Simple: outlines = MakeSimpleOutlines (ll, tm, ts); break; case TTFText.ExtrusionModeEnum.Bent: #if TTFTEXT_LITE if (tm.DemoMode) { #endif outlines = MakeBentOutlines (ll, tm, ts); #if TTFTEXT_LITE } #endif break; case TTFText.ExtrusionModeEnum.Bevel: #if TTFTEXT_LITE if (tm.DemoMode) { #endif outlines = MakeBevelOutlines (ll, tm, ts); #if TTFTEXT_LITE } #endif break; case TTFText.ExtrusionModeEnum.FreeHand: #if TTFTEXT_LITE if (tm.DemoMode) { #endif outlines = MakeFreeHandOutlines (ll, tm, ts); #if TTFTEXT_LITE } #endif break; default: Debug.LogError ("(TTFText) Unexpected Extrusion Mode:" + tm.ExtrusionMode); break; } if (outlines.Length == 0) { mesh.Clear (); advance = Vector3.zero; return mesh; } //if (ts.OutlineEmbold >= 0) { // outlines = OutlineOutlines(outlines, ts.OutlineEmbold); //} mask = outlines [0].SimplifyMask (ts.SimplifyAmount, tm.Size); // front TTFTextOutline o = outlines [0].ApplyMask (mask); front = TTFTextInternal.Tesselators.Triangulate (o, tm.DynamicTextRuntimeTriangulationMethod == TTFText.DynamicTextRuntimeTriangulationMethodEnum.CSharpLibs);//tm.EmbedCharset); advance = o.advance; advance.z = 0; //back o = outlines [outlines.Length - 1].ApplyMask (mask); back = TTFTextInternal.Tesselators.Triangulate (o, tm.DynamicTextRuntimeTriangulationMethod == TTFText.DynamicTextRuntimeTriangulationMethodEnum.CSharpLibs);//tm.EmbedCharset); if (tm.DynamicTextRuntimeTriangulationMethod == TTFText.DynamicTextRuntimeTriangulationMethodEnum.CSharpLibs) { Utilities.ReverseTriangles (front); } else { Utilities.ReverseTriangles (back); } TTFTextInternalMeshGenerators.ExtrudeOutlines (ref mesh, front, back, outlines, mask); Utilities.DestroyObj (front); Utilities.DestroyObj (back); if (! tm.SplitSides) { // merge submeshes Utilities.MergeSubmeshes (mesh); //CombineInstance ci[] = new CombineInstance[mesh.subMeshCount]; //Mesh tmesh=new Mesh(); //mesh.CombineMeshes(true, false); } } ShaderMaps.ComputeUVs2 (mesh, ts.UvType, ts.NormalizeUV, ts.UvScaling, charmetadata); mesh.RecalculateNormals (); ShaderMaps.ComputeTangents (mesh); return mesh; }
// THIS FUNCTION BUILD INDIVIDUAL SUBOBJECTS FOR EACH OBJECT public static IEnumerable BuildSubtext (TTFTextInternal.LineLayout ll, LineSplitter split, int idx, Vector3 pos, TTFText tm) //out Bounds bounds, //out int num) { Vector3 adv = Vector3.zero; Bounds bounds = new Bounds (Vector3.zero, Vector3.zero); int num = 0; foreach (TTFTextInternal.LineLayout l in split(ll)) { //Debug.Log("ll=" + l.line + " pos=" + pos + " charpos0=" + l.charpositions[0] + " advlen=" + l.advance); GameObject go; // instantiate the letter bool b0 = ((l.line.Length > 0) && (l.GetCharStyle (0).GlyphPrefab != null)); if (b0 || (tm.GlyphPrefab != null)) { if (b0) { go = GameObject.Instantiate (l.GetCharStyle (0).GlyphPrefab) as GameObject; } else { go = GameObject.Instantiate (tm.GlyphPrefab) as GameObject; } } else { go = new GameObject (); go.AddComponent<MeshFilter> (); go.AddComponent<MeshRenderer> (); if (tm.gameObject.renderer != null) { if (tm.gameObject.renderer.sharedMaterials != null) { if ((tm.gameObject.renderer.sharedMaterials.Length != 0) && (tm.gameObject.renderer.sharedMaterials [0] != null)) { go.renderer.sharedMaterials = tm.gameObject.renderer.sharedMaterials; } } else { if (tm.gameObject.renderer.sharedMaterial != null) { go.renderer.sharedMaterial = tm.gameObject.renderer.sharedMaterial; } } } } // --------------------------------------------------------------------- // set up the letter/text positon and scale // --------------------------------------------------------------------- int no = idx + num; go.name = System.String.Format ("{0}. {1}", no, l.line); go.transform.parent = tm.transform; if (/*tm.rebuildLayout ||*/ (!tm.SaveTokenPos) || tm.TokenPos.Count <= no) { go.transform.localPosition = pos; go.transform.localRotation = Quaternion.identity; } else { TTFText.TrInfo tr = tm.TokenPos [no]; go.transform.localPosition = tr.localPosition; go.transform.localRotation = tr.localRotation; go.transform.localScale = tr.localScale; } if (l.line.Length > 0) { if ((l.GetCharStyle (0).sharedMaterials != null) && (l.GetCharStyle (0).sharedMaterials.Length > 0) && (l.GetCharStyle (0).sharedMaterials [0] != null)) { go.renderer.sharedMaterials = l.GetCharStyle (0).sharedMaterials; } } // ---------------------------------------------------------- // build the mesh associated with letter/text // ---------------------------------------------------------- Mesh mesh = new Mesh (); TTFTextInternal.Engine.BuildMesh (ref mesh, l, tm, out adv); Bounds b = mesh.bounds; b.center = b.center + pos; TTFTextInternal.Utilities.MergeBounds (ref bounds, b); // -------------------------------------------------------------------------- // set up some metadata so that the script attached to the letters may update // -------------------------------------------------------------------------- #if TTFTEXT_LITE if (tm.DemoMode) { #endif TTFSubtext st = go.GetComponent<TTFSubtext> (); if (st == null) { st = go.AddComponent<TTFSubtext> (); } #if !TTFTEXT_LITE st.Layout = l; #endif st.Text = l.line; st.LineNo = l.lineno; st.SequenceNo = idx + num; st.Advance = adv; #if TTFTEXT_LITE } #endif // --------------------------------------------------------------------- // // IF A SPECIAL TEXTURE IS AFFECTED TO THIS CHARACTER THIS IS THE MOMENT // // --------------------------------------------------------------------- if (l.line.Length >= 1) { if (((l.charmetadata [0] as TextureElement) != null)) { TextureElement tel = (l.charmetadata [0] as TextureElement); Material m = tel.material; Material [] mx = new Material[1]; if (m == null) { //m=new Material(Shader.Find("GUI/Text Shader")); m = new Material (Shader.Find ("Self-Illumin/Diffuse")); m.name = "[generated material for text]"; m.mainTexture = tel.texture; } mx [0] = m; go.renderer.sharedMaterials = mx; TTFTextReleaseTempResources rmod = go.GetComponent<TTFTextReleaseTempResources> (); if (rmod == null) { rmod = go.AddComponent<TTFTextReleaseTempResources> (); } if ((tel.material == null) && (tel.shouldReleaseMaterial)) { rmod.material = m; } if (tel.shouldReleaseTexture) { rmod.texture = tel.texture; } } else { int cmo = l.GetCharStyle (0).MaterialOffset; if (cmo != 0) { //Debug.Log(cmo); if (go.renderer != null) { if (go.renderer.sharedMaterials != null) { int ml = go.renderer.sharedMaterials.Length; int tml = 1; if (l.GetCharStyle (0).SplitSides) { tml = 3; TTFText.ExtrusionModeEnum em = l.GetCharStyle (0).ExtrusionMode; if (em == TTFText.ExtrusionModeEnum.None) { tml = 1; if (l.GetCharStyle (0).BackFace) { tml += 1; } } if (em == TTFText.ExtrusionModeEnum.Pipe) { tml = 1; } } int mo = ((cmo % ml) + ml) % ml; Material [] omx = go.renderer.sharedMaterials; Material [] nmx = new Material[tml]; //Debug.Log(mo); for (int i=0; i<tml; i++) { nmx [i] = omx [(i + mo) % ml]; } go.renderer.sharedMaterial = nmx [0]; //go.renderer.sharedMaterials=new Material[0] {nmx[0]}; //go.renderer. go.renderer.sharedMaterials = nmx; } } } } } // // time to update every one // UpdateComponentsWithNewMesh (go, mesh); pos += l.advance; num++; yield return bounds; } }