unsafe string GetUrl(int index, int mouseX) { mouseX -= Textures[index].X1; DrawTextArgs args = default(DrawTextArgs); args.UseShadow = true; string text = lines[index]; if (game.ClassicMode) { return(null); } char * chars = stackalloc char[lines.Length * 96]; Portion *portions = stackalloc Portion[(96 / httpLen) * 2]; int portionsCount = Reduce(chars, index, portions); for (int i = 0, x = 0; i < portionsCount; i++) { Portion bit = portions[i]; args.Text = text.Substring(bit.LineBeg, bit.LineLen); args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont; int width = game.Drawer2D.MeasureText(ref args).Width; if (args.Font != font && mouseX >= x && mouseX < x + width) { string url = new string(chars, bit.Beg, bit.Len & 0x7FFF); // replace multiline bits return(Utils.StripColours(url).Replace("> ", "")); } x += width; } return(null); }
unsafe int Reduce(char *chars, int target, Portion *portions) { Portion *start = portions; int charsLen = 0; int * begs = stackalloc int[lines.Length]; int * ends = stackalloc int[lines.Length]; for (int i = 0; i < lines.Length; i++) { string line = lines[i]; begs[i] = -1; ends[i] = -1; if (line == null) { continue; } begs[i] = charsLen; for (int j = 0; j < line.Length; j++) { chars[charsLen + j] = line[j]; } charsLen += line.Length; ends[i] = charsLen; } int end = 0; Portion bit = default(Portion); for (;;) { int nextStart = NextUrl(chars, charsLen, end); // add normal portion between urls bit.Beg = end; bit.Len = nextStart - end; Output(bit, begs[target], ends[target], ref portions); if (nextStart == charsLen) { break; } end = UrlEnd(chars, charsLen, begs, nextStart); // add this url portion bit.Beg = nextStart; bit.Len = (end - nextStart) | 0x8000; Output(bit, begs[target], ends[target], ref portions); } return((int)(portions - start)); }
unsafe void Output(Portion bit, int lineBeg, int lineEnd, Portion *portions, ref int count) { if (bit.Beg >= lineEnd || bit.Len == 0) { return; } bit.LineBeg = bit.Beg; bit.LineLen = bit.Len & 0x7FFF; // Adjust this portion to be within this line if (bit.Beg >= lineBeg) { } else if (bit.Beg + bit.LineLen > lineBeg) { // Adjust start of portion to be within this line int underBy = lineBeg - bit.Beg; bit.LineBeg += underBy; bit.LineLen -= underBy; } else { return; } // Limit length of portion to be within this line int overBy = (bit.LineBeg + bit.LineLen) - lineEnd; if (overBy > 0) { bit.LineLen -= overBy; } bit.LineBeg -= lineBeg; if (bit.LineLen == 0) { return; } portions[count] = bit; count++; }
unsafe Texture DrawAdvanced(ref DrawTextArgs args, int index, string text) { char * chars = stackalloc char[lines.Length * 96]; Portion *portions = stackalloc Portion[(96 / httpLen) * 2]; int portionsCount = Reduce(chars, index, portions); Size total = Size.Empty; Size *partSizes = stackalloc Size[portionsCount]; for (int i = 0; i < portionsCount; i++) { Portion bit = portions[i]; args.Text = text.Substring(bit.LineBeg, bit.LineLen); args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont; partSizes[i] = game.Drawer2D.MeasureText(ref args); total.Height = Math.Max(partSizes[i].Height, total.Height); total.Width += partSizes[i].Width; } using (IDrawer2D drawer = game.Drawer2D) using (Bitmap bmp = IDrawer2D.CreatePow2Bitmap(total)) { drawer.SetBitmap(bmp); for (int i = 0, x = 0; i < portionsCount; i++) { Portion bit = portions[i]; args.Text = text.Substring(bit.LineBeg, bit.LineLen); args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont; drawer.DrawText(ref args, x, 0); x += partSizes[i].Width; } return(drawer.Make2DTexture(bmp, total, 0, 0)); } }