2 // Radegast Metaverse Client
\r
3 // Copyright (c) 2009-2011, Radegast Development Team
\r
4 // All rights reserved.
\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
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
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
34 using System.Collections.Generic;
\r
35 using System.Drawing;
\r
36 using System.Drawing.Imaging;
\r
38 using System.Windows.Forms;
\r
40 using System.Threading;
\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
50 namespace Radegast.Rendering
\r
53 public partial class SceneWindow : RadegastTabControl
\r
55 #region Public fields
\r
57 /// The OpenGL surface
\r
59 public OpenTK.GLControl glControl = null;
\r
62 /// Use multi sampling (anti aliasing)
\r
64 public bool UseMultiSampling = true;
\r
67 /// Is rendering engine ready and enabled
\r
69 public bool RenderingEnabled = false;
\r
72 /// Rednder in wireframe mode
\r
74 public bool Wireframe = false;
\r
77 /// Object from up to this distance from us will be rendered
\r
79 public float DrawDistance
\r
81 get { return drawDistance; }
\r
84 drawDistance = value;
\r
85 drawDistanceSquared = value * value;
\r
92 /// List of prims in the scene
\r
94 Dictionary<uint, RenderPrimitive> Prims = new Dictionary<uint, RenderPrimitive>();
\r
95 List<SceneObject> SortedObjects;
\r
96 List<SceneObject> OccludedObjects;
\r
97 List<RenderAvatar> VisibleAvatars;
\r
98 Dictionary<uint, RenderAvatar> Avatars = new Dictionary<uint, RenderAvatar>();
\r
103 public bool PrimitiveRenderingEnabled = true;
\r
108 public bool AvatarRenderingEnabled = true;
\r
111 /// Show avatar skeloton
\r
113 public bool RenderAvatarSkeleton = false;
\r
116 /// Should we try to optimize by not drawing objects occluded behind other objects
\r
118 public bool OcclusionCullingEnabled = true;
\r
121 /// Cache images after jpeg2000 decode. Uses a lot of disk space and can cause disk trashing
\r
123 public bool CacheDecodedTextures = false;
\r
125 #endregion Public fields
\r
127 #region Private fields
\r
130 Dictionary<UUID, TextureInfo> TexturesPtrMap = new Dictionary<UUID, TextureInfo>();
\r
131 MeshmerizerR renderer;
\r
132 OpenTK.Graphics.GraphicsMode GLMode = null;
\r
133 AutoResetEvent TextureThreadContextReady = new AutoResetEvent(false);
\r
135 delegate void GenericTask();
\r
136 BlockingQueue<GenericTask> PendingTasks = new BlockingQueue<GenericTask>();
\r
137 Thread genericTaskThread;
\r
139 BlockingQueue<TextureLoadItem> PendingTextures = new BlockingQueue<TextureLoadItem>();
\r
142 Font HoverTextFont = new Font(FontFamily.GenericSansSerif, 9f, FontStyle.Regular);
\r
143 Font AvatarTagFont = new Font(FontFamily.GenericSansSerif, 10f, FontStyle.Bold);
\r
144 Dictionary<UUID, Bitmap> sculptCache = new Dictionary<UUID, Bitmap>();
\r
145 OpenTK.Matrix4 ModelMatrix;
\r
146 OpenTK.Matrix4 ProjectionMatrix;
\r
147 int[] Viewport = new int[4];
\r
148 bool useVBO = true;
\r
149 System.Diagnostics.Stopwatch renderTimer;
\r
150 float lastFrameTime = 0f;
\r
151 float advTimerTick = 0f;
\r
152 float minLODFactor = 0.0001f;
\r
154 float[] lightPos = new float[] { 128f, 128f, 5000f, 0f };
\r
155 float ambient = 0.26f;
\r
156 float difuse = 0.27f;
\r
157 float specular = 0.20f;
\r
158 OpenTK.Vector4 ambientColor;
\r
159 OpenTK.Vector4 difuseColor;
\r
160 OpenTK.Vector4 specularColor;
\r
161 float drawDistance = 48f;
\r
162 float drawDistanceSquared = 48f * 48f;
\r
165 RadegastInstance Instance;
\r
167 #endregion Private fields
\r
169 #region Construction and disposal
\r
170 public SceneWindow(RadegastInstance instance)
\r
173 InitializeComponent();
\r
174 Disposed += new EventHandler(frmPrimWorkshop_Disposed);
\r
176 this.Instance = instance;
\r
177 this.Client = instance.Client;
\r
179 UseMultiSampling = cbAA.Checked = instance.GlobalSettings["use_multi_sampling"];
\r
180 cbAA.CheckedChanged += cbAA_CheckedChanged;
\r
182 this.instance = instance;
\r
184 genericTaskThread = new Thread(new ThreadStart(GenericTaskRunner));
\r
185 genericTaskThread.IsBackground = true;
\r
186 genericTaskThread.Name = "Generic task queue";
\r
187 genericTaskThread.Start();
\r
189 renderer = new MeshmerizerR();
\r
190 renderTimer = new System.Diagnostics.Stopwatch();
\r
191 renderTimer.Start();
\r
193 // Camera initial setting
\r
194 Camera = new Camera();
\r
197 tbDrawDistance.Value = (int)DrawDistance;
\r
198 lblDrawDistance.Text = string.Format("Draw distance: {0}", tbDrawDistance.Value);
\r
200 Client.Objects.TerseObjectUpdate += new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
\r
201 Client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
\r
202 Client.Objects.ObjectDataBlockUpdate += new EventHandler<ObjectDataBlockUpdateEventArgs>(Objects_ObjectDataBlockUpdate);
\r
203 Client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);
\r
204 Client.Network.SimChanged += new EventHandler<SimChangedEventArgs>(Network_SimChanged);
\r
205 Client.Terrain.LandPatchReceived += new EventHandler<LandPatchReceivedEventArgs>(Terrain_LandPatchReceived);
\r
206 Client.Avatars.AvatarAnimation += new EventHandler<AvatarAnimationEventArgs>(AvatarAnimationChanged);
\r
207 Client.Avatars.AvatarAppearance += new EventHandler<AvatarAppearanceEventArgs>(Avatars_AvatarAppearance);
\r
208 Client.Appearance.AppearanceSet += new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
\r
209 Instance.Netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(Netcom_ClientDisconnected);
\r
210 Application.Idle += new EventHandler(Application_Idle);
\r
213 void frmPrimWorkshop_Disposed(object sender, EventArgs e)
\r
215 RenderingEnabled = false;
\r
216 Application.Idle -= new EventHandler(Application_Idle);
\r
218 PendingTextures.Close();
\r
220 Client.Objects.TerseObjectUpdate -= new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
\r
221 Client.Objects.ObjectUpdate -= new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
\r
222 Client.Objects.ObjectDataBlockUpdate -= new EventHandler<ObjectDataBlockUpdateEventArgs>(Objects_ObjectDataBlockUpdate);
\r
223 Client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
\r
224 Client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);
\r
225 Client.Terrain.LandPatchReceived -= new EventHandler<LandPatchReceivedEventArgs>(Terrain_LandPatchReceived);
\r
226 Client.Avatars.AvatarAnimation -= new EventHandler<AvatarAnimationEventArgs>(AvatarAnimationChanged);
\r
227 Client.Avatars.AvatarAppearance -= new EventHandler<AvatarAppearanceEventArgs>(Avatars_AvatarAppearance);
\r
228 Client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
\r
230 PendingTasks.Close();
\r
231 if (genericTaskThread != null)
\r
233 genericTaskThread.Join(2000);
\r
234 genericTaskThread = null;
\r
237 if (instance.Netcom != null)
\r
239 Instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_ClientDisconnected);
\r
242 if (glControl != null)
\r
244 glControl.Dispose();
\r
250 foreach (var img in sculptCache.Values)
\r
252 sculptCache.Clear();
\r
255 lock (Prims) Prims.Clear();
\r
256 lock (Avatars) Avatars.Clear();
\r
258 TexturesPtrMap.Clear();
\r
262 void Application_Idle(object sender, EventArgs e)
\r
264 if (glControl != null && !glControl.IsDisposed && RenderingEnabled)
\r
268 while (glControl != null && glControl.IsIdle && RenderingEnabled)
\r
271 if (instance.MonoRuntime)
\r
273 Application.DoEvents();
\r
277 catch (ObjectDisposedException)
\r
281 #endregion Construction and disposal
\r
284 public void RegisterTabEvents()
\r
286 this.RadegastTab.TabAttached += new EventHandler(RadegastTab_TabAttached);
\r
287 this.RadegastTab.TabDetached += new EventHandler(RadegastTab_TabDetached);
\r
288 this.RadegastTab.TabClosed += new EventHandler(RadegastTab_TabClosed);
\r
291 public void UnregisterTabEvents()
\r
293 this.RadegastTab.TabAttached -= new EventHandler(RadegastTab_TabAttached);
\r
294 this.RadegastTab.TabDetached -= new EventHandler(RadegastTab_TabDetached);
\r
295 this.RadegastTab.TabClosed -= new EventHandler(RadegastTab_TabClosed);
\r
298 void RadegastTab_TabDetached(object sender, EventArgs e)
\r
300 instance.GlobalSettings["scene_window_docked"] = false;
\r
301 pnlDebug.Visible = true;
\r
304 void RadegastTab_TabAttached(object sender, EventArgs e)
\r
306 instance.GlobalSettings["scene_window_docked"] = true;
\r
307 pnlDebug.Visible = false;
\r
310 void RadegastTab_TabClosed(object sender, EventArgs e)
\r
312 if (this.RadegastTab != null)
\r
314 UnregisterTabEvents();
\r
318 #endregion Tab Events
\r
320 #region Network messaage handlers
\r
321 void Terrain_LandPatchReceived(object sender, LandPatchReceivedEventArgs e)
\r
323 if (e.Simulator.Handle == Client.Network.CurrentSim.Handle)
\r
325 TerrainModified = true;
\r
329 void Netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
\r
331 if (InvokeRequired)
\r
333 if (IsHandleCreated || !instance.MonoRuntime)
\r
335 BeginInvoke(new MethodInvoker(() => Netcom_ClientDisconnected(sender, e)));
\r
343 void Network_SimChanged(object sender, SimChangedEventArgs e)
\r
345 if (InvokeRequired)
\r
347 BeginInvoke(new MethodInvoker(() => Network_SimChanged(sender, e)));
\r
354 foreach (var img in sculptCache.Values)
\r
356 sculptCache.Clear();
\r
358 lock (Prims) Prims.Clear();
\r
359 lock (Avatars) Avatars.Clear();
\r
360 LoadCurrentPrims();
\r
364 void Objects_KillObject(object sender, KillObjectEventArgs e)
\r
366 if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;
\r
367 if (InvokeRequired)
\r
369 if (IsHandleCreated)
\r
371 BeginInvoke(new MethodInvoker(() => Objects_KillObject(sender, e)));
\r
376 // TODO: there should be really cleanup of resources when removing prims and avatars
\r
377 lock (Prims) Prims.Remove(e.ObjectLocalID);
\r
378 lock (Avatars) Avatars.Remove(e.ObjectLocalID);
\r
381 void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e)
\r
383 if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;
\r
384 UpdatePrimBlocking(e.Prim);
\r
387 void Objects_ObjectUpdate(object sender, PrimEventArgs e)
\r
389 if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;
\r
390 UpdatePrimBlocking(e.Prim);
\r
393 void Objects_ObjectDataBlockUpdate(object sender, ObjectDataBlockUpdateEventArgs e)
\r
395 if (e.Simulator.Handle != Client.Network.CurrentSim.Handle) return;
\r
396 UpdatePrimBlocking(e.Prim);
\r
399 void AvatarAnimationChanged(object sender, AvatarAnimationEventArgs e)
\r
402 // We don't currently have UUID -> RenderAvatar mapping so we need to walk the list
\r
403 foreach (RenderAvatar av in Avatars.Values)
\r
405 if (av.avatar.ID == e.AvatarID)
\r
407 foreach (Animation anim in e.Animations)
\r
409 UUID tid = UUID.Random();
\r
410 skeleton.mAnimationTransactions.Add(tid, av);
\r
412 BinBVHAnimationReader bvh;
\r
413 if(skeleton.mAnimationCache.TryGetValue(anim.AnimationID,out bvh))
\r
415 skeleton.addanimation(null, tid, bvh);
\r
419 Logger.Log("Requesting new animation asset " + anim.AnimationID.ToString(), Helpers.LogLevel.Info);
\r
421 Client.Assets.RequestAsset(anim.AnimationID, AssetType.Animation, false,SourceType.Asset,tid, animRecievedCallback);
\r
428 void animRecievedCallback(AssetDownload transfer, Asset asset)
\r
430 if (transfer.Success)
\r
432 skeleton.addanimation(asset,transfer.ID, null);
\r
436 void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e)
\r
438 // We don't currently have UUID -> RenderAvatar mapping so we need to walk the list
\r
439 foreach (RenderAvatar av in Avatars.Values)
\r
441 if (av.avatar.ID == e.AvatarID)
\r
443 av.glavatar.morph(av.avatar);
\r
448 void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
\r
453 if (Avatars.TryGetValue(Client.Self.LocalID, out me))
\r
455 me.glavatar.morph(me.avatar);
\r
460 #endregion Network messaage handlers
\r
462 #region glControl setup and disposal
\r
463 public void SetupGLControl()
\r
465 RenderingEnabled = false;
\r
467 if (glControl != null)
\r
468 glControl.Dispose();
\r
475 if (!UseMultiSampling)
\r
477 GLMode = new OpenTK.Graphics.GraphicsMode(OpenTK.DisplayDevice.Default.BitsPerPixel, 24, 8, 0);
\r
481 for (int aa = 0; aa <= 4; aa += 2)
\r
483 var testMode = new OpenTK.Graphics.GraphicsMode(OpenTK.DisplayDevice.Default.BitsPerPixel, 24, 8, aa);
\r
484 if (testMode.Samples == aa)
\r
499 if (GLMode == null)
\r
501 // Try default mode
\r
502 glControl = new OpenTK.GLControl();
\r
506 glControl = new OpenTK.GLControl(GLMode);
\r
509 catch (Exception ex)
\r
511 Logger.Log(ex.Message, Helpers.LogLevel.Warning, Client);
\r
515 if (glControl == null)
\r
517 Logger.Log("Failed to initialize OpenGL control, cannot continue", Helpers.LogLevel.Error, Client);
\r
521 Logger.Log("Initializing OpenGL mode: " + GLMode.ToString(), Helpers.LogLevel.Info);
\r
523 glControl.Paint += glControl_Paint;
\r
524 glControl.Resize += glControl_Resize;
\r
525 glControl.MouseDown += glControl_MouseDown;
\r
526 glControl.MouseUp += glControl_MouseUp;
\r
527 glControl.MouseMove += glControl_MouseMove;
\r
528 glControl.MouseWheel += glControl_MouseWheel;
\r
529 glControl.Load += new EventHandler(glControl_Load);
\r
530 glControl.Disposed += new EventHandler(glControl_Disposed);
\r
531 glControl.Dock = DockStyle.Fill;
\r
532 glControl.VSync = false;
\r
533 Controls.Add(glControl);
\r
534 glControl.BringToFront();
\r
537 void glControl_Disposed(object sender, EventArgs e)
\r
539 TextureThreadRunning = false;
\r
540 PendingTextures.Close();
\r
541 glControl.Paint -= glControl_Paint;
\r
542 glControl.Resize -= glControl_Resize;
\r
543 glControl.MouseDown -= glControl_MouseDown;
\r
544 glControl.MouseUp -= glControl_MouseUp;
\r
545 glControl.MouseMove -= glControl_MouseMove;
\r
546 glControl.MouseWheel -= glControl_MouseWheel;
\r
547 glControl.Load -= new EventHandler(glControl_Load);
\r
548 glControl.Disposed -= glControl_Disposed;
\r
553 ambientColor = new OpenTK.Vector4(ambient, ambient, ambient, difuse);
\r
554 difuseColor = new OpenTK.Vector4(difuse, difuse, difuse, difuse);
\r
555 specularColor = new OpenTK.Vector4(specular, specular, specular, specular);
\r
556 GL.Light(LightName.Light0, LightParameter.Ambient, ambientColor);
\r
557 GL.Light(LightName.Light0, LightParameter.Diffuse, difuseColor);
\r
558 GL.Light(LightName.Light0, LightParameter.Specular, specularColor);
\r
559 GL.Light(LightName.Light0, LightParameter.Position, lightPos);
\r
562 void glControl_Load(object sender, EventArgs e)
\r
566 GL.ShadeModel(ShadingModel.Smooth);
\r
568 GL.Enable(EnableCap.Lighting);
\r
569 GL.Enable(EnableCap.Light0);
\r
572 GL.ClearDepth(1.0d);
\r
573 GL.Enable(EnableCap.DepthTest);
\r
574 GL.Enable(EnableCap.CullFace);
\r
575 GL.CullFace(CullFaceMode.Back);
\r
577 // GL.Color() tracks objects ambient and diffuse color
\r
578 GL.Enable(EnableCap.ColorMaterial);
\r
579 GL.ColorMaterial(MaterialFace.Front, ColorMaterialParameter.AmbientAndDiffuse);
\r
581 GL.DepthMask(true);
\r
582 GL.DepthFunc(DepthFunction.Lequal);
\r
583 GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
\r
584 GL.MatrixMode(MatrixMode.Projection);
\r
586 GL.AlphaFunc(AlphaFunction.Greater, 0.5f);
\r
587 GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
\r
588 string glExtensions = GL.GetString(StringName.Extensions);
\r
589 hasMipmap = glExtensions.Contains("GL_SGIS_generate_mipmap");
\r
590 useVBO = glExtensions.Contains("ARB_vertex_buffer_object");
\r
592 // Double check if we have mipmap ability
\r
598 Bitmap testPic = new Bitmap(1, 1);
\r
599 BitmapData testData = testPic.LockBits(new Rectangle(0, 0, 1, 1), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
\r
600 GL.GenTextures(1, out testID);
\r
601 GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb8, 1, 1, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, testData.Scan0);
\r
602 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
\r
603 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1);
\r
604 GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
\r
605 testPic.UnlockBits(testData);
\r
607 GL.DeleteTexture(testID);
\r
611 Logger.DebugLog("Don't have glGenerateMipmap() after all");
\r
616 RenderingEnabled = true;
\r
617 // Call the resizing function which sets up the GL drawing window
\r
618 // and will also invalidate the GL control
\r
619 glControl_Resize(null, null);
\r
620 RenderingEnabled = false;
\r
622 glControl.Context.MakeCurrent(null);
\r
623 TextureThreadContextReady.Reset();
\r
624 var textureThread = new Thread(() => TextureThread())
\r
626 IsBackground = true,
\r
627 Name = "TextureDecodingThread"
\r
629 textureThread.Start();
\r
630 TextureThreadContextReady.WaitOne(1000, false);
\r
631 glControl.MakeCurrent();
\r
632 RenderingEnabled = true;
\r
633 LoadCurrentPrims();
\r
635 catch (Exception ex)
\r
637 RenderingEnabled = false;
\r
638 Logger.Log("Failed to initialize OpenGL control", Helpers.LogLevel.Warning, Client, ex);
\r
641 #endregion glControl setup and disposal
\r
643 #region glControl paint and resize events
\r
644 private void MainRenderLoop()
\r
646 if (!RenderingEnabled) return;
\r
647 lastFrameTime = (float)renderTimer.Elapsed.TotalSeconds;
\r
649 // Something went horribly wrong
\r
650 if (lastFrameTime < 0) return;
\r
652 // Stopwatch loses resolution if it runs for a long time, reset it
\r
653 renderTimer.Reset();
\r
654 renderTimer.Start();
\r
656 // Determine if we need to throttle frame rate
\r
657 bool throttle = false;
\r
659 // Some other app has focus
\r
660 if (Form.ActiveForm == null)
\r
666 // If we're docked but not active tab, throttle
\r
667 if (!this.RadegastTab.Selected && !this.RadegastTab.Detached)
\r
673 // Limit FPS to max 15
\r
676 int msToSleep = 66 - ((int)(lastFrameTime / 1000));
\r
677 if (msToSleep < 10) msToSleep = 10;
\r
678 Thread.Sleep(msToSleep);
\r
683 glControl.SwapBuffers();
\r
686 void glControl_Paint(object sender, EventArgs e)
\r
691 private void glControl_Resize(object sender, EventArgs e)
\r
693 if (!RenderingEnabled) return;
\r
694 glControl.MakeCurrent();
\r
696 GL.ClearColor(0.39f, 0.58f, 0.93f, 1.0f);
\r
698 GL.Viewport(0, 0, glControl.Width, glControl.Height);
\r
701 GL.MatrixMode(MatrixMode.Projection);
\r
706 GL.MatrixMode(MatrixMode.Modelview);
\r
709 #endregion glControl paint and resize events
\r
711 #region Mouse handling
\r
712 bool dragging = false;
\r
713 int dragX, dragY, downX, downY;
\r
715 private void glControl_MouseWheel(object sender, MouseEventArgs e)
\r
717 Camera.Position += (Camera.Position - Camera.FocalPoint) * (e.Delta / -500f);
\r
720 SceneObject RightclickedObject;
\r
721 int RightclickedFaceID;
\r
723 private void glControl_MouseDown(object sender, MouseEventArgs e)
\r
725 if (e.Button == MouseButtons.Left)
\r
728 downX = dragX = e.X;
\r
729 downY = dragY = e.Y;
\r
731 else if (e.Button == MouseButtons.Right)
\r
734 RightclickedObject = null;
\r
735 if (TryPick(e.X, e.Y, out picked, out RightclickedFaceID))
\r
737 if (picked is SceneObject)
\r
739 RightclickedObject = (SceneObject)picked;
\r
742 ctxMenu.Show(glControl, e.X, e.Y);
\r
746 private void glControl_MouseMove(object sender, MouseEventArgs e)
\r
750 int deltaX = e.X - dragX;
\r
751 int deltaY = e.Y - dragY;
\r
752 float pixelToM = 1f / 75f;
\r
754 if (e.Button == MouseButtons.Left)
\r
757 if (ModifierKeys == Keys.Control || ModifierKeys == (Keys.Alt | Keys.Control | Keys.Shift))
\r
759 Vector3 direction = Camera.Position - Camera.FocalPoint;
\r
760 direction.Normalize();
\r
761 Vector3 vy = direction % new Vector3(0f, 0f, 1f);
\r
762 Vector3 vx = vy % direction;
\r
763 Vector3 vxy = vx * deltaY * pixelToM * 2 + vy * deltaX * pixelToM * 2;
\r
764 Camera.Position += vxy;
\r
765 Camera.FocalPoint += vxy;
\r
768 // Alt-zoom (up down move camera closer to target, left right rotate around target)
\r
769 if (ModifierKeys == Keys.Alt)
\r
771 Camera.Position += (Camera.Position - Camera.FocalPoint) * deltaY * pixelToM;
\r
772 var dx = -(deltaX * pixelToM);
\r
773 Camera.Position = Camera.FocalPoint + (Camera.Position - Camera.FocalPoint) * new Quaternion(0f, 0f, (float)Math.Sin(dx), (float)Math.Cos(dx));
\r
776 // Rotate camera in a vertical circle around target on up down mouse movement
\r
777 if (ModifierKeys == (Keys.Alt | Keys.Control))
\r
779 Camera.Position = Camera.FocalPoint +
\r
780 (Camera.Position - Camera.FocalPoint)
\r
781 * Quaternion.CreateFromAxisAngle((Camera.Position - Camera.FocalPoint) % new Vector3(0f, 0f, 1f), deltaY * pixelToM);
\r
782 var dx = -(deltaX * pixelToM);
\r
783 Camera.Position = Camera.FocalPoint + (Camera.Position - Camera.FocalPoint) * new Quaternion(0f, 0f, (float)Math.Sin(dx), (float)Math.Cos(dx));
\r
793 private void glControl_MouseUp(object sender, MouseEventArgs e)
\r
795 if (e.Button == MouseButtons.Left)
\r
799 if (e.X == downX && e.Y == downY) // click
\r
803 if (TryPick(e.X, e.Y, out clicked, out faceID))
\r
805 if (clicked is RenderPrimitive)
\r
807 RenderPrimitive picked = (RenderPrimitive)clicked;
\r
809 if (ModifierKeys == Keys.None)
\r
811 Client.Self.Grab(picked.Prim.LocalID, Vector3.Zero, Vector3.Zero, Vector3.Zero, faceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);
\r
812 Client.Self.GrabUpdate(picked.Prim.ID, Vector3.Zero, Vector3.Zero, Vector3.Zero, Vector3.Zero, faceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);
\r
813 Client.Self.DeGrab(picked.Prim.LocalID);
\r
815 else if (ModifierKeys == Keys.Alt)
\r
817 Camera.FocalPoint = picked.RenderPosition;
\r
818 Cursor.Position = glControl.PointToScreen(new Point(glControl.Width / 2, glControl.Height / 2));
\r
821 else if (clicked is RenderAvatar)
\r
823 RenderAvatar av = (RenderAvatar)clicked;
\r
824 if (ModifierKeys == Keys.Alt)
\r
826 Vector3 pos = av.RenderPosition;
\r
827 pos.Z += 1.5f; // focus roughly on the chest area
\r
828 Camera.FocalPoint = pos;
\r
829 Cursor.Position = glControl.PointToScreen(new Point(glControl.Width / 2, glControl.Height / 2));
\r
836 #endregion Mouse handling
\r
838 // Switch to ortho display mode for drawing hud
\r
839 public void GLHUDBegin()
\r
841 GL.Disable(EnableCap.DepthTest);
\r
842 GL.Disable(EnableCap.Lighting);
\r
843 GL.Disable(EnableCap.Light0);
\r
844 GL.MatrixMode(MatrixMode.Projection);
\r
847 GL.Ortho(0, glControl.Width, 0, glControl.Height, -5, 1);
\r
848 GL.MatrixMode(MatrixMode.Modelview);
\r
852 // Switch back to frustrum display mode
\r
853 public void GLHUDEnd()
\r
855 GL.Enable(EnableCap.DepthTest);
\r
856 GL.Enable(EnableCap.Lighting);
\r
857 GL.Enable(EnableCap.Light0);
\r
858 GL.MatrixMode(MatrixMode.Projection);
\r
860 GL.MatrixMode(MatrixMode.Modelview);
\r
863 public int GLLoadImage(Bitmap bitmap, bool hasAlpha)
\r
866 GL.GenTextures(1, out ret);
\r
867 GL.BindTexture(TextureTarget.Texture2D, ret);
\r
869 Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
\r
871 BitmapData bitmapData =
\r
874 ImageLockMode.ReadOnly,
\r
875 hasAlpha ? System.Drawing.Imaging.PixelFormat.Format32bppArgb : System.Drawing.Imaging.PixelFormat.Format24bppRgb);
\r
878 TextureTarget.Texture2D,
\r
880 hasAlpha ? PixelInternalFormat.Rgba : PixelInternalFormat.Rgb8,
\r
884 hasAlpha ? OpenTK.Graphics.OpenGL.PixelFormat.Bgra : OpenTK.Graphics.OpenGL.PixelFormat.Bgr,
\r
885 PixelType.UnsignedByte,
\r
888 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
\r
889 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
\r
890 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
\r
893 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
\r
894 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1);
\r
895 GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
\r
899 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
\r
902 bitmap.UnlockBits(bitmapData);
\r
906 #region Texture thread
\r
907 bool TextureThreadRunning = true;
\r
909 void TextureThread()
\r
911 OpenTK.INativeWindow window = new OpenTK.NativeWindow();
\r
912 OpenTK.Graphics.IGraphicsContext context = new OpenTK.Graphics.GraphicsContext(GLMode, window.WindowInfo);
\r
913 context.MakeCurrent(window.WindowInfo);
\r
914 TextureThreadContextReady.Set();
\r
915 PendingTextures.Open();
\r
916 Logger.DebugLog("Started Texture Thread");
\r
918 while (window.Exists && TextureThreadRunning)
\r
920 window.ProcessEvents();
\r
922 TextureLoadItem item = null;
\r
924 if (!PendingTextures.Dequeue(Timeout.Infinite, ref item)) continue;
\r
926 // Already have this one loaded
\r
927 if (item.Data.TextureInfo.TexturePointer != 0) continue;
\r
929 byte[] imageBytes = null;
\r
930 if (item.TGAData != null)
\r
932 imageBytes = item.TGAData;
\r
934 else if (item.TextureData != null || item.LoadAssetFromCache)
\r
936 if (item.LoadAssetFromCache)
\r
938 item.TextureData = Client.Assets.Cache.GetCachedAssetBytes(item.Data.TextureInfo.TextureID);
\r
941 if (!OpenJPEG.DecodeToImage(item.TextureData, out mi)) continue;
\r
943 bool hasAlpha = false;
\r
944 bool fullAlpha = false;
\r
945 bool isMask = false;
\r
946 if ((mi.Channels & ManagedImage.ImageChannels.Alpha) != 0)
\r
951 // Do we really have alpha, is it all full alpha, or is it a mask
\r
952 for (int i = 0; i < mi.Alpha.Length; i++)
\r
954 if (mi.Alpha[i] < 255)
\r
958 if (mi.Alpha[i] != 0)
\r
962 if (mi.Alpha[i] != 0 && mi.Alpha[i] != 255)
\r
970 mi.ConvertChannels(mi.Channels & ~ManagedImage.ImageChannels.Alpha);
\r
974 item.Data.TextureInfo.HasAlpha = hasAlpha;
\r
975 item.Data.TextureInfo.FullAlpha = fullAlpha;
\r
976 item.Data.TextureInfo.IsMask = isMask;
\r
978 imageBytes = mi.ExportTGA();
\r
979 if (CacheDecodedTextures)
\r
981 RHelp.SaveCachedImage(imageBytes, item.TeFace.TextureID, hasAlpha, fullAlpha, isMask);
\r
985 if (imageBytes != null)
\r
989 using (MemoryStream byteData = new MemoryStream(imageBytes))
\r
991 img = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(byteData);
\r
994 Bitmap bitmap = (Bitmap)img;
\r
996 bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
\r
997 item.Data.TextureInfo.TexturePointer = GLLoadImage(bitmap, item.Data.TextureInfo.HasAlpha);
\r
1002 item.TextureData = null;
\r
1003 item.TGAData = null;
\r
1004 imageBytes = null;
\r
1006 context.Dispose();
\r
1008 Logger.DebugLog("Texture thread exited");
\r
1010 #endregion Texture thread
\r
1012 void GenericTaskRunner()
\r
1014 PendingTasks.Open();
\r
1015 Logger.DebugLog("Started generic task thread");
\r
1019 GenericTask task = null;
\r
1020 if (!PendingTasks.Dequeue(Timeout.Infinite, ref task)) break;
\r
1023 Logger.DebugLog("Generic task thread exited");
\r
1026 void LoadCurrentPrims()
\r
1028 if (!Client.Network.Connected) return;
\r
1030 ThreadPool.QueueUserWorkItem(sync =>
\r
1032 if (PrimitiveRenderingEnabled)
\r
1034 List<Primitive> mainPrims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive root) => root.ParentID == 0);
\r
1035 foreach (Primitive mainPrim in mainPrims)
\r
1037 UpdatePrimBlocking(mainPrim);
\r
1038 Client.Network.CurrentSim.ObjectsPrimitives
\r
1039 .FindAll((Primitive child) => child.ParentID == mainPrim.LocalID)
\r
1040 .ForEach((Primitive subPrim) => UpdatePrimBlocking(subPrim));
\r
1044 if (AvatarRenderingEnabled)
\r
1046 List<Avatar> avis = Client.Network.CurrentSim.ObjectsAvatars.FindAll((Avatar a) => true);
\r
1047 foreach (Avatar avatar in avis)
\r
1049 UpdatePrimBlocking(avatar);
\r
1050 Client.Network.CurrentSim.ObjectsPrimitives
\r
1051 .FindAll((Primitive child) => child.ParentID == avatar.LocalID)
\r
1052 .ForEach((Primitive attachedPrim) =>
\r
1054 UpdatePrimBlocking(attachedPrim);
\r
1055 Client.Network.CurrentSim.ObjectsPrimitives
\r
1056 .FindAll((Primitive child) => child.ParentID == attachedPrim.LocalID)
\r
1057 .ForEach((Primitive attachedPrimChild) =>
\r
1059 UpdatePrimBlocking(attachedPrimChild);
\r
1067 private void ControlLoaded(object sender, EventArgs e)
\r
1069 ThreadPool.QueueUserWorkItem(sync =>
\r
1072 AvatarDataInitialzied();
\r
1076 #region Private methods (the meat)
\r
1078 private void AvatarDataInitialzied()
\r
1080 if (IsDisposed) return;
\r
1082 // Ensure that this is done on the main thread
\r
1083 if (InvokeRequired)
\r
1085 Invoke(new MethodInvoker(() => AvatarDataInitialzied()));
\r
1089 foreach (VisualParamEx vpe in VisualParamEx.morphParams.Values)
\r
1091 comboBox_morph.Items.Add(vpe.Name);
\r
1094 foreach (VisualParamEx vpe in VisualParamEx.drivenParams.Values)
\r
1096 comboBox_driver.Items.Add(vpe.Name);
\r
1102 private void InitAvatarData()
\r
1104 GLAvatar.loadlindenmeshes2("avatar_lad.xml");
\r
1107 private void UpdateCamera()
\r
1109 if (Client != null)
\r
1111 Client.Self.Movement.Camera.LookAt(Camera.Position, Camera.FocalPoint);
\r
1112 Client.Self.Movement.Camera.Far = Camera.Far = DrawDistance;
\r
1118 Vector3 camPos = Client.Self.SimPosition + new Vector3(-2, 0, 0) * Client.Self.Movement.BodyRotation;
\r
1120 Camera.Position = camPos;
\r
1121 Camera.FocalPoint = Client.Self.SimPosition + new Vector3(5, 0, 0) * Client.Self.Movement.BodyRotation;
\r
1122 Camera.Zoom = 1.0f;
\r
1123 Camera.Far = DrawDistance;
\r
1127 Vector3 PrimPos(Primitive prim)
\r
1131 PrimPosAndRot(GetSceneObject(prim.LocalID), out pos, out rot);
\r
1135 bool IsAttached(uint parentLocalID)
\r
1137 if (parentLocalID == 0) return false;
\r
1138 if (Client.Network.CurrentSim.ObjectsAvatars.ContainsKey(parentLocalID))
\r
1144 return IsAttached(Client.Network.CurrentSim.ObjectsPrimitives[parentLocalID].ParentID);
\r
1148 SceneObject GetSceneObject(uint localID)
\r
1150 RenderPrimitive parent;
\r
1152 if (Prims.TryGetValue(localID, out parent))
\r
1156 else if (Avatars.TryGetValue(localID, out avi))
\r
1163 void PrimPosAndRot(SceneObject prim, out Vector3 pos, out Quaternion rot)
\r
1167 pos = RHelp.InvalidPosition;
\r
1168 rot = Quaternion.Identity;
\r
1172 if (prim.BasePrim.ParentID == 0)
\r
1174 pos = prim.InterpolatedPosition;
\r
1175 rot = prim.InterpolatedRotation;
\r
1180 pos = RHelp.InvalidPosition;
\r
1181 rot = Quaternion.Identity;
\r
1183 SceneObject p = GetSceneObject(prim.BasePrim.ParentID);
\r
1184 if (p == null) return;
\r
1186 if (!p.PositionCalculated)
\r
1188 PrimPosAndRot(p, out p.RenderPosition, out p.RenderRotation);
\r
1189 p.DistanceSquared = Vector3.DistanceSquared(Camera.RenderPosition, p.RenderPosition);
\r
1190 p.PositionCalculated = true;
\r
1193 Vector3 parentPos = p.RenderPosition;
\r
1194 Quaternion parentRot = p.RenderRotation;
\r
1196 if (p is RenderPrimitive)
\r
1198 pos = parentPos + prim.InterpolatedPosition * parentRot;
\r
1199 rot = parentRot * prim.InterpolatedRotation;
\r
1201 else if (p is RenderAvatar)
\r
1203 RenderAvatar parentav = (RenderAvatar)p;
\r
1205 int attachment_index = (int)prim.BasePrim.PrimData.AttachmentPoint;
\r
1206 // Check for invalid LL attachment point
\r
1207 if (attachment_index > GLAvatar.attachment_points.Count()) return;
\r
1209 attachment_point apoint = GLAvatar.attachment_points[attachment_index];
\r
1210 Vector3 point = parentav.glavatar.skel.getOffset(apoint.joint) + apoint.position;
\r
1211 Quaternion qrot = apoint.rotation * parentav.glavatar.skel.getRotation(apoint.joint);
\r
1213 pos = parentPos + point * parentRot + prim.InterpolatedPosition * (parentRot * qrot);
\r
1214 rot = qrot * parentRot * prim.InterpolatedRotation;
\r
1220 private void SetPerspective()
\r
1222 float dAspRat = (float)glControl.Width / (float)glControl.Height;
\r
1223 GluPerspective(50.0f * Camera.Zoom, dAspRat, 0.1f, 1000f);
\r
1227 #pragma warning disable 0612
\r
1228 OpenTK.Graphics.TextPrinter Printer = new OpenTK.Graphics.TextPrinter(OpenTK.Graphics.TextQuality.High);
\r
1229 #pragma warning restore 0612
\r
1231 private void RenderStats()
\r
1233 // This is a FIR filter known as a MMA or Modified Mean Average, using a 20 point sampling width
\r
1234 advTimerTick = ((19 * advTimerTick) + lastFrameTime) / 20;
\r
1235 // Stats in window title for now
\r
1236 Text = String.Format("Scene Viewer: FPS {0:000.00} Texture decode queue: {1}, Sculpt queue: {2}",
\r
1237 1d / advTimerTick,
\r
1238 PendingTextures.Count,
\r
1239 PendingTasks.Count);
\r
1241 #if TURNS_OUT_PRINTER_IS_EXPENISVE
\r
1242 int posX = glControl.Width - 100;
\r
1246 Printer.Print(String.Format("FPS {0:000.00}", 1d / advTimerTick), AvatarTagFont, Color.Orange,
\r
1247 new RectangleF(posX, posY, 100, 50),
\r
1248 OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);
\r
1253 private void RenderText()
\r
1258 GL.Color4(0f, 0f, 0f, 0.4f);
\r
1260 foreach (RenderAvatar av in VisibleAvatars)
\r
1262 Vector3 avPos = av.RenderPosition;
\r
1263 if (av.DistanceSquared > 400f) continue;
\r
1265 OpenTK.Vector3 tagPos = RHelp.TKVector3(avPos);
\r
1267 OpenTK.Vector3 screenPos;
\r
1268 if (!Math3D.GluProject(tagPos, ModelMatrix, ProjectionMatrix, Viewport, out screenPos)) continue;
\r
1270 string tagText = instance.Names.Get(av.avatar.ID, av.avatar.Name);
\r
1271 if (!string.IsNullOrEmpty(av.avatar.GroupName))
\r
1273 tagText = av.avatar.GroupName + "\n" + tagText;
\r
1275 var tSize = Printer.Measure(tagText, AvatarTagFont);
\r
1277 // Render tag backround
\r
1278 GL.Begin(BeginMode.Quads);
\r
1279 float halfWidth = tSize.BoundingBox.Width / 2 + 12;
\r
1280 float halfHeight = tSize.BoundingBox.Height / 2 + 5;
\r
1281 GL.Vertex2(screenPos.X - halfWidth, screenPos.Y - halfHeight);
\r
1282 GL.Vertex2(screenPos.X + halfWidth, screenPos.Y - halfHeight);
\r
1283 GL.Vertex2(screenPos.X + halfWidth, screenPos.Y + halfHeight);
\r
1284 GL.Vertex2(screenPos.X - halfWidth, screenPos.Y + halfHeight);
\r
1287 screenPos.Y = glControl.Height - screenPos.Y;
\r
1288 screenPos.X -= tSize.BoundingBox.Width / 2;
\r
1289 screenPos.Y -= tSize.BoundingBox.Height / 2 + 2;
\r
1291 if (screenPos.Y > 0)
\r
1294 Printer.Print(tagText, AvatarTagFont, Color.Orange,
\r
1295 new RectangleF(screenPos.X, screenPos.Y, tSize.BoundingBox.Width + 2, tSize.BoundingBox.Height + 2),
\r
1296 OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);
\r
1302 lock (SortedObjects)
\r
1305 foreach (SceneObject obj in SortedObjects)
\r
1307 if (!(obj is RenderPrimitive)) continue;
\r
1309 RenderPrimitive prim = (RenderPrimitive)obj;
\r
1312 if (!string.IsNullOrEmpty(prim.BasePrim.Text))
\r
1314 string text = System.Text.RegularExpressions.Regex.Replace(prim.BasePrim.Text, "(\r?\n)+", "\n");
\r
1315 OpenTK.Vector3 primPos = RHelp.TKVector3(prim.RenderPosition);
\r
1317 // Display hovertext only on objects that are withing 12m of the camera
\r
1318 if (prim.DistanceSquared > (12 * 12)) continue;
\r
1320 primPos.Z += prim.BasePrim.Scale.Z * 0.8f;
\r
1322 // Convert objects world position to 2D screen position in pixels
\r
1323 OpenTK.Vector3 screenPos;
\r
1324 if (!Math3D.GluProject(primPos, ModelMatrix, ProjectionMatrix, Viewport, out screenPos)) continue;
\r
1325 screenPos.Y = glControl.Height - screenPos.Y;
\r
1329 Color color = Color.FromArgb((int)(prim.BasePrim.TextColor.A * 255), (int)(prim.BasePrim.TextColor.R * 255), (int)(prim.BasePrim.TextColor.G * 255), (int)(prim.BasePrim.TextColor.B * 255));
\r
1331 var size = Printer.Measure(text, HoverTextFont);
\r
1332 screenPos.X -= size.BoundingBox.Width / 2;
\r
1333 screenPos.Y -= size.BoundingBox.Height;
\r
1335 if (screenPos.Y > 0)
\r
1339 if (color != Color.Black)
\r
1341 Printer.Print(text, HoverTextFont, Color.Black, new RectangleF(screenPos.X + 1, screenPos.Y + 1, size.BoundingBox.Width + 2, size.BoundingBox.Height + 2), OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);
\r
1344 Printer.Print(text, HoverTextFont, color, new RectangleF(screenPos.X, screenPos.Y, size.BoundingBox.Width + 2, size.BoundingBox.Height + 2), OpenTK.Graphics.TextPrinterOptions.Default, OpenTK.Graphics.TextAlignment.Center);
\r
1355 private void AddAvatarToScene(Avatar av)
\r
1359 if (Avatars.ContainsKey(av.LocalID))
\r
1361 // flag we got an update??
\r
1362 updateAVtes(Avatars[av.LocalID]);
\r
1366 GLAvatar ga = new GLAvatar();
\r
1369 RenderAvatar ra = new Rendering.RenderAvatar();
\r
1373 Avatars.Add(av.LocalID, ra);
\r
1374 ra.glavatar.morph(av);
\r
1380 private void updateAVtes(RenderAvatar ra)
\r
1382 if (ra.avatar.Textures == null)
\r
1385 int[] tes = { 8, 9, 10, 11, 19, 20 };
\r
1387 foreach (int fi in tes)
\r
1389 Primitive.TextureEntryFace TEF = ra.avatar.Textures.FaceTextures[fi];
\r
1393 if (ra.data[fi] == null || ra.data[fi].TextureInfo.TextureID != TEF.TextureID)
\r
1395 FaceData data = new FaceData();
\r
1396 ra.data[fi] = data;
\r
1397 data.TextureInfo.TextureID = TEF.TextureID;
\r
1399 DownloadTexture(new TextureLoadItem()
\r
1403 TeFace = ra.avatar.Textures.FaceTextures[fi]
\r
1409 private void RenderAvatarsSkeleton(RenderPass pass)
\r
1411 if (!RenderAvatarSkeleton) return;
\r
1415 foreach (RenderAvatar av in Avatars.Values)
\r
1417 // Individual prim matrix
\r
1420 // Prim roation and position
\r
1421 Vector3 pos = av.avatar.Position;
\r
1424 GL.MultMatrix(Math3D.CreateSRTMatrix(new Vector3(1, 1, 1), av.avatar.Rotation, pos));
\r
1426 GL.Begin(BeginMode.Lines);
\r
1428 GL.Color3(1.0, 0.0, 0.0);
\r
1430 foreach (Bone b in av.glavatar.skel.mBones.Values)
\r
1432 Vector3 newpos = b.getTotalOffset();
\r
1434 if (b.parent != null)
\r
1436 Vector3 parentpos = b.parent.getTotalOffset();
\r
1437 GL.Vertex3(parentpos.X, parentpos.Y, parentpos.Z);
\r
1441 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1444 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1449 newpos.X += 0.01f;
\r
1450 newpos.Y += 0.01f;
\r
1451 newpos.Z += 0.01f;
\r
1452 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1454 newpos.X -= 0.02f;
\r
1455 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1456 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1458 newpos.Y -= 0.02f;
\r
1459 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1460 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1462 newpos.X += 0.02f;
\r
1463 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1464 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1466 newpos.Y += 0.02f;
\r
1467 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1468 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1470 newpos.Z -= 0.02f;
\r
1471 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1472 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1474 newpos.Y -= 0.02f;
\r
1475 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1476 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1478 newpos.X -= 0.02f;
\r
1479 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1480 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1482 newpos.Y += 0.02f;
\r
1483 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1484 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1486 newpos.X += 0.02f;
\r
1487 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1488 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1490 newpos.Y -= 0.01f;
\r
1491 newpos.Z += 0.01f;
\r
1492 newpos.X -= 0.01f;
\r
1493 GL.Vertex3(newpos.X, newpos.Y, newpos.Z);
\r
1501 GL.Color3(0.0, 1.0, 0.0);
\r
1510 private void RenderAvatars(RenderPass pass)
\r
1512 if (!AvatarRenderingEnabled) return;
\r
1516 GL.EnableClientState(ArrayCap.VertexArray);
\r
1517 GL.EnableClientState(ArrayCap.TextureCoordArray);
\r
1518 GL.EnableClientState(ArrayCap.NormalArray);
\r
1521 foreach (RenderAvatar av in VisibleAvatars)
\r
1523 // need to rebuild mesh as animations may have changed rotations
\r
1524 if (av.glavatar.skel.mNeedsMeshRebuild)
\r
1526 av.glavatar.skel.mNeedsMeshRebuild = false;
\r
1529 av.glavatar.skel.animate(lastFrameTime);
\r
1533 if (av.glavatar._meshes.Count > 0)
\r
1536 foreach (GLMesh mesh in av.glavatar._meshes.Values)
\r
1538 if (av.glavatar.skel.mNeedsMeshRebuild)
\r
1540 mesh.applyjointweights();
\r
1544 if (!av.glavatar._showSkirt && mesh.Name == "skirtMesh")
\r
1547 if (mesh.Name == "hairMesh") // Don't render the hair mesh for the moment
\r
1550 GL.Color3(1f, 1f, 1f);
\r
1552 // Individual prim matrix
\r
1555 // Prim roation and position
\r
1556 GL.MultMatrix(Math3D.CreateSRTMatrix(new Vector3(1, 1, 1), av.RenderRotation, av.RenderPosition));
\r
1558 // Special case for eyeballs we need to offset the mesh to the correct position
\r
1559 // We have manually added the eyeball offset based on the headbone when we
\r
1560 // constructed the meshes, but why are the position offsets we got when loading
\r
1561 // the other meshes <0,7,0> ?
\r
1562 if (mesh.Name == "eyeBallLeftMesh")
\r
1564 // Mesh roation and position
\r
1565 GL.MultMatrix(Math3D.CreateSRTMatrix(new Vector3(1, 1, 1), av.glavatar.skel.mLeftEye.getTotalRotation(), av.glavatar.skel.mLeftEye.getTotalOffset()));
\r
1567 if (mesh.Name == "eyeBallRightMesh")
\r
1569 // Mesh roation and position
\r
1570 GL.MultMatrix(Math3D.CreateSRTMatrix(new Vector3(1, 1, 1), av.glavatar.skel.mRightEye.getTotalRotation(), av.glavatar.skel.mRightEye.getTotalOffset()));
\r
1573 //Should we be offsetting the base meshs at all?
\r
1574 //if (mesh.Name == "headMesh")
\r
1576 // GL.MultMatrix(Math3D.CreateTranslationMatrix(av.glavatar.skel.getDeltaOffset("mHead")));
\r
1580 if (pass == RenderPass.Picking)
\r
1582 GL.Disable(EnableCap.Texture2D);
\r
1584 for (int i = 0; i < av.data.Length; i++)
\r
1586 if (av.data[i] != null)
\r
1588 av.data[i].PickingID = avatarNr;
\r
1591 byte[] primNrBytes = Utils.Int16ToBytes((short)avatarNr);
\r
1592 byte[] faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)faceNr, 254 };
\r
1593 GL.Color4(faceColor);
\r
1597 if (av.data[mesh.teFaceID] == null)
\r
1599 GL.Disable(EnableCap.Texture2D);
\r
1603 if (mesh.teFaceID != 0)
\r
1605 GL.Enable(EnableCap.Texture2D);
\r
1606 GL.BindTexture(TextureTarget.Texture2D, av.data[mesh.teFaceID].TextureInfo.TexturePointer);
\r
1610 GL.Disable(EnableCap.Texture2D);
\r
1615 GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, mesh.RenderData.TexCoords);
\r
1616 GL.VertexPointer(3, VertexPointerType.Float, 0, mesh.RenderData.Vertices);
\r
1617 GL.NormalPointer(NormalPointerType.Float, 0, mesh.RenderData.Normals);
\r
1619 GL.DrawElements(BeginMode.Triangles, mesh.RenderData.Indices.Length, DrawElementsType.UnsignedShort, mesh.RenderData.Indices);
\r
1621 GL.BindTexture(TextureTarget.Texture2D, 0);
\r
1627 av.glavatar.skel.mNeedsMeshRebuild = false;
\r
1630 GL.Disable(EnableCap.Texture2D);
\r
1631 GL.DisableClientState(ArrayCap.NormalArray);
\r
1632 GL.DisableClientState(ArrayCap.VertexArray);
\r
1633 GL.DisableClientState(ArrayCap.TextureCoordArray);
\r
1637 #endregion avatars
\r
1640 bool TerrainModified = true;
\r
1641 float[,] heightTable = new float[256, 256];
\r
1643 ushort[] terrainIndices;
\r
1644 Vertex[] terrainVertices;
\r
1645 int terrainTexture = -1;
\r
1646 bool fetchingTerrainTexture = false;
\r
1647 Bitmap terrainImage = null;
\r
1648 int terrainVBO = -1;
\r
1649 int terrainIndexVBO = -1;
\r
1651 private void ResetTerrain()
\r
1653 ResetTerrain(true);
\r
1656 private void ResetTerrain(bool removeImage)
\r
1658 if (terrainImage != null)
\r
1660 terrainImage.Dispose();
\r
1661 terrainImage = null;
\r
1664 if (terrainVBO != -1)
\r
1666 GL.DeleteBuffers(1, ref terrainVBO);
\r
1670 if (terrainIndexVBO != -1)
\r
1672 GL.DeleteBuffers(1, ref terrainIndexVBO);
\r
1673 terrainIndexVBO = -1;
\r
1678 if (terrainTexture != -1)
\r
1680 GL.DeleteTexture(terrainTexture);
\r
1681 terrainTexture = -1;
\r
1685 fetchingTerrainTexture = false;
\r
1686 TerrainModified = true;
\r
1689 private void UpdateTerrain()
\r
1691 if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Terrain == null) return;
\r
1694 for (int x = 0; x < 255; x += step)
\r
1696 for (int y = 0; y < 255; y += step)
\r
1699 int patchNr = ((int)x / 16) * 16 + (int)y / 16;
\r
1700 if (Client.Network.CurrentSim.Terrain[patchNr] != null
\r
1701 && Client.Network.CurrentSim.Terrain[patchNr].Data != null)
\r
1703 float[] data = Client.Network.CurrentSim.Terrain[patchNr].Data;
\r
1704 z = data[(int)x % 16 * 16 + (int)y % 16];
\r
1706 heightTable[x, y] = z;
\r
1710 terrainFace = renderer.TerrainMesh(heightTable, 0f, 255f, 0f, 255f);
\r
1711 terrainVertices = terrainFace.Vertices.ToArray();
\r
1712 terrainIndices = terrainFace.Indices.ToArray();
\r
1714 TerrainModified = false;
\r
1717 void UpdateTerrainTexture()
\r
1719 if (!fetchingTerrainTexture)
\r
1721 fetchingTerrainTexture = true;
\r
1722 ThreadPool.QueueUserWorkItem(sync =>
\r
1724 Simulator sim = Client.Network.CurrentSim;
\r
1725 terrainImage = TerrainSplat.Splat(instance, heightTable,
\r
1726 new UUID[] { sim.TerrainDetail0, sim.TerrainDetail1, sim.TerrainDetail2, sim.TerrainDetail3 },
\r
1727 new float[] { sim.TerrainStartHeight00, sim.TerrainStartHeight01, sim.TerrainStartHeight10, sim.TerrainStartHeight11 },
\r
1728 new float[] { sim.TerrainHeightRange00, sim.TerrainHeightRange01, sim.TerrainHeightRange10, sim.TerrainHeightRange11 },
\r
1731 fetchingTerrainTexture = false;
\r
1736 private void RenderTerrain()
\r
1738 GL.Color3(1f, 1f, 1f);
\r
1739 GL.EnableClientState(ArrayCap.VertexArray);
\r
1740 GL.EnableClientState(ArrayCap.TextureCoordArray);
\r
1741 GL.EnableClientState(ArrayCap.NormalArray);
\r
1743 if (TerrainModified)
\r
1745 ResetTerrain(false);
\r
1747 UpdateTerrainTexture();
\r
1750 if (terrainImage != null)
\r
1752 if (terrainTexture != -1)
\r
1754 GL.DeleteTexture(terrainTexture);
\r
1757 terrainTexture = GLLoadImage(terrainImage, false);
\r
1758 terrainImage.Dispose();
\r
1759 terrainImage = null;
\r
1762 if (terrainTexture == -1)
\r
1768 GL.Enable(EnableCap.Texture2D);
\r
1769 GL.BindTexture(TextureTarget.Texture2D, terrainTexture);
\r
1776 fixed (float* normalPtr = &terrainVertices[0].Normal.X)
\r
1777 fixed (float* texPtr = &terrainVertices[0].TexCoord.X)
\r
1779 GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)normalPtr);
\r
1780 GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)texPtr);
\r
1781 GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, terrainVertices);
\r
1782 GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedShort, terrainIndices);
\r
1788 if (terrainVBO == -1)
\r
1790 GL.GenBuffers(1, out terrainVBO);
\r
1791 GL.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO);
\r
1792 GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(terrainVertices.Length * FaceData.VertexSize), terrainVertices, BufferUsageHint.StaticDraw);
\r
1796 GL.BindBuffer(BufferTarget.ArrayBuffer, terrainVBO);
\r
1799 if (terrainIndexVBO == -1)
\r
1801 GL.GenBuffers(1, out terrainIndexVBO);
\r
1802 GL.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO);
\r
1803 GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(terrainIndices.Length * sizeof(ushort)), terrainIndices, BufferUsageHint.StaticDraw);
\r
1807 GL.BindBuffer(BufferTarget.ElementArrayBuffer, terrainIndexVBO);
\r
1810 GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)12);
\r
1811 GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)(24));
\r
1812 GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, (IntPtr)(0));
\r
1814 GL.DrawElements(BeginMode.Triangles, terrainIndices.Length, DrawElementsType.UnsignedShort, IntPtr.Zero);
\r
1816 GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
\r
1817 GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
\r
1819 GL.BindTexture(TextureTarget.Texture2D, 0);
\r
1820 GL.DisableClientState(ArrayCap.VertexArray);
\r
1821 GL.DisableClientState(ArrayCap.TextureCoordArray);
\r
1822 GL.DisableClientState(ArrayCap.NormalArray);
\r
1824 #endregion Terrain
\r
1826 private void ResetMaterial()
\r
1828 GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Ambient, new float[] { 0.2f, 0.2f, 0.2f, 1.0f });
\r
1829 GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, new float[] { 0.8f, 0.8f, 0.8f, 1.0f });
\r
1830 GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Specular, new float[] { 0f, 0f, 0f, 1.0f });
\r
1831 GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0f, 0f, 0f, 1.0f });
\r
1832 GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Shininess, 0f);
\r
1835 float LODFactor(float distance, Vector3 primScale, float radius)
\r
1837 float scale = primScale.X;
\r
1838 if (primScale.Y > scale) scale = primScale.Y;
\r
1839 if (primScale.Z > scale) scale = primScale.Z;
\r
1840 return scale * radius * radius / distance;
\r
1843 void RenderSphere(float cx, float cy, float cz, float r, int p)
\r
1845 GL.PushAttrib(AttribMask.AllAttribBits);
\r
1846 GL.Disable(EnableCap.Fog);
\r
1847 GL.Disable(EnableCap.Texture2D);
\r
1848 GL.Disable(EnableCap.Dither);
\r
1849 GL.Disable(EnableCap.Lighting);
\r
1850 GL.Disable(EnableCap.LineStipple);
\r
1851 GL.Disable(EnableCap.PolygonStipple);
\r
1852 GL.Disable(EnableCap.CullFace);
\r
1853 GL.Disable(EnableCap.Blend);
\r
1854 GL.Disable(EnableCap.AlphaTest);
\r
1855 GL.Disable(EnableCap.DepthTest);
\r
1857 const float TWOPI = 6.28318530717958f;
\r
1858 const float PIDIV2 = 1.57079632679489f;
\r
1860 float theta1 = 0.0f;
\r
1861 float theta2 = 0.0f;
\r
1862 float theta3 = 0.0f;
\r
1872 // Disallow a negative number for radius.
\r
1876 // Disallow a negative number for precision.
\r
1880 // If the sphere is too small, just render a OpenGL point instead.
\r
1881 if (p < 4 || r <= 0)
\r
1883 GL.Begin(BeginMode.Points);
\r
1884 GL.Vertex3(cx, cy, cz);
\r
1889 for (int i = 0; i < p / 2; ++i)
\r
1891 theta1 = i * TWOPI / p - PIDIV2;
\r
1892 theta2 = (i + 1) * TWOPI / p - PIDIV2;
\r
1894 GL.Begin(BeginMode.TriangleStrip);
\r
1896 for (int j = 0; j <= p; ++j)
\r
1898 theta3 = j * TWOPI / p;
\r
1900 ex = (float)(Math.Cos(theta2) * Math.Cos(theta3));
\r
1901 ey = (float)Math.Sin(theta2);
\r
1902 ez = (float)(Math.Cos(theta2) * Math.Sin(theta3));
\r
1907 GL.Normal3(ex, ey, ez);
\r
1908 GL.TexCoord2(-(j / (float)p), 2 * (i + 1) / (float)p);
\r
1909 GL.Vertex3(px, py, pz);
\r
1911 ex = (float)(Math.Cos(theta1) * Math.Cos(theta3));
\r
1912 ey = (float)Math.Sin(theta1);
\r
1913 ez = (float)(Math.Cos(theta1) * Math.Sin(theta3));
\r
1918 GL.Normal3(ex, ey, ez);
\r
1919 GL.TexCoord2(-(j / (float)p), 2 * i / (float)p);
\r
1920 GL.Vertex3(px, py, pz);
\r
1928 void RenderPrim(RenderPrimitive mesh, RenderPass pass, int primNr)
\r
1930 if (!AvatarRenderingEnabled && mesh.Attached) return;
\r
1932 Primitive prim = mesh.Prim;
\r
1934 // Individual prim matrix
\r
1937 // Prim roation and position and scale
\r
1938 GL.MultMatrix(Math3D.CreateSRTMatrix(prim.Scale, mesh.RenderRotation, mesh.RenderPosition));
\r
1940 // Do we have animated texture on this face
\r
1941 bool animatedTexture = false;
\r
1943 // Initialise flags tracking what type of faces this prim has
\r
1944 if (pass == RenderPass.Simple)
\r
1946 mesh.HasSimpleFaces = false;
\r
1948 else if (pass == RenderPass.Alpha)
\r
1950 mesh.HasAlphaFaces = false;
\r
1953 // Draw the prim faces
\r
1954 for (int j = 0; j < mesh.Faces.Count; j++)
\r
1956 Primitive.TextureEntryFace teFace = mesh.Prim.Textures.GetFace((uint)j);
\r
1957 Face face = mesh.Faces[j];
\r
1958 FaceData data = (FaceData)mesh.Faces[j].UserData;
\r
1963 if (teFace == null)
\r
1966 // Don't render transparent faces
\r
1967 if (data.TextureInfo.FullAlpha || teFace.RGBA.A <= 0.01f) continue;
\r
1969 bool switchedLightsOff = false;
\r
1971 if (pass != RenderPass.Picking)
\r
1973 bool belongToAlphaPass = (teFace.RGBA.A < 0.99f) || (data.TextureInfo.HasAlpha && !data.TextureInfo.IsMask);
\r
1975 if (belongToAlphaPass && pass != RenderPass.Alpha) continue;
\r
1976 if (!belongToAlphaPass && pass == RenderPass.Alpha) continue;
\r
1978 if (pass == RenderPass.Simple)
\r
1980 mesh.HasSimpleFaces = true;
\r
1982 else if (pass == RenderPass.Alpha)
\r
1984 mesh.HasAlphaFaces = true;
\r
1987 if (teFace.Fullbright)
\r
1989 GL.Disable(EnableCap.Lighting);
\r
1990 switchedLightsOff = true;
\r
1993 switch (teFace.Shiny)
\r
1995 case Shininess.High:
\r
1996 GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0.94f);
\r
1999 case Shininess.Medium:
\r
2000 GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0.64f);
\r
2003 case Shininess.Low:
\r
2004 GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0.24f);
\r
2008 case Shininess.None:
\r
2010 GL.Material(MaterialFace.Front, MaterialParameter.Shininess, 0f);
\r
2014 var faceColor = new float[] { teFace.RGBA.R, teFace.RGBA.G, teFace.RGBA.B, teFace.RGBA.A };
\r
2015 GL.Color4(faceColor);
\r
2017 GL.Material(MaterialFace.Front, MaterialParameter.Specular, new float[] { 0.5f, 0.5f, 0.5f, 1f });
\r
2019 if (data.TextureInfo.TexturePointer == 0 && TexturesPtrMap.ContainsKey(teFace.TextureID))
\r
2021 data.TextureInfo = TexturesPtrMap[teFace.TextureID];
\r
2024 if (data.TextureInfo.TexturePointer == 0)
\r
2026 GL.Disable(EnableCap.Texture2D);
\r
2027 if (texturesRequestedThisFrame < 2 && !data.TextureInfo.FetchFailed)
\r
2029 texturesRequestedThisFrame++;
\r
2031 DownloadTexture(new TextureLoadItem()
\r
2041 // Is this face using texture animation
\r
2042 if ((prim.TextureAnim.Flags & Primitive.TextureAnimMode.ANIM_ON) != 0
\r
2043 && (prim.TextureAnim.Face == j || prim.TextureAnim.Face == 255))
\r
2045 if (data.AnimInfo == null)
\r
2047 data.AnimInfo = new TextureAnimationInfo();
\r
2049 data.AnimInfo.PrimAnimInfo = prim.TextureAnim;
\r
2050 data.AnimInfo.Step(lastFrameTime);
\r
2051 animatedTexture = true;
\r
2053 else if (data.AnimInfo != null) // Face texture not animated. Do we have previous anim setting?
\r
2055 data.AnimInfo = null;
\r
2058 GL.Enable(EnableCap.Texture2D);
\r
2059 GL.BindTexture(TextureTarget.Texture2D, data.TextureInfo.TexturePointer);
\r
2065 data.PickingID = primNr;
\r
2066 var primNrBytes = Utils.UInt16ToBytes((ushort)primNr);
\r
2067 var faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)j, 255 };
\r
2068 GL.Color4(faceColor);
\r
2073 Vertex[] verts = face.Vertices.ToArray();
\r
2074 ushort[] indices = face.Indices.ToArray();
\r
2078 fixed (float* normalPtr = &verts[0].Normal.X)
\r
2079 fixed (float* texPtr = &verts[0].TexCoord.X)
\r
2081 GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)normalPtr);
\r
2082 GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)texPtr);
\r
2083 GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, verts);
\r
2084 GL.DrawElements(BeginMode.Triangles, indices.Length, DrawElementsType.UnsignedShort, indices);
\r
2090 data.CheckVBO(face);
\r
2091 GL.BindBuffer(BufferTarget.ArrayBuffer, data.VertexVBO);
\r
2092 GL.BindBuffer(BufferTarget.ElementArrayBuffer, data.IndexVBO);
\r
2093 GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)12);
\r
2094 GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)(24));
\r
2095 GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, (IntPtr)(0));
\r
2097 GL.DrawElements(BeginMode.Triangles, face.Indices.Count, DrawElementsType.UnsignedShort, IntPtr.Zero);
\r
2099 GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
\r
2100 GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
\r
2104 if (switchedLightsOff)
\r
2106 GL.Enable(EnableCap.Lighting);
\r
2107 switchedLightsOff = false;
\r
2111 GL.BindTexture(TextureTarget.Texture2D, 0);
\r
2114 // Reset texture coordinates if we modified them in texture animation
\r
2115 if (animatedTexture)
\r
2117 GL.MatrixMode(MatrixMode.Texture);
\r
2118 GL.LoadIdentity();
\r
2119 GL.MatrixMode(MatrixMode.Modelview);
\r
2122 // Pop the prim matrix
\r
2126 void SortCullInterpolate()
\r
2128 SortedObjects = new List<SceneObject>();
\r
2129 VisibleAvatars = new List<RenderAvatar>();
\r
2130 if (OcclusionCullingEnabled)
\r
2132 OccludedObjects = new List<SceneObject>();
\r
2137 foreach (RenderPrimitive obj in Prims.Values)
\r
2139 obj.PositionCalculated = false;
\r
2142 // Calculate positions and rotations of root prims
\r
2143 // Perform interpolation om objects that survive culling
\r
2144 foreach (RenderPrimitive obj in Prims.Values)
\r
2146 if (obj.BasePrim.ParentID != 0) continue;
\r
2147 if (!obj.Initialized) obj.Initialize();
\r
2151 if (!obj.Meshing && meshingsRequestedThisFrame < 2)
\r
2153 meshingsRequestedThisFrame++;
\r
2159 obj.Step(lastFrameTime);
\r
2161 if (!obj.PositionCalculated)
\r
2163 PrimPosAndRot(obj, out obj.RenderPosition, out obj.RenderRotation);
\r
2164 obj.DistanceSquared = Vector3.DistanceSquared(Camera.RenderPosition, obj.RenderPosition);
\r
2165 obj.PositionCalculated = true;
\r
2168 if (!Frustum.ObjectInFrustum(obj.RenderPosition, obj.BoundingVolume, obj.BasePrim.Scale)) continue;
\r
2169 if (LODFactor(obj.DistanceSquared, obj.BasePrim.Scale, obj.BoundingVolume.R) < minLODFactor) continue;
\r
2171 obj.Attached = false;
\r
2172 if (OcclusionCullingEnabled && obj.Occluded())
\r
2174 OccludedObjects.Add(obj);
\r
2178 SortedObjects.Add(obj);
\r
2182 // Calculate avatar positions and perform interpolation tasks
\r
2185 foreach (RenderAvatar obj in Avatars.Values)
\r
2187 if (!obj.Initialized) obj.Initialize();
\r
2188 obj.Step(lastFrameTime);
\r
2189 PrimPosAndRot(obj, out obj.RenderPosition, out obj.RenderRotation);
\r
2190 obj.DistanceSquared = Vector3.DistanceSquared(Camera.RenderPosition, obj.RenderPosition);
\r
2191 obj.PositionCalculated = true;
\r
2193 if (!Frustum.ObjectInFrustum(obj.RenderPosition, obj.BoundingVolume, obj.BasePrim.Scale)) continue;
\r
2194 if (LODFactor(obj.DistanceSquared, obj.BasePrim.Scale, obj.BoundingVolume.R) < minLODFactor) continue;
\r
2196 VisibleAvatars.Add(obj);
\r
2197 // SortedObjects.Add(obj);
\r
2201 // Calculate position and rotations of child objects
\r
2202 foreach (RenderPrimitive obj in Prims.Values)
\r
2204 if (obj.BasePrim.ParentID == 0) continue;
\r
2205 if (!obj.Initialized) obj.Initialize();
\r
2209 if (!obj.Meshing && meshingsRequestedThisFrame < 2)
\r
2211 meshingsRequestedThisFrame++;
\r
2217 obj.Step(lastFrameTime);
\r
2219 if (!obj.PositionCalculated)
\r
2221 PrimPosAndRot(obj, out obj.RenderPosition, out obj.RenderRotation);
\r
2222 obj.DistanceSquared = Vector3.DistanceSquared(Camera.RenderPosition, obj.RenderPosition);
\r
2223 obj.PositionCalculated = true;
\r
2226 if (!Frustum.ObjectInFrustum(obj.RenderPosition, obj.BoundingVolume, obj.BasePrim.Scale)) continue;
\r
2227 if (LODFactor(obj.DistanceSquared, obj.BasePrim.Scale, obj.BoundingVolume.R) < minLODFactor) continue;
\r
2229 if (!obj.AttachedStateKnown)
\r
2231 obj.Attached = IsAttached(obj.BasePrim.ParentID);
\r
2232 obj.AttachedStateKnown = true;
\r
2235 if (OcclusionCullingEnabled && obj.Occluded())
\r
2237 OccludedObjects.Add(obj);
\r
2241 SortedObjects.Add(obj);
\r
2246 // RenderPrimitive class has IComparable implementation
\r
2247 // that allows sorting by distance
\r
2248 SortedObjects.Sort();
\r
2251 void RenderBoundingBox(SceneObject prim)
\r
2253 Vector3 scale = prim.BasePrim.Scale;
\r
2256 GL.MultMatrix(Math3D.CreateSRTMatrix(scale, prim.RenderRotation, prim.RenderPosition));
\r
2260 GL.DrawElements(BeginMode.Quads, RHelp.CubeIndices.Length, DrawElementsType.UnsignedShort, IntPtr.Zero);
\r
2264 GL.VertexPointer(3, VertexPointerType.Float, 0, RHelp.CubeVertices);
\r
2265 GL.DrawElements(BeginMode.Quads, RHelp.CubeIndices.Length, DrawElementsType.UnsignedShort, RHelp.CubeIndices);
\r
2270 int boundingBoxVBO = -1;
\r
2271 int boundingBoxVIndexVBO = -1;
\r
2273 private void RenderOccludedObjects()
\r
2275 if (!OcclusionCullingEnabled) return;
\r
2277 GL.EnableClientState(ArrayCap.VertexArray);
\r
2278 GL.ColorMask(false, false, false, false);
\r
2279 GL.Disable(EnableCap.CullFace);
\r
2280 GL.Disable(EnableCap.Lighting);
\r
2284 if (boundingBoxVBO == -1)
\r
2286 GL.GenBuffers(1, out boundingBoxVBO);
\r
2287 GL.BindBuffer(BufferTarget.ArrayBuffer, boundingBoxVBO);
\r
2288 GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(sizeof(float) * RHelp.CubeVertices.Length), RHelp.CubeVertices, BufferUsageHint.StaticDraw);
\r
2292 GL.BindBuffer(BufferTarget.ArrayBuffer, boundingBoxVBO);
\r
2295 if (boundingBoxVIndexVBO == -1)
\r
2297 GL.GenBuffers(1, out boundingBoxVIndexVBO);
\r
2298 GL.BindBuffer(BufferTarget.ElementArrayBuffer, boundingBoxVIndexVBO);
\r
2299 GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(sizeof(ushort) * RHelp.CubeIndices.Length), RHelp.CubeIndices, BufferUsageHint.StaticDraw);
\r
2303 GL.BindBuffer(BufferTarget.ElementArrayBuffer, boundingBoxVIndexVBO);
\r
2306 GL.VertexPointer(3, VertexPointerType.Float, 0, (IntPtr)0);
\r
2309 foreach (SceneObject obj in OccludedObjects)
\r
2311 if ((!obj.HasAlphaFaces && !obj.HasSimpleFaces)) continue;
\r
2312 obj.HasSimpleFaces = true;
\r
2313 obj.HasAlphaFaces = false;
\r
2314 obj.StartSimpleQuery();
\r
2315 RenderBoundingBox(obj);
\r
2316 obj.EndSimpleQuery();
\r
2321 GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
\r
2322 GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
\r
2325 GL.ColorMask(true, true, true, true);
\r
2326 GL.DisableClientState(ArrayCap.VertexArray);
\r
2327 GL.Enable(EnableCap.CullFace);
\r
2328 GL.Enable(EnableCap.Lighting);
\r
2331 private void RenderObjects(RenderPass pass)
\r
2333 if (!PrimitiveRenderingEnabled) return;
\r
2335 GL.EnableClientState(ArrayCap.VertexArray);
\r
2336 GL.EnableClientState(ArrayCap.TextureCoordArray);
\r
2337 GL.EnableClientState(ArrayCap.NormalArray);
\r
2339 Vector3 myPos = Vector3.Zero;
\r
2341 if (Avatars.TryGetValue(Client.Self.LocalID, out me))
\r
2343 myPos = me.RenderPosition;
\r
2347 myPos = Client.Self.SimPosition;
\r
2350 int nrPrims = SortedObjects.Count;
\r
2351 for (int i = 0; i < nrPrims; i++)
\r
2353 //RenderBoundingBox(SortedPrims[i]);
\r
2355 // When rendering alpha faces, draw from back towards the camers
\r
2356 // otherwise from those closest to camera, to the farthest
\r
2357 int ix = pass == RenderPass.Alpha ? nrPrims - i - 1 : i;
\r
2358 SceneObject obj = SortedObjects[ix];
\r
2360 if (obj is RenderPrimitive)
\r
2362 // Don't render objects that are outside the draw distane
\r
2363 if (Vector3.DistanceSquared(myPos, obj.RenderPosition) > drawDistanceSquared) continue;
\r
2364 obj.StartQuery(pass);
\r
2365 RenderPrim((RenderPrimitive)obj, pass, ix);
\r
2366 obj.EndQuery(pass);
\r
2370 GL.Disable(EnableCap.Texture2D);
\r
2371 GL.DisableClientState(ArrayCap.VertexArray);
\r
2372 GL.DisableClientState(ArrayCap.TextureCoordArray);
\r
2373 GL.DisableClientState(ArrayCap.NormalArray);
\r
2376 void DrawWaterQuad(float x, float y, float z)
\r
2378 GL.Vertex3(x, y, z);
\r
2379 GL.Vertex3(x + 256f, y, z);
\r
2380 GL.Vertex3(x + 256f, y + 256f, z);
\r
2381 GL.Vertex3(x, y + 256f, z);
\r
2384 public void RenderWater()
\r
2386 float z = Client.Network.CurrentSim.WaterHeight;
\r
2388 GL.Color4(0.09f, 0.28f, 0.63f, 0.84f);
\r
2390 GL.Begin(BeginMode.Quads);
\r
2391 for (float x = -256f * 2; x <= 256 * 2; x += 256f)
\r
2392 for (float y = -256f * 2; y <= 256 * 2; y += 256f)
\r
2393 DrawWaterQuad(x, y, z);
\r
2397 int texturesRequestedThisFrame;
\r
2398 int meshingsRequestedThisFrame;
\r
2400 private void Render(bool picking)
\r
2404 GL.ClearColor(1f, 1f, 1f, 1f);
\r
2408 GL.ClearColor(0.39f, 0.58f, 0.93f, 1.0f);
\r
2411 GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
\r
2412 GL.LoadIdentity();
\r
2414 // Setup wireframe or solid fill drawing mode
\r
2415 if (Wireframe && !picking)
\r
2417 GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
\r
2421 GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
\r
2424 var mLookAt = OpenTK.Matrix4d.LookAt(
\r
2425 Camera.RenderPosition.X, Camera.RenderPosition.Y, Camera.RenderPosition.Z,
\r
2426 Camera.RenderFocalPoint.X, Camera.RenderFocalPoint.Y, Camera.RenderFocalPoint.Z,
\r
2428 GL.MultMatrix(ref mLookAt);
\r
2430 GL.Light(LightName.Light0, LightParameter.Position, lightPos);
\r
2432 // Push the world matrix
\r
2435 if (Camera.Modified)
\r
2437 GL.GetFloat(GetPName.ProjectionMatrix, out ProjectionMatrix);
\r
2438 GL.GetFloat(GetPName.ModelviewMatrix, out ModelMatrix);
\r
2439 GL.GetInteger(GetPName.Viewport, Viewport);
\r
2440 Frustum.CalculateFrustum(ProjectionMatrix, ModelMatrix);
\r
2442 Camera.Modified = false;
\r
2443 Camera.Step(lastFrameTime);
\r
2446 SortCullInterpolate();
\r
2450 GL.Disable(EnableCap.Lighting);
\r
2451 RenderObjects(RenderPass.Picking);
\r
2452 RenderAvatars(RenderPass.Picking);
\r
2453 GL.Enable(EnableCap.Lighting);
\r
2457 texturesRequestedThisFrame = 0;
\r
2458 meshingsRequestedThisFrame = 0;
\r
2460 // Alpha mask elements, no blending, alpha test for A > 0.5
\r
2461 GL.Enable(EnableCap.AlphaTest);
\r
2463 RenderObjects(RenderPass.Simple);
\r
2464 RenderAvatarsSkeleton(RenderPass.Simple);
\r
2465 RenderAvatars(RenderPass.Simple);
\r
2466 GL.Disable(EnableCap.AlphaTest);
\r
2468 GL.DepthMask(false);
\r
2469 RenderOccludedObjects();
\r
2471 // Alpha blending elements, disable writing to depth buffer
\r
2472 GL.Enable(EnableCap.Blend);
\r
2474 RenderObjects(RenderPass.Alpha);
\r
2475 GL.DepthMask(true);
\r
2481 GL.Disable(EnableCap.Blend);
\r
2484 // Pop the world matrix
\r
2488 private void GluPerspective(float fovy, float aspect, float zNear, float zFar)
\r
2490 float fH = (float)Math.Tan(fovy / 360 * (float)Math.PI) * zNear;
\r
2491 float fW = fH * aspect;
\r
2492 GL.Frustum(-fW, fW, -fH, fH, zNear, zFar);
\r
2495 private bool TryPick(int x, int y, out object picked, out int faceID)
\r
2497 // Save old attributes
\r
2498 GL.PushAttrib(AttribMask.AllAttribBits);
\r
2500 // Disable some attributes to make the objects flat / solid color when they are drawn
\r
2501 GL.Disable(EnableCap.Fog);
\r
2502 GL.Disable(EnableCap.Texture2D);
\r
2503 GL.Disable(EnableCap.Dither);
\r
2504 GL.Disable(EnableCap.Lighting);
\r
2505 GL.Disable(EnableCap.LineStipple);
\r
2506 GL.Disable(EnableCap.PolygonStipple);
\r
2507 GL.Disable(EnableCap.CullFace);
\r
2508 GL.Disable(EnableCap.Blend);
\r
2509 GL.Disable(EnableCap.AlphaTest);
\r
2513 byte[] color = new byte[4];
\r
2514 GL.ReadPixels(x, glControl.Height - y, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, color);
\r
2518 int primID = Utils.BytesToUInt16(color, 0);
\r
2519 faceID = color[2];
\r
2523 if (color[3] == 254) // Avatar
\r
2525 lock (VisibleAvatars)
\r
2527 foreach (var avatar in VisibleAvatars)
\r
2529 for (int i = 0; i < avatar.data.Length; i++)
\r
2531 var face = avatar.data[i];
\r
2532 if (face != null && face.PickingID == primID)
\r
2541 if (picked != null)
\r
2547 if (color[3] == 255) // Prim
\r
2549 lock (SortedObjects)
\r
2551 foreach (SceneObject obj in SortedObjects)
\r
2553 if (!(obj is RenderPrimitive)) continue;
\r
2554 RenderPrimitive prim = (RenderPrimitive)obj;
\r
2556 foreach (var face in prim.Faces)
\r
2558 if (face.UserData == null) continue;
\r
2559 if (((FaceData)face.UserData).PickingID == primID)
\r
2566 if (picked != null) break;
\r
2571 return picked != null;
\r
2574 public void DownloadTexture(TextureLoadItem item)
\r
2576 lock (TexturesPtrMap)
\r
2578 if (TexturesPtrMap.ContainsKey(item.TeFace.TextureID))
\r
2580 item.Data.TextureInfo = TexturesPtrMap[item.TeFace.TextureID];
\r
2584 TexturesPtrMap[item.TeFace.TextureID] = item.Data.TextureInfo;
\r
2586 if (item.TextureData == null && item.TGAData == null)
\r
2588 if (CacheDecodedTextures && RHelp.LoadCachedImage(item.TeFace.TextureID, out item.TGAData, out item.Data.TextureInfo.HasAlpha, out item.Data.TextureInfo.FullAlpha, out item.Data.TextureInfo.IsMask))
\r
2590 PendingTextures.Enqueue(item);
\r
2592 else if (Client.Assets.Cache.HasAsset(item.Data.TextureInfo.TextureID))
\r
2594 item.LoadAssetFromCache = true;
\r
2595 PendingTextures.Enqueue(item);
\r
2597 else if (!item.Data.TextureInfo.FetchFailed)
\r
2599 Client.Assets.RequestImage(item.TeFace.TextureID, (state, asset) =>
\r
2603 case TextureRequestState.Finished:
\r
2604 item.TextureData = asset.AssetData;
\r
2605 PendingTextures.Enqueue(item);
\r
2608 case TextureRequestState.Aborted:
\r
2609 case TextureRequestState.NotFound:
\r
2610 case TextureRequestState.Timeout:
\r
2611 item.Data.TextureInfo.FetchFailed = true;
\r
2619 PendingTextures.Enqueue(item);
\r
2625 private void CalculateBoundingBox(RenderPrimitive rprim)
\r
2627 Primitive prim = rprim.BasePrim;
\r
2629 // Calculate bounding volumes for each prim and adjust textures
\r
2630 rprim.BoundingVolume = new BoundingVolume();
\r
2631 for (int j = 0; j < rprim.Faces.Count; j++)
\r
2633 Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j);
\r
2634 if (teFace == null) continue;
\r
2636 Face face = rprim.Faces[j];
\r
2637 FaceData data = new FaceData();
\r
2639 data.BoundingVolume.CreateBoundingVolume(face);
\r
2640 rprim.BoundingVolume.AddVolume(data.BoundingVolume);
\r
2642 // With linear texture animation in effect, texture repeats and offset are ignored
\r
2643 if ((prim.TextureAnim.Flags & Primitive.TextureAnimMode.ANIM_ON) != 0
\r
2644 && (prim.TextureAnim.Flags & Primitive.TextureAnimMode.ROTATE) == 0
\r
2645 && (prim.TextureAnim.Face == 255 || prim.TextureAnim.Face == j))
\r
2647 teFace.RepeatU = 1;
\r
2648 teFace.RepeatV = 1;
\r
2649 teFace.OffsetU = 0;
\r
2650 teFace.OffsetV = 0;
\r
2653 // Need to adjust UV for spheres as they are sort of half-prim
\r
2654 if (prim.PrimData.ProfileCurve == ProfileCurve.HalfCircle)
\r
2656 teFace = (Primitive.TextureEntryFace)teFace.Clone();
\r
2657 teFace.RepeatV *= 2;
\r
2658 teFace.OffsetV += 0.5f;
\r
2661 // Sculpt UV vertically flipped compared to prims. Flip back
\r
2662 if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero && prim.Sculpt.Type != SculptType.Mesh)
\r
2664 teFace = (Primitive.TextureEntryFace)teFace.Clone();
\r
2665 teFace.RepeatV *= -1;
\r
2668 // Texture transform for this face
\r
2669 renderer.TransformTexCoords(face.Vertices, face.Center, teFace);
\r
2671 // Set the UserData for this face to our FaceData struct
\r
2672 face.UserData = data;
\r
2673 rprim.Faces[j] = face;
\r
2677 private void MeshPrim(RenderPrimitive rprim)
\r
2679 if (rprim.Meshing) return;
\r
2681 rprim.Meshing = true;
\r
2682 Primitive prim = rprim.BasePrim;
\r
2685 if (prim.Sculpt == null || prim.Sculpt.SculptTexture == UUID.Zero)
\r
2687 FacetedMesh mesh = renderer.GenerateFacetedMesh(prim, DetailLevel.High);
\r
2688 rprim.Faces = mesh.Faces;
\r
2689 CalculateBoundingBox(rprim);
\r
2690 rprim.Meshed = true;
\r
2691 rprim.Meshing = false;
\r
2695 PendingTasks.Enqueue(new GenericTask(() =>
\r
2697 FacetedMesh mesh = null;
\r
2701 if (prim.Sculpt.Type != SculptType.Mesh)
\r
2702 { // Regular sculptie
\r
2705 lock (sculptCache)
\r
2707 if (sculptCache.ContainsKey(prim.Sculpt.SculptTexture))
\r
2709 img = sculptCache[prim.Sculpt.SculptTexture];
\r
2715 if (LoadTexture(prim.Sculpt.SculptTexture, ref img, true))
\r
2717 sculptCache[prim.Sculpt.SculptTexture] = (Bitmap)img;
\r
2725 mesh = renderer.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.High);
\r
2729 AutoResetEvent gotMesh = new AutoResetEvent(false);
\r
2731 Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) =>
\r
2733 if (!success || !FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out mesh))
\r
2735 Logger.Log("Failed to fetch or decode the mesh asset", Helpers.LogLevel.Warning, Client);
\r
2740 gotMesh.WaitOne(20 * 1000, false);
\r
2748 rprim.Faces = mesh.Faces;
\r
2749 CalculateBoundingBox(rprim);
\r
2750 rprim.Meshed = true;
\r
2751 rprim.Meshing = false;
\r
2757 Prims.Remove(rprim.BasePrim.LocalID);
\r
2765 private void UpdatePrimBlocking(Primitive prim)
\r
2767 if (!RenderingEnabled) return;
\r
2769 if (AvatarRenderingEnabled && prim.PrimData.PCode == PCode.Avatar)
\r
2771 AddAvatarToScene(Client.Network.CurrentSim.ObjectsAvatars[prim.LocalID]);
\r
2776 if (prim.PrimData.PCode != PCode.Prim) return;
\r
2777 if (!PrimitiveRenderingEnabled) return;
\r
2779 if (prim.Textures == null) return;
\r
2781 RenderPrimitive rPrim = null;
\r
2782 if (Prims.TryGetValue(prim.LocalID, out rPrim))
\r
2784 rPrim.AttachedStateKnown = false;
\r
2788 rPrim = new RenderPrimitive();
\r
2791 rPrim.Prim = prim;
\r
2792 rPrim.Meshed = false;
\r
2793 lock (Prims) Prims[prim.LocalID] = rPrim;
\r
2796 private bool LoadTexture(UUID textureID, ref Image texture, bool removeAlpha)
\r
2798 ManualResetEvent gotImage = new ManualResetEvent(false);
\r
2804 bool hasAlpha, fullAlpha, isMask;
\r
2806 if (RHelp.LoadCachedImage(textureID, out tgaData, out hasAlpha, out fullAlpha, out isMask))
\r
2808 img = LoadTGAClass.LoadTGA(new MemoryStream(tgaData));
\r
2812 instance.Client.Assets.RequestImage(textureID, (TextureRequestState state, AssetTexture assetTexture) =>
\r
2814 if (state == TextureRequestState.Finished)
\r
2817 OpenJPEG.DecodeToImage(assetTexture.AssetData, out mi);
\r
2821 if ((mi.Channels & ManagedImage.ImageChannels.Alpha) != 0)
\r
2823 mi.ConvertChannels(mi.Channels & ~ManagedImage.ImageChannels.Alpha);
\r
2826 tgaData = mi.ExportTGA();
\r
2827 img = LoadTGAClass.LoadTGA(new MemoryStream(tgaData));
\r
2828 RHelp.SaveCachedImage(tgaData, textureID, (mi.Channels & ManagedImage.ImageChannels.Alpha) != 0, false, false);
\r
2833 gotImage.WaitOne(30 * 1000, false);
\r
2842 catch (Exception e)
\r
2844 Logger.Log(e.Message, Helpers.LogLevel.Error, instance.Client, e);
\r
2848 #endregion Private methods (the meat)
\r
2850 #region Form controls handlers
\r
2851 private void chkWireFrame_CheckedChanged(object sender, EventArgs e)
\r
2853 Wireframe = chkWireFrame.Checked;
\r
2856 private void btnReset_Click(object sender, EventArgs e)
\r
2861 private void cbAA_CheckedChanged(object sender, EventArgs e)
\r
2863 instance.GlobalSettings["use_multi_sampling"] = UseMultiSampling = cbAA.Checked;
\r
2867 #endregion Form controls handlers
\r
2869 #region Context menu
\r
2871 /// Dynamically construct the context menu when we right click on the screen
\r
2873 /// <param name="csender"></param>
\r
2874 /// <param name="ce"></param>
\r
2875 private void ctxObjects_Opening(object csender, System.ComponentModel.CancelEventArgs ce)
\r
2877 // Clear all context menu items
\r
2878 ctxMenu.Items.Clear();
\r
2879 ToolStripMenuItem item;
\r
2881 // Was it prim that was right clicked
\r
2882 if (RightclickedObject != null && RightclickedObject is RenderPrimitive)
\r
2884 RenderPrimitive prim = (RenderPrimitive)RightclickedObject;
\r
2886 // Sit/stand up button handling
\r
2887 item = new ToolStripMenuItem("Sit", null, (sender, e) =>
\r
2889 if (!instance.State.IsSitting)
\r
2891 instance.State.SetSitting(true, prim.Prim.ID);
\r
2895 instance.State.SetSitting(false, UUID.Zero);
\r
2899 if (instance.State.IsSitting)
\r
2901 item.Text = "Stand up";
\r
2903 else if (prim.Prim.Properties != null
\r
2904 && !string.IsNullOrEmpty(prim.Prim.Properties.SitName))
\r
2906 item.Text = prim.Prim.Properties.SitName;
\r
2908 ctxMenu.Items.Add(item);
\r
2910 // Is the prim touchable
\r
2911 if ((prim.Prim.Flags & PrimFlags.Touch) != 0)
\r
2913 item = new ToolStripMenuItem("Touch", null, (sender, e) =>
\r
2915 Client.Self.Grab(prim.Prim.LocalID, Vector3.Zero, Vector3.Zero, Vector3.Zero, RightclickedFaceID, Vector3.Zero, Vector3.Zero, Vector3.Zero);
\r
2916 Thread.Sleep(100);
\r
2917 Client.Self.DeGrab(prim.Prim.LocalID);
\r
2920 if (prim.Prim.Properties != null
\r
2921 && !string.IsNullOrEmpty(prim.Prim.Properties.TouchName))
\r
2923 item.Text = prim.Prim.Properties.TouchName;
\r
2925 ctxMenu.Items.Add(item);
\r
2928 // Can I modify this object?
\r
2929 if ((prim.Prim.Flags & PrimFlags.ObjectModify) != 0)
\r
2932 item = new ToolStripMenuItem("Take", null, (sender, e) =>
\r
2934 instance.MediaManager.PlayUISound(UISounds.ObjectDelete);
\r
2935 Client.Inventory.RequestDeRezToInventory(prim.Prim.LocalID);
\r
2937 ctxMenu.Items.Add(item);
\r
2940 item = new ToolStripMenuItem("Delete", null, (sender, e) =>
\r
2942 instance.MediaManager.PlayUISound(UISounds.ObjectDelete);
\r
2943 Client.Inventory.RequestDeRezToInventory(prim.Prim.LocalID, DeRezDestination.AgentInventoryTake, Client.Inventory.FindFolderForType(AssetType.TrashFolder), UUID.Random());
\r
2945 ctxMenu.Items.Add(item);
\r
2951 // If we are not the sole menu item, add separator
\r
2952 if (ctxMenu.Items.Count > 0)
\r
2954 ctxMenu.Items.Add(new ToolStripSeparator());
\r
2958 // Dock/undock menu item
\r
2959 bool docked = !instance.TabConsole.Tabs["scene_window"].Detached;
\r
2962 item = new ToolStripMenuItem("Undock", null, (sender, e) =>
\r
2964 instance.TabConsole.SelectDefaultTab();
\r
2965 instance.TabConsole.Tabs["scene_window"].Detach(instance);
\r
2970 item = new ToolStripMenuItem("Dock", null, (sender, e) =>
\r
2972 Control p = Parent;
\r
2973 instance.TabConsole.Tabs["scene_window"].AttachTo(instance.TabConsole.tstTabs, instance.TabConsole.toolStripContainer1.ContentPanel);
\r
2976 ((Form)p).Close();
\r
2980 ctxMenu.Items.Add(item);
\r
2982 #endregion Context menu
\r
2984 private void hsAmbient_Scroll(object sender, ScrollEventArgs e)
\r
2986 ambient = (float)hsAmbient.Value / 100f;
\r
2990 private void hsDiffuse_Scroll(object sender, ScrollEventArgs e)
\r
2992 difuse = (float)hsDiffuse.Value / 100f;
\r
2996 private void hsSpecular_Scroll(object sender, ScrollEventArgs e)
\r
2998 specular = (float)hsSpecular.Value / 100f;
\r
3002 private void hsLOD_Scroll(object sender, ScrollEventArgs e)
\r
3004 minLODFactor = (float)hsLOD.Value / 5000f;
\r
3007 private void button_vparam_Click(object sender, EventArgs e)
\r
3009 //int paramid = int.Parse(textBox_vparamid.Text);
\r
3010 //float weight = (float)hScrollBar_weight.Value/100f;
\r
3011 float weightx = float.Parse(textBox_x.Text);
\r
3012 float weighty = float.Parse(textBox_y.Text);
\r
3013 float weightz = float.Parse(textBox_z.Text);
\r
3015 foreach (RenderAvatar av in Avatars.Values)
\r
3017 //av.glavatar.morphtest(av.avatar,paramid,weight);
\r
3018 av.glavatar.skel.deformbone(comboBox1.Text, new Vector3(0, 0, 0), new Vector3(float.Parse(textBox_sx.Text), float.Parse(textBox_sy.Text), float.Parse(textBox_sz.Text)), Quaternion.CreateFromEulers((float)(Math.PI * (weightx / 180)), (float)(Math.PI * (weighty / 180)), (float)(Math.PI * (weightz / 180))));
\r
3020 foreach (GLMesh mesh in av.glavatar._meshes.Values)
\r
3022 mesh.applyjointweights();
\r
3028 private void textBox_vparamid_TextChanged(object sender, EventArgs e)
\r
3033 private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
\r
3036 string bone = comboBox1.Text;
\r
3037 foreach (RenderAvatar av in Avatars.Values)
\r
3040 if (av.glavatar.skel.mBones.TryGetValue(bone, out b))
\r
3042 textBox_sx.Text = (b.scale.X - 1.0f).ToString();
\r
3043 textBox_sy.Text = (b.scale.Y - 1.0f).ToString();
\r
3044 textBox_sz.Text = (b.scale.Z - 1.0f).ToString();
\r
3047 b.rot.GetEulerAngles(out x, out y, out z);
\r
3048 textBox_x.Text = x.ToString();
\r
3049 textBox_y.Text = y.ToString();
\r
3050 textBox_z.Text = z.ToString();
\r
3059 private void textBox_y_TextChanged(object sender, EventArgs e)
\r
3064 private void textBox_z_TextChanged(object sender, EventArgs e)
\r
3069 private void comboBox_morph_SelectedIndexChanged(object sender, EventArgs e)
\r
3074 private void button1_Click(object sender, EventArgs e)
\r
3076 foreach (RenderAvatar av in Avatars.Values)
\r
3079 foreach (VisualParamEx vpe in VisualParamEx.morphParams.Values)
\r
3081 if (vpe.Name == comboBox_morph.Text)
\r
3088 av.glavatar.morphtest(av.avatar, id, float.Parse(textBox_morphamount.Text));
\r
3090 foreach (GLMesh mesh in av.glavatar._meshes.Values)
\r
3092 mesh.applyjointweights();
\r
3101 private void gbZoom_Enter(object sender, EventArgs e)
\r
3106 private void button_driver_Click(object sender, EventArgs e)
\r
3108 foreach (RenderAvatar av in Avatars.Values)
\r
3111 foreach (VisualParamEx vpe in VisualParamEx.drivenParams.Values)
\r
3113 if (vpe.Name == comboBox_driver.Text)
\r
3120 av.glavatar.morphtest(av.avatar, id, float.Parse(textBox_driveramount.Text));
\r
3122 foreach (GLMesh mesh in av.glavatar._meshes.Values)
\r
3124 mesh.applyjointweights();
\r
3131 private void tbDrawDistance_Scroll(object sender, EventArgs e)
\r
3133 DrawDistance = (float)tbDrawDistance.Value;
\r
3134 lblDrawDistance.Text = string.Format("Draw distance: {0}", tbDrawDistance.Value);
\r
3138 bool miscEnabled = true;
\r
3139 private void cbMisc_CheckedChanged(object sender, EventArgs e)
\r
3141 miscEnabled = cbMisc.Checked;
\r
3142 OcclusionCullingEnabled = miscEnabled;
\r