OSDN Git Service

affad93ceb467ef4a84dc1ea7204fd7d88467bd6
[radegast/radegast.git] / Radegast / GUI / Rendering / Rendering.cs
1 // \r
2 // Radegast Metaverse Client\r
3 // Copyright (c) 2009-2011, Radegast Development Team\r
4 // All rights reserved.\r
5 // \r
6 // Redistribution and use in source and binary forms, with or without\r
7 // modification, are permitted provided that the following conditions are met:\r
8 // \r
9 //     * Redistributions of source code must retain the above copyright notice,\r
10 //       this list of conditions and the following disclaimer.\r
11 //     * Redistributions in binary form must reproduce the above copyright\r
12 //       notice, this list of conditions and the following disclaimer in the\r
13 //       documentation and/or other materials provided with the distribution.\r
14 //     * Neither the name of the application "Radegast", nor the names of its\r
15 //       contributors may be used to endorse or promote products derived from\r
16 //       this software without specific prior written permission.\r
17 // \r
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 //\r
29 // $Id$\r
30 //\r
31 \r
32 #region Usings\r
33 using System;\r
34 using System.Collections.Generic;\r
35 using System.Drawing;\r
36 using System.Drawing.Imaging;\r
37 using System.IO;\r
38 using System.Windows.Forms;\r
39 using System.Text;\r
40 using System.Threading;\r
41 using System.Linq;\r
42 using OpenTK.Graphics.OpenGL;\r
43 using OpenMetaverse;\r
44 using OpenMetaverse.Rendering;\r
45 using OpenMetaverse.Assets;\r
46 using OpenMetaverse.Imaging;\r
47 using OpenMetaverse.StructuredData;\r
48 #endregion Usings\r
49 \r
50 namespace Radegast\r
51 {\r
52 \r
53     public partial class SceneWindow : RadegastForm\r
54     {\r
55         #region Public fields\r
56         /// <summary>\r
57         /// The OpenGL surface\r
58         /// </summary>\r
59         public OpenTK.GLControl glControl = null;\r
60 \r
61         /// <summary>\r
62         /// Use multi sampling (anti aliasing)\r
63         /// </summary>\r
64         public bool UseMultiSampling = true;\r
65 \r
66         /// <summary>\r
67         /// Is rendering engine ready and enabled\r
68         /// </summary>\r
69         public bool RenderingEnabled = false;\r
70 \r
71         /// <summary>\r
72         /// Rednder in wireframe mode\r
73         /// </summary>\r
74         public bool Wireframe = false;\r
75 \r
76         /// <summary>\r
77         /// List of prims in the scene\r
78         /// </summary>\r
79         Dictionary<uint, FacetedMesh> Prims = new Dictionary<uint, FacetedMesh>();\r
80 \r
81         #endregion Public fields\r
82 \r
83         #region Private fields\r
84 \r
85         Camera Camera;\r
86         Dictionary<UUID, TextureInfo> TexturesPtrMap = new Dictionary<UUID, TextureInfo>();\r
87         RadegastInstance instance;\r
88         MeshmerizerR renderer;\r
89         OpenTK.Graphics.GraphicsMode GLMode = null;\r
90         AutoResetEvent TextureThreadContextReady = new AutoResetEvent(false);\r
91         BlockingQueue<TextureLoadItem> PendingTextures = new BlockingQueue<TextureLoadItem>();\r
92         float[] lightPos = new float[] { 0f, 0f, 1f, 0f };\r
93         bool hasMipmap;\r
94 \r
95         #endregion Private fields\r
96 \r
97         #region Construction and disposal\r
98         public SceneWindow(RadegastInstance instance)\r
99             : base(instance)\r
100         {\r
101             InitializeComponent();\r
102             Disposed += new EventHandler(frmPrimWorkshop_Disposed);\r
103             AutoSavePosition = true;\r
104             UseMultiSampling = cbAA.Checked = instance.GlobalSettings["use_multi_sampling"];\r
105             cbAA.CheckedChanged += cbAA_CheckedChanged;\r
106 \r
107             this.instance = instance;\r
108 \r
109             renderer = new MeshmerizerR();\r
110 \r
111             // Camera initial setting\r
112             Camera = new Camera();\r
113             InitCamera();\r
114 \r
115             Client.Objects.TerseObjectUpdate += new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);\r
116             Client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);\r
117             Client.Objects.ObjectDataBlockUpdate += new EventHandler<ObjectDataBlockUpdateEventArgs>(Objects_ObjectDataBlockUpdate);\r
118             Client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);\r
119             Client.Network.SimChanged += new EventHandler<SimChangedEventArgs>(Network_SimChanged);\r
120             Client.Self.TeleportProgress += new EventHandler<TeleportEventArgs>(Self_TeleportProgress);\r
121             Instance.Netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(Netcom_ClientDisconnected);\r
122             Application.Idle += new EventHandler(Application_Idle);\r
123         }\r
124 \r
125         void frmPrimWorkshop_Disposed(object sender, EventArgs e)\r
126         {\r
127             Application.Idle -= new EventHandler(Application_Idle);\r
128             Client.Objects.TerseObjectUpdate -= new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);\r
129             Client.Objects.ObjectUpdate -= new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);\r
130             Client.Objects.ObjectDataBlockUpdate -= new EventHandler<ObjectDataBlockUpdateEventArgs>(Objects_ObjectDataBlockUpdate);\r
131             Client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);\r
132             Client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);\r
133             Client.Self.TeleportProgress -= new EventHandler<TeleportEventArgs>(Self_TeleportProgress);\r
134             Instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_ClientDisconnected);\r
135 \r
136             if (glControl != null)\r
137             {\r
138                 glControl.Dispose();\r
139             }\r
140             glControl = null;\r
141             lock (Prims) Prims.Clear();\r
142             TexturesPtrMap.Clear();\r
143             GC.Collect();\r
144         }\r
145 \r
146         void Application_Idle(object sender, EventArgs e)\r
147         {\r
148             if (glControl != null && !glControl.IsDisposed && RenderingEnabled)\r
149             {\r
150                 while (glControl.IsIdle)\r
151                 {\r
152                     MainRenderLoop();\r
153                 }\r
154             }\r
155         }\r
156         #endregion Construction and disposal\r
157 \r
158         #region Network messaage handlers\r
159         void Netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)\r
160         {\r
161             if (InvokeRequired)\r
162             {\r
163                 if (IsHandleCreated || !instance.MonoRuntime)\r
164                 {\r
165                     BeginInvoke(new MethodInvoker(() => Netcom_ClientDisconnected(sender, e)));\r
166                 }\r
167                 return;\r
168             }\r
169 \r
170             Dispose();\r
171         }\r
172 \r
173         void Self_TeleportProgress(object sender, TeleportEventArgs e)\r
174         {\r
175             switch (e.Status)\r
176             {\r
177                 case TeleportStatus.Progress:\r
178                 case TeleportStatus.Start:\r
179                     RenderingEnabled = false;\r
180                     break;\r
181 \r
182                 case TeleportStatus.Cancelled:\r
183                 case TeleportStatus.Failed:\r
184                     RenderingEnabled = true;\r
185                     break;\r
186 \r
187                 case TeleportStatus.Finished:\r
188                     ThreadPool.QueueUserWorkItem(sync =>\r
189                     {\r
190                         Thread.Sleep(3000);\r
191                         InitCamera();\r
192                         LoadCurrentPrims();\r
193                         RenderingEnabled = true;\r
194                     });\r
195                     break;\r
196             }\r
197         }\r
198 \r
199         void Network_SimChanged(object sender, SimChangedEventArgs e)\r
200         {\r
201             lock (Prims) Prims.Clear();\r
202         }\r
203 \r
204         void Objects_KillObject(object sender, KillObjectEventArgs e)\r
205         {\r
206             if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;\r
207             lock (Prims) Prims.Remove(e.ObjectLocalID);\r
208         }\r
209 \r
210         void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e)\r
211         {\r
212             if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;\r
213             UpdatePrimBlocking(e.Prim);\r
214         }\r
215 \r
216         void Objects_ObjectUpdate(object sender, PrimEventArgs e)\r
217         {\r
218             if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;\r
219             UpdatePrimBlocking(e.Prim);\r
220         }\r
221 \r
222         void Objects_ObjectDataBlockUpdate(object sender, ObjectDataBlockUpdateEventArgs e)\r
223         {\r
224             if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;\r
225             UpdatePrimBlocking(e.Prim);\r
226         }\r
227         #endregion Network messaage handlers\r
228 \r
229         #region glControl setup and disposal\r
230         public void SetupGLControl()\r
231         {\r
232             RenderingEnabled = false;\r
233 \r
234             if (glControl != null)\r
235                 glControl.Dispose();\r
236             glControl = null;\r
237 \r
238             GLMode = null;\r
239 \r
240             try\r
241             {\r
242                 if (!UseMultiSampling)\r
243                 {\r
244                     GLMode = new OpenTK.Graphics.GraphicsMode(OpenTK.DisplayDevice.Default.BitsPerPixel, 24, 8, 0);\r
245                 }\r
246                 else\r
247                 {\r
248                     for (int aa = 0; aa <= 4; aa += 2)\r
249                     {\r
250                         var testMode = new OpenTK.Graphics.GraphicsMode(OpenTK.DisplayDevice.Default.BitsPerPixel, 24, 8, aa);\r
251                         if (testMode.Samples == aa)\r
252                         {\r
253                             GLMode = testMode;\r
254                         }\r
255                     }\r
256                 }\r
257             }\r
258             catch\r
259             {\r
260                 GLMode = null;\r
261             }\r
262 \r
263 \r
264             try\r
265             {\r
266                 if (GLMode == null)\r
267                 {\r
268                     // Try default mode\r
269                     glControl = new OpenTK.GLControl();\r
270                 }\r
271                 else\r
272                 {\r
273                     glControl = new OpenTK.GLControl(GLMode);\r
274                 }\r
275             }\r
276             catch (Exception ex)\r
277             {\r
278                 Logger.Log(ex.Message, Helpers.LogLevel.Warning, Client);\r
279                 glControl = null;\r
280             }\r
281 \r
282             if (glControl == null)\r
283             {\r
284                 Logger.Log("Failed to initialize OpenGL control, cannot continue", Helpers.LogLevel.Error, Client);\r
285                 return;\r
286             }\r
287 \r
288             Logger.Log("Initializing OpenGL mode: " + GLMode.ToString(), Helpers.LogLevel.Info);\r
289 \r
290             glControl.Paint += glControl_Paint;\r
291             glControl.Resize += glControl_Resize;\r
292             glControl.MouseDown += glControl_MouseDown;\r
293             glControl.MouseUp += glControl_MouseUp;\r
294             glControl.MouseMove += glControl_MouseMove;\r
295             glControl.MouseWheel += glControl_MouseWheel;\r
296             glControl.Load += new EventHandler(glControl_Load);\r
297             glControl.Disposed += new EventHandler(glControl_Disposed);\r
298             glControl.Dock = DockStyle.Fill;\r
299             Controls.Add(glControl);\r
300             glControl.BringToFront();\r
301         }\r
302 \r
303         void glControl_Disposed(object sender, EventArgs e)\r
304         {\r
305             TextureThreadRunning = false;\r
306             PendingTextures.Close();\r
307             glControl.Paint -= glControl_Paint;\r
308             glControl.Resize -= glControl_Resize;\r
309             glControl.MouseDown -= glControl_MouseDown;\r
310             glControl.MouseUp -= glControl_MouseUp;\r
311             glControl.MouseMove -= glControl_MouseMove;\r
312             glControl.MouseWheel -= glControl_MouseWheel;\r
313             glControl.Load -= new EventHandler(glControl_Load);\r
314             glControl.Disposed -= glControl_Disposed;\r
315         }\r
316 \r
317         void glControl_Load(object sender, EventArgs e)\r
318         {\r
319             try\r
320             {\r
321                 GL.ShadeModel(ShadingModel.Smooth);\r
322                 GL.ClearColor(0f, 0f, 0f, 0f);\r
323 \r
324                 //GL.LightModel(LightModelParameter.LightModelAmbient, new float[] { 0.5f, 0.5f, 0.5f, 1.0f });\r
325 \r
326                 GL.Enable(EnableCap.Lighting);\r
327                 GL.Enable(EnableCap.Light0);\r
328                 GL.Light(LightName.Light0, LightParameter.Ambient, new float[] { 0.5f, 0.5f, 0.5f, 1f });\r
329                 GL.Light(LightName.Light0, LightParameter.Diffuse, new float[] { 0.3f, 0.3f, 0.3f, 1f });\r
330                 GL.Light(LightName.Light0, LightParameter.Specular, new float[] { 0.8f, 0.8f, 0.8f, 1.0f });\r
331                 GL.Light(LightName.Light0, LightParameter.Position, lightPos);\r
332 \r
333                 GL.ClearDepth(1.0d);\r
334                 GL.Enable(EnableCap.DepthTest);\r
335                 GL.Enable(EnableCap.ColorMaterial);\r
336                 GL.Enable(EnableCap.CullFace);\r
337                 GL.ColorMaterial(MaterialFace.Front, ColorMaterialParameter.AmbientAndDiffuse);\r
338                 GL.ColorMaterial(MaterialFace.Front, ColorMaterialParameter.Specular);\r
339 \r
340                 GL.DepthMask(true);\r
341                 GL.DepthFunc(DepthFunction.Lequal);\r
342                 GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);\r
343                 GL.MatrixMode(MatrixMode.Projection);\r
344 \r
345                 GL.Enable(EnableCap.Blend);\r
346                 GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);\r
347                 hasMipmap = GL.GetString(StringName.Extensions).Contains("GL_SGIS_generate_mipmap");\r
348 \r
349                 RenderingEnabled = true;\r
350                 // Call the resizing function which sets up the GL drawing window\r
351                 // and will also invalidate the GL control\r
352                 glControl_Resize(null, null);\r
353 \r
354                 glControl.Context.MakeCurrent(null);\r
355                 TextureThreadContextReady.Reset();\r
356                 var textureThread = new Thread(() => TextureThread())\r
357                 {\r
358                     IsBackground = true,\r
359                     Name = "TextureLoadingThread"\r
360                 };\r
361                 textureThread.Start();\r
362                 TextureThreadContextReady.WaitOne(1000, false);\r
363                 glControl.MakeCurrent();\r
364             }\r
365             catch (Exception ex)\r
366             {\r
367                 RenderingEnabled = false;\r
368                 Logger.Log("Failed to initialize OpenGL control", Helpers.LogLevel.Warning, Client, ex);\r
369             }\r
370         }\r
371         #endregion glControl setup and disposal\r
372 \r
373         #region glControl paint and resize events\r
374         private void MainRenderLoop()\r
375         {\r
376             if (!RenderingEnabled) return;\r
377 \r
378             Render(false);\r
379 \r
380             glControl.SwapBuffers();\r
381         }\r
382 \r
383         void glControl_Paint(object sender, EventArgs e)\r
384         {\r
385             MainRenderLoop();\r
386         }\r
387 \r
388         private void glControl_Resize(object sender, EventArgs e)\r
389         {\r
390             if (!RenderingEnabled) return;\r
391             glControl.MakeCurrent();\r
392 \r
393             GL.ClearColor(0.39f, 0.58f, 0.93f, 1.0f);\r
394 \r
395             GL.Viewport(0, 0, glControl.Width, glControl.Height);\r
396 \r
397             GL.PushMatrix();\r
398             GL.MatrixMode(MatrixMode.Projection);\r
399             GL.LoadIdentity();\r
400 \r
401             SetPerspective();\r
402 \r
403             GL.MatrixMode(MatrixMode.Modelview);\r
404             GL.PopMatrix();\r
405         }\r
406         #endregion glControl paint and resize events\r
407 \r
408         #region Mouse handling\r
409         bool dragging = false;\r
410         int dragX, dragY, downX, downY;\r
411 \r
412         private void glControl_MouseWheel(object sender, MouseEventArgs e)\r
413         {\r
414             int newVal = Utils.Clamp(scrollZoom.Value + e.Delta / 10, scrollZoom.Minimum, scrollZoom.Maximum);\r
415 \r
416             if (scrollZoom.Value != newVal)\r
417             {\r
418                 Camera.Zoom = 1f - (float)newVal / (float)scrollZoom.Minimum;\r
419                 scrollZoom.Value = newVal;\r
420                 glControl_Resize(null, null);\r
421             }\r
422         }\r
423 \r
424         FacetedMesh RightclickedPrim;\r
425         int RightclickedFaceID;\r
426 \r
427         private void glControl_MouseDown(object sender, MouseEventArgs e)\r
428         {\r
429             if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Middle)\r
430             {\r
431                 dragging = true;\r
432                 downX = dragX = e.X;\r
433                 downY = dragY = e.Y;\r
434             }\r
435             else if (e.Button == MouseButtons.Right)\r
436             {\r
437                 if (TryPick(e.X, e.Y, out RightclickedPrim, out RightclickedFaceID))\r
438                 {\r
439                     ctxObjects.Show(glControl, e.X, e.Y);\r
440                 }\r
441             }\r
442 \r
443         }\r
444 \r
445         private void glControl_MouseMove(object sender, MouseEventArgs e)\r
446         {\r
447             if (dragging)\r
448             {\r
449                 int deltaX = e.X - dragX;\r
450                 int deltaY = e.Y - dragY;\r
451                 float pixelToM = 1f / 75f;\r
452 \r
453                 if (e.Button == MouseButtons.Left)\r
454                 {\r
455                     // Pan\r
456                     if (ModifierKeys == Keys.Control || ModifierKeys == (Keys.Alt | Keys.Control | Keys.Shift))\r
457                     {\r
458                         Vector3 direction = Camera.Position - Camera.FocalPoint;\r
459                         direction.Normalize();\r
460                         Vector3 vy = direction % new Vector3(0f, 0f, 1f);\r
461                         Vector3 vx = vy % direction;\r
462                         Vector3 vxy = vx * deltaY * pixelToM + vy * deltaX * pixelToM;\r
463                         Camera.Position += vxy;\r
464                         Camera.FocalPoint += vxy;\r
465                     }\r
466 \r
467                     // Alt-zoom (up down move camera closer to target, left right rotate around target)\r
468                     if (ModifierKeys == Keys.Alt)\r
469                     {\r
470                         Camera.Position += (Camera.Position - Camera.FocalPoint) * deltaY * pixelToM;\r
471                         var dx = -(deltaX * pixelToM);\r
472                         Camera.Position = Camera.FocalPoint + (Camera.Position - Camera.FocalPoint) * new Quaternion(0f, 0f, (float)Math.Sin(dx), (float)Math.Cos(dx));\r
473                     }\r
474 \r
475                     // Rotate camera in a vertical circle around target on up down mouse movement\r
476                     if (ModifierKeys == (Keys.Alt | Keys.Control))\r
477                     {\r
478                         Camera.Position = Camera.FocalPoint +\r
479                             (Camera.Position - Camera.FocalPoint)\r
480                             * Quaternion.CreateFromAxisAngle((Camera.Position - Camera.FocalPoint) % new Vector3(0f, 0f, 1f), deltaY * pixelToM);\r
481                         var dx = -(deltaX * pixelToM);\r
482                         Camera.Position = Camera.FocalPoint + (Camera.Position - Camera.FocalPoint) * new Quaternion(0f, 0f, (float)Math.Sin(dx), (float)Math.Cos(dx));\r
483                     }\r
484 \r
485                 }\r
486 \r
487                 dragX = e.X;\r
488                 dragY = e.Y;\r
489             }\r
490         }\r
491 \r
492         private void glControl_MouseUp(object sender, MouseEventArgs e)\r
493         {\r
494             if (e.Button == MouseButtons.Left)\r
495             {\r
496                 dragging = false;\r
497 \r
498                 if (e.X == downX && e.Y == downY) // click\r
499                 {\r
500                     FacetedMesh picked;\r
501                     int faceID;\r
502                     if (TryPick(e.X, e.Y, out picked, out faceID))\r
503                     {\r
504                         if (ModifierKeys == Keys.None)\r
505                         {\r
506                             Client.Self.Grab(picked.Prim.LocalID, Vector3.Zero, Vector3.Zero, Vector3.Zero, faceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);\r
507                             Client.Self.GrabUpdate(picked.Prim.ID, Vector3.Zero, Vector3.Zero, Vector3.Zero, Vector3.Zero, faceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);\r
508                             Client.Self.DeGrab(picked.Prim.LocalID);\r
509                         }\r
510                         else if (ModifierKeys == Keys.Alt)\r
511                         {\r
512                             Camera.FocalPoint = PrimPos(picked.Prim);\r
513                             UpdateCamera();\r
514                         }\r
515                     }\r
516                 }\r
517             }\r
518         }\r
519         #endregion Mouse handling\r
520 \r
521         #region Texture thread\r
522         bool TextureThreadRunning = true;\r
523 \r
524         void TextureThread()\r
525         {\r
526             OpenTK.INativeWindow window = new OpenTK.NativeWindow();\r
527             OpenTK.Graphics.IGraphicsContext context = new OpenTK.Graphics.GraphicsContext(GLMode, window.WindowInfo);\r
528             context.MakeCurrent(window.WindowInfo);\r
529             TextureThreadContextReady.Set();\r
530             PendingTextures.Open();\r
531             Logger.DebugLog("Started Texture Thread");\r
532 \r
533             while (window.Exists && TextureThreadRunning)\r
534             {\r
535                 window.ProcessEvents();\r
536 \r
537                 TextureLoadItem item = null;\r
538 \r
539                 if (!PendingTextures.Dequeue(Timeout.Infinite, ref item)) continue;\r
540 \r
541                 if (TexturesPtrMap.ContainsKey(item.TeFace.TextureID))\r
542                 {\r
543                     item.Data.TextureInfo = TexturesPtrMap[item.TeFace.TextureID];\r
544                     GL.BindTexture(TextureTarget.Texture2D, item.Data.TextureInfo.TexturePointer);\r
545                     continue;\r
546                 }\r
547 \r
548                 if (LoadTexture(item.TeFace.TextureID, ref item.Data.TextureInfo.Texture, false))\r
549                 {\r
550                     GL.GenTextures(1, out item.Data.TextureInfo.TexturePointer);\r
551                     GL.BindTexture(TextureTarget.Texture2D, item.Data.TextureInfo.TexturePointer);\r
552 \r
553                     Bitmap bitmap = (Bitmap)item.Data.TextureInfo.Texture;\r
554 \r
555                     bool hasAlpha;\r
556                     if (item.Data.TextureInfo.Texture.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb)\r
557                     {\r
558                         hasAlpha = true;\r
559                     }\r
560                     else\r
561                     {\r
562                         hasAlpha = false;\r
563                     }\r
564                     item.Data.TextureInfo.HasAlpha = hasAlpha;\r
565 \r
566                     bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r
567                     Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);\r
568 \r
569                     BitmapData bitmapData =\r
570                         bitmap.LockBits(\r
571                         rectangle,\r
572                         ImageLockMode.ReadOnly,\r
573                         hasAlpha ? System.Drawing.Imaging.PixelFormat.Format32bppArgb : System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r
574 \r
575                     GL.TexImage2D(\r
576                         TextureTarget.Texture2D,\r
577                         0,\r
578                         hasAlpha ? PixelInternalFormat.Rgba : PixelInternalFormat.Rgb8,\r
579                         bitmap.Width,\r
580                         bitmap.Height,\r
581                         0,\r
582                         hasAlpha ? OpenTK.Graphics.OpenGL.PixelFormat.Bgra : OpenTK.Graphics.OpenGL.PixelFormat.Bgr,\r
583                         PixelType.UnsignedByte,\r
584                         bitmapData.Scan0);\r
585 \r
586                     GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);\r
587                     GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);\r
588                     GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);\r
589                     if (hasMipmap)\r
590                     {\r
591                         GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);\r
592                         GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1);\r
593                         GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);\r
594                     }\r
595                     else\r
596                     {\r
597                         GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);\r
598                     }\r
599 \r
600                     TexturesPtrMap[item.TeFace.TextureID] = item.Data.TextureInfo;\r
601 \r
602                     bitmap.UnlockBits(bitmapData);\r
603                     bitmap.Dispose();\r
604                     item.Data.TextureInfo.Texture = null;\r
605 \r
606                     GL.Flush();\r
607                 }\r
608             }\r
609             Logger.DebugLog("Texture thread exited");\r
610         }\r
611         #endregion Texture thread\r
612 \r
613         void LoadCurrentPrims()\r
614         {\r
615             ThreadPool.QueueUserWorkItem(sync =>\r
616                 {\r
617                     Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive root) => root.ParentID == 0).ForEach((Primitive mainPrim) =>\r
618                     {\r
619                         UpdatePrimBlocking(Client.Network.CurrentSim.ObjectsPrimitives[mainPrim.LocalID]);\r
620                         Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive p) => { return p.ParentID == mainPrim.LocalID; })\r
621                             .FindAll((Primitive child) => child.ParentID == mainPrim.LocalID)\r
622                             .ForEach((Primitive subPrim) => UpdatePrimBlocking(subPrim));\r
623                     });\r
624                 }\r
625             );\r
626         }\r
627 \r
628         private void frmPrimWorkshop_Shown(object sender, EventArgs e)\r
629         {\r
630             SetupGLControl();\r
631             UpdateCamera();\r
632             LoadCurrentPrims();\r
633         }\r
634 \r
635         #region Private methods (the meat)\r
636         private void UpdateCamera()\r
637         {\r
638             if (Client != null)\r
639             {\r
640                 Client.Self.Movement.Camera.LookAt(Camera.Position, Camera.FocalPoint);\r
641                 //Client.Self.Movement.Camera.Far = (float)Camera.Far;\r
642             }\r
643 \r
644             if (RenderingEnabled)\r
645             {\r
646                 GL.PushMatrix();\r
647                 GL.MatrixMode(MatrixMode.Projection);\r
648                 GL.LoadIdentity();\r
649 \r
650                 SetPerspective();\r
651 \r
652                 GL.MatrixMode(MatrixMode.Modelview);\r
653                 GL.PopMatrix();\r
654             }\r
655         }\r
656 \r
657         void InitCamera()\r
658         {\r
659             Camera.Position = Client.Self.SimPosition + new Vector3(-2, 0, 0) * Client.Self.Movement.BodyRotation;\r
660             Camera.Position.Z += 2f;\r
661             Camera.FocalPoint = Client.Self.SimPosition + new Vector3(5, 0, 0) * Client.Self.Movement.BodyRotation;\r
662             Camera.Zoom = 1.0f;\r
663             Camera.Far = 128.0f;\r
664         }\r
665 \r
666         Vector3 PrimPos(Primitive prim)\r
667         {\r
668             if (prim.ParentID == 0)\r
669             {\r
670                 return prim.Position;\r
671             }\r
672             else\r
673             {\r
674                 Primitive parent;\r
675                 if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(prim.ParentID, out parent))\r
676                 {\r
677                     return parent.Position + prim.Position * Matrix4.CreateFromQuaternion(parent.Rotation);\r
678                     //return parent.Position * prim.Position * prim.Rotation;\r
679                 }\r
680                 else\r
681                 {\r
682                     return Vector3.Zero;\r
683                 }\r
684             }\r
685         }\r
686 \r
687         private void SetPerspective()\r
688         {\r
689             float dAspRat = (float)glControl.Width / (float)glControl.Height;\r
690             GluPerspective(50.0f * Camera.Zoom, dAspRat, 0.1f, (float)Camera.Far);\r
691         }\r
692 \r
693         private OpenTK.Vector3 WorldToScreen(OpenTK.Vector3 world)\r
694         {\r
695             OpenTK.Vector3 screen;\r
696             double[] ModelViewMatrix = new double[16];\r
697             double[] ProjectionMatrix = new double[16];\r
698             int[] Viewport = new int[4];\r
699 \r
700             GL.GetInteger(GetPName.Viewport, Viewport);\r
701             GL.GetDouble(GetPName.ModelviewMatrix, ModelViewMatrix);\r
702             GL.GetDouble(GetPName.ProjectionMatrix, ProjectionMatrix);\r
703 \r
704 #pragma warning disable 0618\r
705             OpenTK.Graphics.Glu.Project(world,\r
706                 ModelViewMatrix,\r
707                 ProjectionMatrix,\r
708                 Viewport,\r
709                 out screen);\r
710 #pragma warning restore 0618\r
711 \r
712             screen.Y = glControl.Height - screen.Y;\r
713             return screen;\r
714         }\r
715 \r
716 #pragma warning disable 0612\r
717         OpenTK.Graphics.TextPrinter Printer = new OpenTK.Graphics.TextPrinter(OpenTK.Graphics.TextQuality.High);\r
718 #pragma warning restore 0612\r
719         private void RenderText()\r
720         {\r
721             lock (Prims)\r
722             {\r
723                 int primNr = 0;\r
724                 foreach (FacetedMesh mesh in Prims.Values)\r
725                 {\r
726                     primNr++;\r
727                     Primitive prim = mesh.Prim;\r
728                     if (!string.IsNullOrEmpty(prim.Text))\r
729                     {\r
730                         string text = System.Text.RegularExpressions.Regex.Replace(prim.Text, "(\r?\n)+", "\n");\r
731                         OpenTK.Vector3 screenPos = OpenTK.Vector3.Zero;\r
732                         OpenTK.Vector3 primPos = OpenTK.Vector3.Zero;\r
733 \r
734                         // Is it child prim\r
735                         FacetedMesh parent = null;\r
736                         if (Prims.TryGetValue(prim.ParentID, out parent))\r
737                         {\r
738                             var newPrimPos = prim.Position * Matrix4.CreateFromQuaternion(parent.Prim.Rotation);\r
739                             primPos = new OpenTK.Vector3(newPrimPos.X, newPrimPos.Y, newPrimPos.Z);\r
740                         }\r
741 \r
742                         primPos.Z += prim.Scale.Z * 0.7f;\r
743                         screenPos = WorldToScreen(primPos);\r
744                         Printer.Begin();\r
745 \r
746                         Color color = Color.FromArgb((int)(prim.TextColor.A * 255), (int)(prim.TextColor.R * 255), (int)(prim.TextColor.G * 255), (int)(prim.TextColor.B * 255));\r
747 \r
748                         using (Font f = new Font(FontFamily.GenericSansSerif, 10f, FontStyle.Bold))\r
749                         {\r
750                             var size = Printer.Measure(text, f);\r
751                             screenPos.X -= size.BoundingBox.Width / 2;\r
752                             screenPos.Y -= size.BoundingBox.Height;\r
753 \r
754                             // Shadow\r
755                             if (color != Color.Black)\r
756                             {\r
757                                 Printer.Print(text, f, Color.Black, new RectangleF(screenPos.X + 1, screenPos.Y + 1, size.BoundingBox.Width, size.BoundingBox.Height), OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);\r
758                             }\r
759                             Printer.Print(text, f, color, new RectangleF(screenPos.X, screenPos.Y, size.BoundingBox.Width, size.BoundingBox.Height), OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);\r
760                         }\r
761                         Printer.End();\r
762                     }\r
763                 }\r
764             }\r
765         }\r
766 \r
767         private void RenderObjects(RenderPass pass)\r
768         {\r
769             lock (Prims)\r
770             {\r
771                 int primNr = 0;\r
772                 foreach (FacetedMesh mesh in Prims.Values)\r
773                 {\r
774                     primNr++;\r
775                     Primitive prim = mesh.Prim;\r
776                     Primitive parent = null;\r
777                     if (prim.ParentID != 0 && !Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(prim.ParentID, out parent)) continue;\r
778 \r
779                     // Individual prim matrix\r
780                     GL.PushMatrix();\r
781 \r
782                     if (prim.ParentID != 0)\r
783                     {\r
784                         // Apply prim translation and rotation relative to the root prim\r
785                         GL.MultMatrix(Math3D.CreateTranslationMatrix(parent.Position));\r
786                         GL.MultMatrix(Math3D.CreateRotationMatrix(parent.Rotation));\r
787                     }\r
788 \r
789                     // Prim roation and position\r
790                     GL.MultMatrix(Math3D.CreateTranslationMatrix(prim.Position));\r
791                     GL.MultMatrix(Math3D.CreateRotationMatrix(prim.Rotation));\r
792 \r
793                     // Prim scaling\r
794                     GL.Scale(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);\r
795 \r
796                     // Draw the prim faces\r
797                     for (int j = 0; j < mesh.Faces.Count; j++)\r
798                     {\r
799                         Primitive.TextureEntryFace teFace = mesh.Prim.Textures.FaceTextures[j];\r
800                         Face face = mesh.Faces[j];\r
801                         FaceData data = (FaceData)face.UserData;\r
802 \r
803                         if (teFace == null)\r
804                             teFace = mesh.Prim.Textures.DefaultTexture;\r
805 \r
806                         if (pass != RenderPass.Picking)\r
807                         {\r
808                             bool belongToAlphaPass = (teFace.RGBA.A < 0.99) || data.TextureInfo.HasAlpha;\r
809 \r
810                             if (belongToAlphaPass && pass != RenderPass.Alpha) continue;\r
811                             if (!belongToAlphaPass && pass == RenderPass.Alpha) continue;\r
812 \r
813                             // Don't render transparent faces\r
814                             if (teFace.RGBA.A <= 0.01f) continue;\r
815 \r
816                             switch (teFace.Shiny)\r
817                             {\r
818                                 case Shininess.High:\r
819                                     GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 94f);\r
820                                     break;\r
821 \r
822                                 case Shininess.Medium:\r
823                                     GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 64f);\r
824                                     break;\r
825 \r
826                                 case Shininess.Low:\r
827                                     GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 24f);\r
828                                     break;\r
829 \r
830 \r
831                                 case Shininess.None:\r
832                                 default:\r
833                                     GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0f);\r
834                                     break;\r
835                             }\r
836 \r
837                             var faceColor = new float[] { teFace.RGBA.R, teFace.RGBA.G, teFace.RGBA.B, teFace.RGBA.A };\r
838 \r
839                             GL.Color4(faceColor);\r
840                             GL.Material(MaterialFace.Front, MaterialParameter.AmbientAndDiffuse, faceColor);\r
841                             GL.Material(MaterialFace.Front, MaterialParameter.Specular, faceColor);\r
842 \r
843                             if (data.TextureInfo.TexturePointer != 0)\r
844                             {\r
845                                 GL.Enable(EnableCap.Texture2D);\r
846                             }\r
847                             else\r
848                             {\r
849                                 GL.Disable(EnableCap.Texture2D);\r
850                             }\r
851 \r
852                             // Bind the texture\r
853                             GL.BindTexture(TextureTarget.Texture2D, data.TextureInfo.TexturePointer);\r
854                         }\r
855                         else\r
856                         {\r
857                             data.PickingID = primNr;\r
858                             var primNrBytes = Utils.Int16ToBytes((short)primNr);\r
859                             var faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)j, 255 };\r
860 \r
861                             GL.Color4(faceColor);\r
862                         }\r
863 \r
864                         GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, data.TexCoords);\r
865                         GL.VertexPointer(3, VertexPointerType.Float, 0, data.Vertices);\r
866                         GL.NormalPointer(NormalPointerType.Float, 0, data.Normals);\r
867                         GL.DrawElements(BeginMode.Triangles, data.Indices.Length, DrawElementsType.UnsignedShort, data.Indices);\r
868 \r
869                     }\r
870 \r
871                     // Pop the prim matrix\r
872                     GL.PopMatrix();\r
873                 }\r
874             }\r
875         }\r
876 \r
877         private void Render(bool picking)\r
878         {\r
879             glControl.MakeCurrent();\r
880             if (picking)\r
881             {\r
882                 GL.ClearColor(1f, 1f, 1f, 1f);\r
883             }\r
884             else\r
885             {\r
886                 GL.ClearColor(0.39f, 0.58f, 0.93f, 1.0f);\r
887             }\r
888 \r
889             GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);\r
890             GL.LoadIdentity();\r
891 \r
892             // Setup wireframe or solid fill drawing mode\r
893             if (Wireframe && !picking)\r
894             {\r
895                 GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);\r
896             }\r
897             else\r
898             {\r
899                 GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);\r
900             }\r
901 \r
902             var mLookAt = OpenTK.Matrix4d.LookAt(\r
903                     Camera.Position.X, Camera.Position.Y, Camera.Position.Z,\r
904                     Camera.FocalPoint.X, Camera.FocalPoint.Y, Camera.FocalPoint.Z,\r
905                     0d, 0d, 1d);\r
906             GL.MultMatrix(ref mLookAt);\r
907 \r
908             //GL.Light(LightName.Light0, LightParameter.Position, lightPos);\r
909 \r
910             // Push the world matrix\r
911             GL.PushMatrix();\r
912 \r
913             GL.EnableClientState(ArrayCap.VertexArray);\r
914             GL.EnableClientState(ArrayCap.TextureCoordArray);\r
915             GL.EnableClientState(ArrayCap.NormalArray);\r
916 \r
917 \r
918             if (picking)\r
919             {\r
920                 RenderObjects(RenderPass.Picking);\r
921             }\r
922             else\r
923             {\r
924                 RenderObjects(RenderPass.Simple);\r
925                 RenderObjects(RenderPass.Alpha);\r
926                 //RenderText();\r
927             }\r
928 \r
929             // Pop the world matrix\r
930             GL.PopMatrix();\r
931 \r
932             GL.DisableClientState(ArrayCap.TextureCoordArray);\r
933             GL.DisableClientState(ArrayCap.VertexArray);\r
934             GL.DisableClientState(ArrayCap.NormalArray);\r
935 \r
936             GL.Flush();\r
937         }\r
938 \r
939         private void GluPerspective(float fovy, float aspect, float zNear, float zFar)\r
940         {\r
941             float fH = (float)Math.Tan(fovy / 360 * (float)Math.PI) * zNear;\r
942             float fW = fH * aspect;\r
943             GL.Frustum(-fW, fW, -fH, fH, zNear, zFar);\r
944         }\r
945 \r
946         private bool TryPick(int x, int y, out FacetedMesh picked, out int faceID)\r
947         {\r
948             // Save old attributes\r
949             GL.PushAttrib(AttribMask.AllAttribBits);\r
950 \r
951             // Disable some attributes to make the objects flat / solid color when they are drawn\r
952             GL.Disable(EnableCap.Fog);\r
953             GL.Disable(EnableCap.Texture2D);\r
954             GL.Disable(EnableCap.Dither);\r
955             GL.Disable(EnableCap.Lighting);\r
956             GL.Disable(EnableCap.LineStipple);\r
957             GL.Disable(EnableCap.PolygonStipple);\r
958             GL.Disable(EnableCap.CullFace);\r
959             GL.Disable(EnableCap.Blend);\r
960             GL.Disable(EnableCap.AlphaTest);\r
961 \r
962             Render(true);\r
963 \r
964             byte[] color = new byte[4];\r
965             GL.ReadPixels(x, glControl.Height - y, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, color);\r
966 \r
967             GL.PopAttrib();\r
968 \r
969             int primID = Utils.BytesToUInt16(color, 0);\r
970             faceID = color[2];\r
971 \r
972             picked = null;\r
973 \r
974             lock (Prims)\r
975             {\r
976                 foreach (var mesh in Prims.Values)\r
977                 {\r
978                     foreach (var face in mesh.Faces)\r
979                     {\r
980                         if (face.UserData == null) continue;\r
981                         if (((FaceData)face.UserData).PickingID == primID)\r
982                         {\r
983                             picked = mesh;\r
984                             break;\r
985                         }\r
986                     }\r
987 \r
988                     if (picked != null) break;\r
989                 }\r
990             }\r
991 \r
992             return picked != null;\r
993         }\r
994 \r
995 \r
996         private void UpdatePrimBlocking(Primitive prim)\r
997         {\r
998             // Don't render avatars for now\r
999             if (Client.Network.CurrentSim.ObjectsAvatars.ContainsKey(prim.LocalID)) return;\r
1000 \r
1001             if (Vector3.Distance(PrimPos(prim), Client.Self.SimPosition) > 32 && !Prims.ContainsKey(prim.ParentID)) return;\r
1002 \r
1003             FacetedMesh mesh = null;\r
1004             FacetedMesh existingMesh = null;\r
1005 \r
1006             lock (Prims)\r
1007             {\r
1008                 if (Prims.ContainsKey(prim.LocalID))\r
1009                 {\r
1010                     existingMesh = Prims[prim.LocalID];\r
1011                 }\r
1012             }\r
1013 \r
1014             if (prim.Textures == null)\r
1015                 return;\r
1016 \r
1017             try\r
1018             {\r
1019                 if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero)\r
1020                 {\r
1021                     if (prim.Sculpt.Type != SculptType.Mesh)\r
1022                     { // Regular sculptie\r
1023                         Image img = null;\r
1024                         if (!LoadTexture(prim.Sculpt.SculptTexture, ref img, true))\r
1025                             return;\r
1026                         mesh = renderer.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.Highest);\r
1027                     }\r
1028                     else\r
1029                     { // Mesh\r
1030                         AutoResetEvent gotMesh = new AutoResetEvent(false);\r
1031                         bool meshSuccess = false;\r
1032 \r
1033                         Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) =>\r
1034                             {\r
1035                                 if (!success || !FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out mesh))\r
1036                                 {\r
1037                                     Logger.Log("Failed to fetch or decode the mesh asset", Helpers.LogLevel.Warning, Client);\r
1038                                 }\r
1039                                 else\r
1040                                 {\r
1041                                     meshSuccess = true;\r
1042                                 }\r
1043                                 gotMesh.Set();\r
1044                             });\r
1045 \r
1046                         if (!gotMesh.WaitOne(20 * 1000, false)) return;\r
1047                         if (!meshSuccess) return;\r
1048                     }\r
1049                 }\r
1050                 else\r
1051                 {\r
1052                     mesh = renderer.GenerateFacetedMesh(prim, DetailLevel.Highest);\r
1053                 }\r
1054             }\r
1055             catch\r
1056             {\r
1057                 return;\r
1058             }\r
1059 \r
1060             // Create a FaceData struct for each face that stores the 3D data\r
1061             // in a OpenGL friendly format\r
1062             for (int j = 0; j < mesh.Faces.Count; j++)\r
1063             {\r
1064                 Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j);\r
1065 \r
1066                 Face face = mesh.Faces[j];\r
1067                 FaceData data = new FaceData();\r
1068 \r
1069                 // Vertices for this face\r
1070                 data.Vertices = new float[face.Vertices.Count * 3];\r
1071                 data.Normals = new float[face.Vertices.Count * 3];\r
1072                 for (int k = 0; k < face.Vertices.Count; k++)\r
1073                 {\r
1074                     data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;\r
1075                     data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;\r
1076                     data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;\r
1077 \r
1078                     data.Normals[k * 3 + 0] = face.Vertices[k].Normal.X;\r
1079                     data.Normals[k * 3 + 1] = face.Vertices[k].Normal.Y;\r
1080                     data.Normals[k * 3 + 2] = face.Vertices[k].Normal.Z;\r
1081                 }\r
1082 \r
1083                 // Indices for this face\r
1084                 data.Indices = face.Indices.ToArray();\r
1085 \r
1086                 // Texture transform for this face\r
1087                 renderer.TransformTexCoords(face.Vertices, face.Center, teFace);\r
1088 \r
1089                 // Texcoords for this face\r
1090                 data.TexCoords = new float[face.Vertices.Count * 2];\r
1091                 for (int k = 0; k < face.Vertices.Count; k++)\r
1092                 {\r
1093                     data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;\r
1094                     data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;\r
1095                 }\r
1096 \r
1097                 // Set the UserData for this face to our FaceData struct\r
1098                 face.UserData = data;\r
1099                 mesh.Faces[j] = face;\r
1100 \r
1101 \r
1102                 if (existingMesh != null &&\r
1103                     j < existingMesh.Faces.Count &&\r
1104                     existingMesh.Faces[j].TextureFace.TextureID == teFace.TextureID &&\r
1105                     ((FaceData)existingMesh.Faces[j].UserData).TextureInfo.TexturePointer != 0\r
1106                     )\r
1107                 {\r
1108                     FaceData existingData = (FaceData)existingMesh.Faces[j].UserData;\r
1109                     data.TextureInfo.TexturePointer = existingData.TextureInfo.TexturePointer;\r
1110                 }\r
1111                 else\r
1112                 {\r
1113 \r
1114                     var textureItem = new TextureLoadItem()\r
1115                     {\r
1116                         Data = data,\r
1117                         Prim = prim,\r
1118                         TeFace = teFace\r
1119                     };\r
1120 \r
1121                     PendingTextures.Enqueue(textureItem);\r
1122                 }\r
1123 \r
1124             }\r
1125 \r
1126             lock (Prims)\r
1127             {\r
1128                 Prims[prim.LocalID] = mesh;\r
1129             }\r
1130         }\r
1131 \r
1132         private bool LoadTexture(UUID textureID, ref Image texture, bool removeAlpha)\r
1133         {\r
1134             ManualResetEvent gotImage = new ManualResetEvent(false);\r
1135             Image img = null;\r
1136 \r
1137             try\r
1138             {\r
1139                 gotImage.Reset();\r
1140                 instance.Client.Assets.RequestImage(textureID, (TextureRequestState state, AssetTexture assetTexture) =>\r
1141                     {\r
1142                         if (state == TextureRequestState.Finished)\r
1143                         {\r
1144                             ManagedImage mi;\r
1145                             OpenJPEG.DecodeToImage(assetTexture.AssetData, out mi);\r
1146 \r
1147                             if (removeAlpha)\r
1148                             {\r
1149                                 if ((mi.Channels & ManagedImage.ImageChannels.Alpha) != 0)\r
1150                                 {\r
1151                                     mi.ConvertChannels(mi.Channels & ~ManagedImage.ImageChannels.Alpha);\r
1152                                 }\r
1153                             }\r
1154 \r
1155                             img = LoadTGAClass.LoadTGA(new MemoryStream(mi.ExportTGA()));\r
1156                         }\r
1157                         gotImage.Set();\r
1158                     }\r
1159                 );\r
1160                 gotImage.WaitOne(30 * 1000, false);\r
1161                 if (img != null)\r
1162                 {\r
1163                     texture = img;\r
1164                     return true;\r
1165                 }\r
1166                 return false;\r
1167             }\r
1168             catch (Exception e)\r
1169             {\r
1170                 Logger.Log(e.Message, Helpers.LogLevel.Error, instance.Client, e);\r
1171                 return false;\r
1172             }\r
1173         }\r
1174         #endregion Private methods (the meat)\r
1175 \r
1176         #region Form controls handlers\r
1177         private void scrollZoom_ValueChanged(object sender, EventArgs e)\r
1178         {\r
1179             Camera.Zoom = 1f - (float)scrollZoom.Value / (float)scrollZoom.Minimum;\r
1180             glControl_Resize(null, null);\r
1181         }\r
1182 \r
1183         private void chkWireFrame_CheckedChanged(object sender, EventArgs e)\r
1184         {\r
1185             Wireframe = chkWireFrame.Checked;\r
1186         }\r
1187 \r
1188         private void btnReset_Click(object sender, EventArgs e)\r
1189         {\r
1190             InitCamera();\r
1191             UpdateCamera();\r
1192             scrollZoom.Value = 0;\r
1193         }\r
1194 \r
1195         private void cbAA_CheckedChanged(object sender, EventArgs e)\r
1196         {\r
1197             instance.GlobalSettings["use_multi_sampling"] = UseMultiSampling = cbAA.Checked;\r
1198             SetupGLControl();\r
1199         }\r
1200 \r
1201         #endregion Form controls handlers\r
1202 \r
1203         #region Context menu\r
1204         private void ctxObjects_Opening(object sender, System.ComponentModel.CancelEventArgs e)\r
1205         {\r
1206             if (instance.State.IsSitting)\r
1207             {\r
1208                 sitToolStripMenuItem.Text = "Stand up";\r
1209             }\r
1210             else if (RightclickedPrim.Prim.Properties != null\r
1211                 && !string.IsNullOrEmpty(RightclickedPrim.Prim.Properties.SitName))\r
1212             {\r
1213                 sitToolStripMenuItem.Text = RightclickedPrim.Prim.Properties.SitName;\r
1214             }\r
1215             else\r
1216             {\r
1217                 sitToolStripMenuItem.Text = "Sit";\r
1218             }\r
1219 \r
1220             if (RightclickedPrim.Prim.Properties != null\r
1221                 && !string.IsNullOrEmpty(RightclickedPrim.Prim.Properties.TouchName))\r
1222             {\r
1223                 touchToolStripMenuItem.Text = RightclickedPrim.Prim.Properties.TouchName;\r
1224             }\r
1225             else\r
1226             {\r
1227                 touchToolStripMenuItem.Text = "Touch";\r
1228             }\r
1229         }\r
1230 \r
1231         private void touchToolStripMenuItem_Click(object sender, EventArgs e)\r
1232         {\r
1233 \r
1234             Client.Self.Grab(RightclickedPrim.Prim.LocalID, Vector3.Zero, Vector3.Zero, Vector3.Zero, RightclickedFaceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);\r
1235             Thread.Sleep(100);\r
1236             Client.Self.DeGrab(RightclickedPrim.Prim.LocalID);\r
1237         }\r
1238 \r
1239         private void sitToolStripMenuItem_Click(object sender, EventArgs e)\r
1240         {\r
1241             if (!instance.State.IsSitting)\r
1242             {\r
1243                 instance.State.SetSitting(true, RightclickedPrim.Prim.ID);\r
1244             }\r
1245             else\r
1246             {\r
1247                 instance.State.SetSitting(false, UUID.Zero);\r
1248             }\r
1249         }\r
1250 \r
1251         private void takeToolStripMenuItem_Click(object sender, EventArgs e)\r
1252         {\r
1253             instance.MediaManager.PlayUISound(UISounds.ObjectDelete);\r
1254             Client.Inventory.RequestDeRezToInventory(RightclickedPrim.Prim.LocalID);\r
1255             Close();\r
1256         }\r
1257 \r
1258         private void returnToolStripMenuItem_Click(object sender, EventArgs e)\r
1259         {\r
1260             instance.MediaManager.PlayUISound(UISounds.ObjectDelete);\r
1261             Client.Inventory.RequestDeRezToInventory(RightclickedPrim.Prim.LocalID, DeRezDestination.ReturnToOwner, UUID.Zero, UUID.Random());\r
1262             Close();\r
1263         }\r
1264 \r
1265         private void deleteToolStripMenuItem_Click(object sender, EventArgs e)\r
1266         {\r
1267             if (RightclickedPrim.Prim.Properties != null && RightclickedPrim.Prim.Properties.OwnerID != Client.Self.AgentID)\r
1268                 returnToolStripMenuItem_Click(sender, e);\r
1269             else\r
1270             {\r
1271                 instance.MediaManager.PlayUISound(UISounds.ObjectDelete);\r
1272                 Client.Inventory.RequestDeRezToInventory(RightclickedPrim.Prim.LocalID, DeRezDestination.AgentInventoryTake, Client.Inventory.FindFolderForType(AssetType.TrashFolder), UUID.Random());\r
1273             }\r
1274             Close();\r
1275         }\r
1276         #endregion Context menu\r
1277     }\r
1278 }\r