static ContextReflection getContextReflection(Type t) { if (contextTypes.TryGetValue(t, out var r)) { return(r); } r = new ContextReflection(t); contextTypes.Add(t, r); return(r); }
/// <summary>Compile all glyphs of the font into .NET codez</summary> static TDelegate compile <TDelegate>(int atlasLayersCount, IEnumerable <Font.GlyphData> glyphs, Type tContext, byte paddingPixel, uint paddingUV) where TDelegate : Delegate { // If needed, create moar layer index constants while (atlasLayersCount > layerConstants.Count) { byte layer = (byte)layerConstants.Count; layerConstants.Add(Expression.Constant(layer, typeof(byte))); } ContextReflection reflection = getContextReflection(tContext); // Build sorted map of these case expressions map.Clear(); foreach (Font.GlyphData glyph in glyphs) { buildGlyph(ref reflection, glyph, paddingPixel, paddingUV); } // Add end of string switch-case, which tests for UINT_MAX and returns map.Add(uint.MaxValue, endOfStringCase); // Implement body of the loop loopBody.Clear(); loopBody.Add(decodeCharacter); loopBody.Add(Expression.Switch(utf32, map.Values.ToArray())); loopBody.Add(switchBreakLabel); // Implement body of the function functionBody.Clear(); functionBody.Add(createDecoder); functionBody.Add(Expression.Loop(Expression.Block(loopBody))); functionBody.Add(returnLabel); // Gather delegate parameters into a list parameters.Clear(); parameters.Add(reflection.paramExpression); parameters.Add(paramString); // Finally, compile all that stuff into CIL. JIT compiler will do the rest. var lambda = Expression.Lambda <TDelegate>(Expression.Block(localVariables, functionBody), parameters); TDelegate result = lambda.Compile(); // Cleanup temporary stuff. Hopefully, all these no longer needed objects will be garbage collected right away, while still at generation 0. map.Clear(); loopBody.Clear(); functionBody.Clear(); parameters.Clear(); return(result); }
// Build SwitchCase expression for one UTF32 character static void buildGlyph(ref ContextReflection reflection, Font.GlyphData glyph, byte paddingPixel, uint paddingUV) { if (glyph.utf32 == '\n' && null != reflection.miNewLine) { addSwitchCase('\n', reflection.paramExpression, reflection.miNewLine); return; } if (glyph.utf32 == '\t' && null != reflection.miTab) { addSwitchCase('\t', reflection.paramExpression, reflection.miTab); return; } Expression advance = Expression.Constant(glyph.data.advance); Expression lsbDelta = Expression.Constant(glyph.data.lsbDelta); Expression rsbDelta = Expression.Constant(glyph.data.rsbDelta); if (glyph.utf32 == nbsp && null != reflection.miNbsp) { addSwitchCase(nbsp, reflection.paramExpression, reflection.miNbsp, advance, lsbDelta, rsbDelta); return; } if (glyph.data.hasSprite) { // The glyph has a bitmap on the atlas short left = glyph.data.left; short top = glyph.data.top; left -= paddingPixel; top -= paddingPixel; CSize size = glyph.sprite.size; size.cx += 2 * paddingPixel; size.cy += 2 * paddingPixel; Expression spriteLeft = Expression.Constant(left, typeof(short)); Expression spriteTop = Expression.Constant(top, typeof(short)); Expression sx = Expression.Constant((ushort)size.cx, typeof(ushort)); Expression sy = Expression.Constant((ushort)size.cy, typeof(ushort)); ulong uv = glyph.sprite.uv; uint uvTL = (uint)(uv & uint.MaxValue); uint uvBR = (uint)(uv >> 32); uvTL -= paddingUV; uvBR += paddingUV; Expression uvTopLeft = Expression.Constant(uvTL, typeof(uint)); Expression uvBottomRight = Expression.Constant(uvBR, typeof(uint)); Expression layer = layerConstants[glyph.sprite.layer]; addSwitchCase(glyph.utf32, reflection.paramExpression, reflection.miEmit, advance, lsbDelta, rsbDelta, spriteLeft, spriteTop, sx, sy, uvTopLeft, uvBottomRight, layer); return; } // The glyph does not have a bitmap. The most likely reason for that, it's a space character. addSwitchCase(glyph.utf32, reflection.paramExpression, reflection.miSkip, advance, lsbDelta, rsbDelta); }