OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
VectorRenderModule.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Drawing;
30 using System.Drawing.Imaging;
31 using System.Globalization;
32 using System.IO;
33 using System.Linq;
34 using System.Net;
35 using Nini.Config;
36 using OpenMetaverse;
37 using OpenMetaverse.Imaging;
38 using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
39 using OpenSim.Region.Framework.Interfaces;
40 using OpenSim.Region.Framework.Scenes;
41 using log4net;
42 using System.Reflection;
43 using Mono.Addins;
44 
45 //using Cairo;
46 
47 namespace OpenSim.Region.CoreModules.Scripting.VectorRender
48 {
49  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "VectorRenderModule")]
51  {
52  // These fields exist for testing purposes, please do not remove.
53 // private static bool s_flipper;
54 // private static byte[] s_asset1Data;
55 // private static byte[] s_asset2Data;
56 
57  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 
59  private Scene m_scene;
60  private IDynamicTextureManager m_textureManager;
61 
62  private Graphics m_graph;
63  private string m_fontName = "Arial";
64 
66  {
67  }
68 
69  #region IDynamicTextureRender Members
70 
71  public string GetContentType()
72  {
73  return "vector";
74  }
75 
76  public string GetName()
77  {
78  return Name;
79  }
80 
81  public bool SupportsAsynchronous()
82  {
83  return true;
84  }
85 
86 // public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
87 // {
88 // string[] lines = GetLines(bodyData);
89 // return lines.Any((str, r) => str.StartsWith("Image"));
90 // }
91 
92  public IDynamicTexture ConvertUrl(string url, string extraParams)
93  {
94  return null;
95  }
96 
97  public IDynamicTexture ConvertData(string bodyData, string extraParams)
98  {
99  return Draw(bodyData, extraParams);
100  }
101 
102  public bool AsyncConvertUrl(UUID id, string url, string extraParams)
103  {
104  return false;
105  }
106 
107  public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
108  {
109  if (m_textureManager == null)
110  {
111  m_log.Warn("[VECTORRENDERMODULE]: No texture manager. Can't function");
112  return false;
113  }
114  // XXX: This isn't actually being done asynchronously!
115  m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams));
116 
117  return true;
118  }
119 
120  public void GetDrawStringSize(string text, string fontName, int fontSize,
121  out double xSize, out double ySize)
122  {
123  lock (this)
124  {
125  using (Font myFont = new Font(fontName, fontSize))
126  {
127  SizeF stringSize = new SizeF();
128 
129  // XXX: This lock may be unnecessary.
130  lock (m_graph)
131  {
132  stringSize = m_graph.MeasureString(text, myFont);
133  xSize = stringSize.Width;
134  ySize = stringSize.Height;
135  }
136  }
137  }
138  }
139 
140  #endregion
141 
142  #region ISharedRegionModule Members
143 
144  public void Initialise(IConfigSource config)
145  {
146  IConfig cfg = config.Configs["VectorRender"];
147  if (null != cfg)
148  {
149  m_fontName = cfg.GetString("font_name", m_fontName);
150  }
151  m_log.DebugFormat("[VECTORRENDERMODULE]: using font \"{0}\" for text rendering.", m_fontName);
152 
153  // We won't dispose of these explicitly since this module is only removed when the entire simulator
154  // is shut down.
155  Bitmap bitmap = new Bitmap(1024, 1024, PixelFormat.Format32bppArgb);
156  m_graph = Graphics.FromImage(bitmap);
157  }
158 
159  public void PostInitialise()
160  {
161  }
162 
163  public void AddRegion(Scene scene)
164  {
165  if (m_scene == null)
166  {
167  m_scene = scene;
168  }
169  }
170 
171  public void RegionLoaded(Scene scene)
172  {
173  if (m_textureManager == null && m_scene == scene)
174  {
175  m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>();
176  if (m_textureManager != null)
177  {
178  m_textureManager.RegisterRender(GetContentType(), this);
179  }
180  }
181  }
182 
183  public void RemoveRegion(Scene scene)
184  {
185  }
186 
187  public void Close()
188  {
189  }
190 
191  public string Name
192  {
193  get { return "VectorRenderModule"; }
194  }
195 
196  public Type ReplaceableInterface
197  {
198  get { return null; }
199  }
200 
201  #endregion
202 
203  private IDynamicTexture Draw(string data, string extraParams)
204  {
205  // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
206  // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
207  int width = 256;
208  int height = 256;
209  int alpha = 255; // 0 is transparent
210  Color bgColor = Color.White; // Default background color
211  char altDataDelim = ';';
212 
213  char[] paramDelimiter = { ',' };
214  char[] nvpDelimiter = { ':' };
215 
216  extraParams = extraParams.Trim();
217  extraParams = extraParams.ToLower();
218 
219  string[] nvps = extraParams.Split(paramDelimiter);
220 
221  int temp = -1;
222  foreach (string pair in nvps)
223  {
224  string[] nvp = pair.Split(nvpDelimiter);
225  string name = "";
226  string value = "";
227 
228  if (nvp[0] != null)
229  {
230  name = nvp[0].Trim();
231  }
232 
233  if (nvp.Length == 2)
234  {
235  value = nvp[1].Trim();
236  }
237 
238  switch (name)
239  {
240  case "width":
241  temp = parseIntParam(value);
242  if (temp != -1)
243  {
244  if (temp < 1)
245  {
246  width = 1;
247  }
248  else if (temp > 2048)
249  {
250  width = 2048;
251  }
252  else
253  {
254  width = temp;
255  }
256  }
257  break;
258  case "height":
259  temp = parseIntParam(value);
260  if (temp != -1)
261  {
262  if (temp < 1)
263  {
264  height = 1;
265  }
266  else if (temp > 2048)
267  {
268  height = 2048;
269  }
270  else
271  {
272  height = temp;
273  }
274  }
275  break;
276  case "alpha":
277  temp = parseIntParam(value);
278  if (temp != -1)
279  {
280  if (temp < 0)
281  {
282  alpha = 0;
283  }
284  else if (temp > 255)
285  {
286  alpha = 255;
287  }
288  else
289  {
290  alpha = temp;
291  }
292  }
293  // Allow a bitmap w/o the alpha component to be created
294  else if (value.ToLower() == "false") {
295  alpha = 256;
296  }
297  break;
298  case "bgcolor":
299  case "bgcolour":
300  int hex = 0;
301  if (Int32.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex))
302  {
303  bgColor = Color.FromArgb(hex);
304  }
305  else
306  {
307  bgColor = Color.FromName(value);
308  }
309  break;
310  case "altdatadelim":
311  altDataDelim = value.ToCharArray()[0];
312  break;
313  case "":
314  // blank string has been passed do nothing just use defaults
315  break;
316  default: // this is all for backwards compat, all a bit ugly hopfully can be removed in future
317  // could be either set alpha or just an int
318  if (name == "setalpha")
319  {
320  alpha = 0; // set the texture to have transparent background (maintains backwards compat)
321  }
322  else
323  {
324  // this function used to accept an int on its own that represented both
325  // width and height, this is to maintain backwards compat, could be removed
326  // but would break existing scripts
327  temp = parseIntParam(name);
328  if (temp != -1)
329  {
330  if (temp > 1024)
331  temp = 1024;
332 
333  if (temp < 128)
334  temp = 128;
335 
336  width = temp;
337  height = temp;
338  }
339  }
340  break;
341  }
342  }
343 
344  Bitmap bitmap = null;
345  Graphics graph = null;
346  bool reuseable = false;
347 
348  try
349  {
350  // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
351  // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
352  // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
353  // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
354  // under lock.
355  lock (this)
356  {
357  if (alpha == 256)
358  bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
359  else
360  bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
361 
362  graph = Graphics.FromImage(bitmap);
363 
364  // this is really just to save people filling the
365  // background color in their scripts, only do when fully opaque
366  if (alpha >= 255)
367  {
368  using (SolidBrush bgFillBrush = new SolidBrush(bgColor))
369  {
370  graph.FillRectangle(bgFillBrush, 0, 0, width, height);
371  }
372  }
373 
374  for (int w = 0; w < bitmap.Width; w++)
375  {
376  if (alpha <= 255)
377  {
378  for (int h = 0; h < bitmap.Height; h++)
379  {
380  bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h)));
381  }
382  }
383  }
384 
385  GDIDraw(data, graph, altDataDelim, out reuseable);
386  }
387 
388  byte[] imageJ2000 = new byte[0];
389 
390  // This code exists for testing purposes, please do not remove.
391 // if (s_flipper)
392 // imageJ2000 = s_asset1Data;
393 // else
394 // imageJ2000 = s_asset2Data;
395 //
396 // s_flipper = !s_flipper;
397 
398  try
399  {
400  imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true);
401  }
402  catch (Exception e)
403  {
404  m_log.ErrorFormat(
405  "[VECTORRENDERMODULE]: OpenJpeg Encode Failed. Exception {0}{1}",
406  e.Message, e.StackTrace);
407  }
408 
410  data, extraParams, imageJ2000, new Size(width, height), reuseable);
411  }
412  finally
413  {
414  // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
415  // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
416  // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
417  // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
418  // under lock.
419  lock (this)
420  {
421  if (graph != null)
422  graph.Dispose();
423 
424  if (bitmap != null)
425  bitmap.Dispose();
426  }
427  }
428  }
429 
430  private int parseIntParam(string strInt)
431  {
432  int parsed;
433  try
434  {
435  parsed = Convert.ToInt32(strInt);
436  }
437  catch (Exception)
438  {
439  //Ckrinke: Add a WriteLine to remove the warning about 'e' defined but not used
440  // m_log.Debug("Problem with Draw. Please verify parameters." + e.ToString());
441  parsed = -1;
442  }
443 
444  return parsed;
445  }
446 
447 /*
448  private void CairoDraw(string data, System.Drawing.Graphics graph)
449  {
450  using (Win32Surface draw = new Win32Surface(graph.GetHdc()))
451  {
452  Context contex = new Context(draw);
453 
454  contex.Antialias = Antialias.None; //fastest method but low quality
455  contex.LineWidth = 7;
456  char[] lineDelimiter = { ';' };
457  char[] partsDelimiter = { ',' };
458  string[] lines = data.Split(lineDelimiter);
459 
460  foreach (string line in lines)
461  {
462  string nextLine = line.Trim();
463 
464  if (nextLine.StartsWith("MoveTO"))
465  {
466  float x = 0;
467  float y = 0;
468  GetParams(partsDelimiter, ref nextLine, ref x, ref y);
469  contex.MoveTo(x, y);
470  }
471  else if (nextLine.StartsWith("LineTo"))
472  {
473  float x = 0;
474  float y = 0;
475  GetParams(partsDelimiter, ref nextLine, ref x, ref y);
476  contex.LineTo(x, y);
477  contex.Stroke();
478  }
479  }
480  }
481  graph.ReleaseHdc();
482  }
483 */
484 
491  private string[] GetLines(string data, char dataDelim)
492  {
493  char[] lineDelimiter = { dataDelim };
494  return data.Split(lineDelimiter);
495  }
496 
497  private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable)
498  {
499  reuseable = true;
500  Point startPoint = new Point(0, 0);
501  Point endPoint = new Point(0, 0);
502  Pen drawPen = null;
503  Font myFont = null;
504  SolidBrush myBrush = null;
505 
506  try
507  {
508  drawPen = new Pen(Color.Black, 7);
509  string fontName = m_fontName;
510  float fontSize = 14;
511  myFont = new Font(fontName, fontSize);
512  myBrush = new SolidBrush(Color.Black);
513 
514  char[] partsDelimiter = {','};
515 
516  foreach (string line in GetLines(data, dataDelim))
517  {
518  string nextLine = line.Trim();
519 
520 // m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
521 
522  //replace with switch, or even better, do some proper parsing
523  if (nextLine.StartsWith("MoveTo"))
524  {
525  float x = 0;
526  float y = 0;
527  GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y);
528  startPoint.X = (int) x;
529  startPoint.Y = (int) y;
530  }
531  else if (nextLine.StartsWith("LineTo"))
532  {
533  float x = 0;
534  float y = 0;
535  GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y);
536  endPoint.X = (int) x;
537  endPoint.Y = (int) y;
538  graph.DrawLine(drawPen, startPoint, endPoint);
539  startPoint.X = endPoint.X;
540  startPoint.Y = endPoint.Y;
541  }
542  else if (nextLine.StartsWith("Text"))
543  {
544  nextLine = nextLine.Remove(0, 4);
545  nextLine = nextLine.Trim();
546  graph.DrawString(nextLine, myFont, myBrush, startPoint);
547  }
548  else if (nextLine.StartsWith("Image"))
549  {
550  // We cannot reuse any generated texture involving fetching an image via HTTP since that image
551  // can change.
552  reuseable = false;
553 
554  float x = 0;
555  float y = 0;
556  GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);
557  endPoint.X = (int) x;
558  endPoint.Y = (int) y;
559 
560  using (Image image = ImageHttpRequest(nextLine))
561  {
562  if (image != null)
563  {
564  graph.DrawImage(image, (float)startPoint.X, (float)startPoint.Y, x, y);
565  }
566  else
567  {
568  using (Font errorFont = new Font(m_fontName,6))
569  {
570  graph.DrawString("URL couldn't be resolved or is", errorFont,
571  myBrush, startPoint);
572  graph.DrawString("not an image. Please check URL.", errorFont,
573  myBrush, new Point(startPoint.X, 12 + startPoint.Y));
574  }
575 
576  graph.DrawRectangle(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
577  }
578  }
579 
580  startPoint.X += endPoint.X;
581  startPoint.Y += endPoint.Y;
582  }
583  else if (nextLine.StartsWith("Rectangle"))
584  {
585  float x = 0;
586  float y = 0;
587  GetParams(partsDelimiter, ref nextLine, 9, ref x, ref y);
588  endPoint.X = (int) x;
589  endPoint.Y = (int) y;
590  graph.DrawRectangle(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
591  startPoint.X += endPoint.X;
592  startPoint.Y += endPoint.Y;
593  }
594  else if (nextLine.StartsWith("FillRectangle"))
595  {
596  float x = 0;
597  float y = 0;
598  GetParams(partsDelimiter, ref nextLine, 13, ref x, ref y);
599  endPoint.X = (int) x;
600  endPoint.Y = (int) y;
601  graph.FillRectangle(myBrush, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
602  startPoint.X += endPoint.X;
603  startPoint.Y += endPoint.Y;
604  }
605  else if (nextLine.StartsWith("FillPolygon"))
606  {
607  PointF[] points = null;
608  GetParams(partsDelimiter, ref nextLine, 11, ref points);
609  graph.FillPolygon(myBrush, points);
610  }
611  else if (nextLine.StartsWith("Polygon"))
612  {
613  PointF[] points = null;
614  GetParams(partsDelimiter, ref nextLine, 7, ref points);
615  graph.DrawPolygon(drawPen, points);
616  }
617  else if (nextLine.StartsWith("Ellipse"))
618  {
619  float x = 0;
620  float y = 0;
621  GetParams(partsDelimiter, ref nextLine, 7, ref x, ref y);
622  endPoint.X = (int)x;
623  endPoint.Y = (int)y;
624  graph.DrawEllipse(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
625  startPoint.X += endPoint.X;
626  startPoint.Y += endPoint.Y;
627  }
628  else if (nextLine.StartsWith("FontSize"))
629  {
630  nextLine = nextLine.Remove(0, 8);
631  nextLine = nextLine.Trim();
632  fontSize = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture);
633 
634  myFont.Dispose();
635  myFont = new Font(fontName, fontSize);
636  }
637  else if (nextLine.StartsWith("FontProp"))
638  {
639  nextLine = nextLine.Remove(0, 8);
640  nextLine = nextLine.Trim();
641 
642  string[] fprops = nextLine.Split(partsDelimiter);
643  foreach (string prop in fprops)
644  {
645 
646  switch (prop)
647  {
648  case "B":
649  if (!(myFont.Bold))
650  {
651  Font newFont = new Font(myFont, myFont.Style | FontStyle.Bold);
652  myFont.Dispose();
653  myFont = newFont;
654  }
655  break;
656  case "I":
657  if (!(myFont.Italic))
658  {
659  Font newFont = new Font(myFont, myFont.Style | FontStyle.Italic);
660  myFont.Dispose();
661  myFont = newFont;
662  }
663  break;
664  case "U":
665  if (!(myFont.Underline))
666  {
667  Font newFont = new Font(myFont, myFont.Style | FontStyle.Underline);
668  myFont.Dispose();
669  myFont = newFont;
670  }
671  break;
672  case "S":
673  if (!(myFont.Strikeout))
674  {
675  Font newFont = new Font(myFont, myFont.Style | FontStyle.Strikeout);
676  myFont.Dispose();
677  myFont = newFont;
678  }
679  break;
680  case "R":
681  // We need to place this newFont inside its own context so that the .NET compiler
682  // doesn't complain about a redefinition of an existing newFont, even though there is none
683  // The mono compiler doesn't produce this error.
684  {
685  Font newFont = new Font(myFont, FontStyle.Regular);
686  myFont.Dispose();
687  myFont = newFont;
688  }
689  break;
690  }
691  }
692  }
693  else if (nextLine.StartsWith("FontName"))
694  {
695  nextLine = nextLine.Remove(0, 8);
696  fontName = nextLine.Trim();
697  myFont.Dispose();
698  myFont = new Font(fontName, fontSize);
699  }
700  else if (nextLine.StartsWith("PenSize"))
701  {
702  nextLine = nextLine.Remove(0, 7);
703  nextLine = nextLine.Trim();
704  float size = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture);
705  drawPen.Width = size;
706  }
707  else if (nextLine.StartsWith("PenCap"))
708  {
709  bool start = true, end = true;
710  nextLine = nextLine.Remove(0, 6);
711  nextLine = nextLine.Trim();
712  string[] cap = nextLine.Split(partsDelimiter);
713  if (cap[0].ToLower() == "start")
714  end = false;
715  else if (cap[0].ToLower() == "end")
716  start = false;
717  else if (cap[0].ToLower() != "both")
718  return;
719  string type = cap[1].ToLower();
720 
721  if (end)
722  {
723  switch (type)
724  {
725  case "arrow":
726  drawPen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
727  break;
728  case "round":
729  drawPen.EndCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
730  break;
731  case "diamond":
732  drawPen.EndCap = System.Drawing.Drawing2D.LineCap.DiamondAnchor;
733  break;
734  case "flat":
735  drawPen.EndCap = System.Drawing.Drawing2D.LineCap.Flat;
736  break;
737  }
738  }
739  if (start)
740  {
741  switch (type)
742  {
743  case "arrow":
744  drawPen.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
745  break;
746  case "round":
747  drawPen.StartCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
748  break;
749  case "diamond":
750  drawPen.StartCap = System.Drawing.Drawing2D.LineCap.DiamondAnchor;
751  break;
752  case "flat":
753  drawPen.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
754  break;
755  }
756  }
757  }
758  else if (nextLine.StartsWith("PenColour") || nextLine.StartsWith("PenColor"))
759  {
760  nextLine = nextLine.Remove(0, 9);
761  nextLine = nextLine.Trim();
762  int hex = 0;
763 
764  Color newColor;
765  if (Int32.TryParse(nextLine, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex))
766  {
767  newColor = Color.FromArgb(hex);
768  }
769  else
770  {
771  // this doesn't fail, it just returns black if nothing is found
772  newColor = Color.FromName(nextLine);
773  }
774 
775  myBrush.Color = newColor;
776  drawPen.Color = newColor;
777  }
778  }
779  }
780  finally
781  {
782  if (drawPen != null)
783  drawPen.Dispose();
784 
785  if (myFont != null)
786  myFont.Dispose();
787 
788  if (myBrush != null)
789  myBrush.Dispose();
790  }
791  }
792 
793  private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref float x, ref float y)
794  {
795  line = line.Remove(0, startLength);
796  string[] parts = line.Split(partsDelimiter);
797  if (parts.Length == 2)
798  {
799  string xVal = parts[0].Trim();
800  string yVal = parts[1].Trim();
801  x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture);
802  y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
803  }
804  else if (parts.Length > 2)
805  {
806  string xVal = parts[0].Trim();
807  string yVal = parts[1].Trim();
808  x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture);
809  y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
810 
811  line = "";
812  for (int i = 2; i < parts.Length; i++)
813  {
814  line = line + parts[i].Trim();
815  line = line + " ";
816  }
817  }
818  }
819 
820  private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref PointF[] points)
821  {
822  line = line.Remove(0, startLength);
823  string[] parts = line.Split(partsDelimiter);
824  if (parts.Length > 1 && parts.Length % 2 == 0)
825  {
826  points = new PointF[parts.Length / 2];
827  for (int i = 0; i < parts.Length; i = i + 2)
828  {
829  string xVal = parts[i].Trim();
830  string yVal = parts[i+1].Trim();
831  float x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture);
832  float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
833  PointF point = new PointF(x, y);
834  points[i / 2] = point;
835 
836 // m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
837  }
838  }
839  }
840 
841  private Bitmap ImageHttpRequest(string url)
842  {
843  try
844  {
845  WebRequest request = HttpWebRequest.Create(url);
846 
847  using (HttpWebResponse response = (HttpWebResponse)(request).GetResponse())
848  {
849  if (response.StatusCode == HttpStatusCode.OK)
850  {
851  using (Stream s = response.GetResponseStream())
852  {
853  Bitmap image = new Bitmap(s);
854  return image;
855  }
856  }
857  }
858  }
859  catch { }
860 
861  return null;
862  }
863  }
864 }
bool AsyncConvertUrl(UUID id, string url, string extraParams)
IDynamicTexture ConvertData(string bodyData, string extraParams)
void GetDrawStringSize(string text, string fontName, int fontSize, out double xSize, out double ySize)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool AsyncConvertData(UUID id, string bodyData, string extraParams)
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
IDynamicTexture ConvertUrl(string url, string extraParams)