/// <summary>\r
/// Render avatars\r
/// </summary>\r
- public bool AvatarRenderingEnabled = false;\r
+ public bool AvatarRenderingEnabled = true;\r
\r
/// <summary>\r
/// Show avatar skeloton\r
MeshmerizerR renderer;\r
OpenTK.Graphics.GraphicsMode GLMode = null;\r
AutoResetEvent TextureThreadContextReady = new AutoResetEvent(false);\r
+ \r
+ delegate void GenericTask();\r
+ BlockingQueue<GenericTask> PendingTasks = new BlockingQueue<GenericTask>();\r
+ Thread genericTaskThread;\r
+\r
BlockingQueue<TextureLoadItem> PendingTextures = new BlockingQueue<TextureLoadItem>();\r
\r
bool hasMipmap;\r
\r
this.instance = instance;\r
\r
+ genericTaskThread = new Thread(new ThreadStart(GenericTaskRunner));\r
+ genericTaskThread.IsBackground = true;\r
+ genericTaskThread.Name = "Generic task queue";\r
+ genericTaskThread.Start();\r
+\r
renderer = new MeshmerizerR();\r
renderTimer = new System.Diagnostics.Stopwatch();\r
renderTimer.Start();\r
Client.Avatars.AvatarAppearance -= new EventHandler<AvatarAppearanceEventArgs>(Avatars_AvatarAppearance);\r
Client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);\r
\r
+ PendingTasks.Close();\r
+ if (genericTaskThread != null)\r
+ {\r
+ genericTaskThread.Join(2000);\r
+ genericTaskThread = null;\r
+ }\r
+\r
if (instance.Netcom != null)\r
{\r
Instance.Netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(Netcom_ClientDisconnected);\r
\r
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r
item.Data.TextureInfo.TexturePointer = GLLoadImage(bitmap, item.Data.TextureInfo.HasAlpha);\r
+ GL.Flush();\r
bitmap.Dispose();\r
}\r
\r
}\r
#endregion Texture thread\r
\r
+ void GenericTaskRunner()\r
+ {\r
+ PendingTasks.Open();\r
+ Logger.DebugLog("Started generic task thread");\r
+\r
+ while (true)\r
+ {\r
+ GenericTask task = null;\r
+ if (!PendingTasks.Dequeue(Timeout.Infinite, ref task)) break;\r
+ task.Invoke();\r
+ }\r
+ Logger.DebugLog("Generic task thread exited");\r
+ }\r
+\r
void LoadCurrentPrims()\r
{\r
if (!Client.Network.Connected) return;\r
// This is a FIR filter known as a MMA or Modified Mean Average, using a 20 point sampling width\r
advTimerTick = ((19 * advTimerTick) + lastFrameTime) / 20;\r
// Stats in window title for now\r
- Text = String.Format("Scene Viewer: FPS {0:000.00} Texture decode queue: {1}", 1d / advTimerTick, PendingTextures.Count);\r
+ Text = String.Format("Scene Viewer: FPS {0:000.00} Texture decode queue: {1}, Sculpt queue: {2}",\r
+ 1d / advTimerTick,\r
+ PendingTextures.Count,\r
+ PendingTasks.Count);\r
+\r
#if TURNS_OUT_PRINTER_IS_EXPENISVE\r
int posX = glControl.Width - 100;\r
int posY = 0;\r
{\r
if (obj.BasePrim.ParentID != 0) continue;\r
if (!obj.Initialized) obj.Initialize();\r
+\r
+ if (!obj.Meshed)\r
+ {\r
+ if (!obj.Meshing && meshingsRequestedThisFrame < 2)\r
+ {\r
+ meshingsRequestedThisFrame++;\r
+ MeshPrim(obj);\r
+ }\r
+ continue;\r
+ }\r
+\r
obj.Step(lastFrameTime);\r
\r
if (!obj.PositionCalculated)\r
{\r
if (obj.BasePrim.ParentID == 0) continue;\r
if (!obj.Initialized) obj.Initialize();\r
+\r
+ if (!obj.Meshed)\r
+ {\r
+ if (!obj.Meshing && meshingsRequestedThisFrame < 2)\r
+ {\r
+ meshingsRequestedThisFrame++;\r
+ MeshPrim(obj);\r
+ }\r
+ continue;\r
+ }\r
+\r
obj.Step(lastFrameTime);\r
\r
if (!obj.PositionCalculated)\r
}\r
\r
int texturesRequestedThisFrame;\r
+ int meshingsRequestedThisFrame;\r
\r
private void Render(bool picking)\r
{\r
else\r
{\r
texturesRequestedThisFrame = 0;\r
+ meshingsRequestedThisFrame = 0;\r
\r
// Alpha mask elements, no blending, alpha test for A > 0.5\r
GL.Enable(EnableCap.AlphaTest);\r
}\r
}\r
\r
- private void MeshPrim(Primitive prim, RenderPrimitive rprim)\r
+ private void CalculateBoundingBox(RenderPrimitive rprim)\r
{\r
+ Primitive prim = rprim.BasePrim;\r
+\r
// Calculate bounding volumes for each prim and adjust textures\r
rprim.BoundingVolume = new BoundingVolume();\r
for (int j = 0; j < rprim.Faces.Count; j++)\r
// Set the UserData for this face to our FaceData struct\r
face.UserData = data;\r
rprim.Faces[j] = face;\r
-\r
- //DownloadTexture(new TextureLoadItem()\r
- //{\r
- // Data = data,\r
- // Prim = prim,\r
- // TeFace = teFace\r
- //});\r
- }\r
-\r
- lock (Prims)\r
- {\r
- Prims[prim.LocalID] = rprim;\r
}\r
}\r
\r
- private void UpdatePrimBlocking(Primitive prim)\r
+ private void MeshPrim(RenderPrimitive rprim)\r
{\r
- if (!RenderingEnabled) return;\r
+ if (rprim.Meshing) return;\r
\r
- if (AvatarRenderingEnabled && prim.PrimData.PCode == PCode.Avatar)\r
- {\r
- AddAvatarToScene(Client.Network.CurrentSim.ObjectsAvatars[prim.LocalID]);\r
- return;\r
- }\r
-\r
- // Skip foliage\r
- if (prim.PrimData.PCode != PCode.Prim) return;\r
- if (!PrimitiveRenderingEnabled) return;\r
-\r
- if (prim.Textures == null) return;\r
-\r
- RenderPrimitive rPrim = null;\r
- if (Prims.TryGetValue(prim.LocalID, out rPrim))\r
- {\r
- rPrim.AttachedStateKnown = false;\r
- }\r
- else\r
- {\r
- rPrim = new RenderPrimitive();\r
- }\r
+ rprim.Meshing = true;\r
+ Primitive prim = rprim.BasePrim;\r
\r
// Regular prim\r
if (prim.Sculpt == null || prim.Sculpt.SculptTexture == UUID.Zero)\r
{\r
FacetedMesh mesh = renderer.GenerateFacetedMesh(prim, DetailLevel.High);\r
- rPrim.Faces = mesh.Faces;\r
- rPrim.Prim = prim;\r
- MeshPrim(prim, rPrim);\r
+ rprim.Faces = mesh.Faces;\r
+ CalculateBoundingBox(rprim);\r
+ rprim.Meshed = true;\r
+ rprim.Meshing = false;\r
}\r
else\r
{\r
- try\r
+ PendingTasks.Enqueue(new GenericTask(() =>\r
{\r
FacetedMesh mesh = null;\r
\r
- if (prim.Sculpt.Type != SculptType.Mesh)\r
- { // Regular sculptie\r
- Image img = null;\r
+ try\r
+ {\r
+ if (prim.Sculpt.Type != SculptType.Mesh)\r
+ { // Regular sculptie\r
+ Image img = null;\r
\r
- lock (sculptCache)\r
- {\r
- if (sculptCache.ContainsKey(prim.Sculpt.SculptTexture))\r
+ lock (sculptCache)\r
{\r
- img = sculptCache[prim.Sculpt.SculptTexture];\r
+ if (sculptCache.ContainsKey(prim.Sculpt.SculptTexture))\r
+ {\r
+ img = sculptCache[prim.Sculpt.SculptTexture];\r
+ }\r
}\r
- }\r
\r
- if (img == null)\r
- {\r
- if (LoadTexture(prim.Sculpt.SculptTexture, ref img, true))\r
- {\r
- sculptCache[prim.Sculpt.SculptTexture] = (Bitmap)img;\r
- }\r
- else\r
+ if (img == null)\r
{\r
- return;\r
+ if (LoadTexture(prim.Sculpt.SculptTexture, ref img, true))\r
+ {\r
+ sculptCache[prim.Sculpt.SculptTexture] = (Bitmap)img;\r
+ }\r
+ else\r
+ {\r
+ return;\r
+ }\r
}\r
- }\r
\r
- mesh = renderer.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.High);\r
- }\r
- else\r
- { // Mesh\r
- AutoResetEvent gotMesh = new AutoResetEvent(false);\r
- bool meshSuccess = false;\r
+ mesh = renderer.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.High);\r
+ }\r
+ else\r
+ { // Mesh\r
+ AutoResetEvent gotMesh = new AutoResetEvent(false);\r
\r
- Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) =>\r
+ Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) =>\r
{\r
if (!success || !FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out mesh))\r
{\r
Logger.Log("Failed to fetch or decode the mesh asset", Helpers.LogLevel.Warning, Client);\r
}\r
- else\r
- {\r
- meshSuccess = true;\r
- }\r
gotMesh.Set();\r
});\r
\r
- if (!gotMesh.WaitOne(20 * 1000, false)) return;\r
- if (!meshSuccess) return;\r
+ gotMesh.WaitOne(20 * 1000, false);\r
+ }\r
}\r
+ catch\r
+ { }\r
\r
if (mesh != null)\r
{\r
- rPrim.Faces = mesh.Faces;\r
- rPrim.Prim = prim;\r
- MeshPrim(prim, rPrim);\r
+ rprim.Faces = mesh.Faces;\r
+ CalculateBoundingBox(rprim);\r
+ rprim.Meshed = true;\r
+ rprim.Meshing = false;\r
}\r
- }\r
- catch\r
- { }\r
+ else\r
+ {\r
+ lock (Prims)\r
+ {\r
+ Prims.Remove(rprim.BasePrim.LocalID);\r
+ }\r
+ }\r
+ }));\r
+ return;\r
}\r
}\r
\r
+ private void UpdatePrimBlocking(Primitive prim)\r
+ {\r
+ if (!RenderingEnabled) return;\r
+\r
+ if (AvatarRenderingEnabled && prim.PrimData.PCode == PCode.Avatar)\r
+ {\r
+ AddAvatarToScene(Client.Network.CurrentSim.ObjectsAvatars[prim.LocalID]);\r
+ return;\r
+ }\r
+\r
+ // Skip foliage\r
+ if (prim.PrimData.PCode != PCode.Prim) return;\r
+ if (!PrimitiveRenderingEnabled) return;\r
+\r
+ if (prim.Textures == null) return;\r
+\r
+ RenderPrimitive rPrim = null;\r
+ if (Prims.TryGetValue(prim.LocalID, out rPrim))\r
+ {\r
+ rPrim.AttachedStateKnown = false;\r
+ }\r
+ else\r
+ {\r
+ rPrim = new RenderPrimitive();\r
+ }\r
+\r
+ rPrim.Prim = prim;\r
+ rPrim.Meshed = false;\r
+ lock (Prims) Prims[prim.LocalID] = rPrim;\r
+ }\r
+\r
private bool LoadTexture(UUID textureID, ref Image texture, bool removeAlpha)\r
{\r
ManualResetEvent gotImage = new ManualResetEvent(false);\r