corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Drawing;
5 using System.Drawing.Imaging;
6 using System.Windows.Forms;
7 using System.IO;
8 using System.Runtime.InteropServices;
9 using Tao.OpenGl;
10 using Tao.Platform.Windows;
11 using ICSharpCode.SharpZipLib.Zip;
12 using OpenMetaverse;
13 using OpenMetaverse.StructuredData;
14 using OpenMetaverse.Imaging;
15 using OpenMetaverse.Rendering;
16 using OpenMetaverse.Assets;
17  
18 namespace PrimWorkshop
19 {
20 public partial class frmBrowser : Form
21 {
22 const float DEG_TO_RAD = 0.0174532925f;
23 const uint TERRAIN_START = (uint)Int32.MaxValue + 1;
24  
25 ContextMenu ExportPrimMenu;
26 ContextMenu ExportTerrainMenu;
27  
28 GridClient Client;
29 Camera Camera;
30 Dictionary<uint, Primitive> RenderFoliageList = new Dictionary<uint, Primitive>();
31 Dictionary<uint, RenderablePrim> RenderPrimList = new Dictionary<uint, RenderablePrim>();
32 Dictionary<UUID, GlacialComponents.Controls.GLItem> DownloadList = new Dictionary<UUID, GlacialComponents.Controls.GLItem>();
33 EventHandler IdleEvent;
34  
35 System.Timers.Timer ProgressTimer;
36 int TotalPrims;
37  
38 // Textures
39 Dictionary<UUID, TextureInfo> Textures = new Dictionary<UUID, TextureInfo>();
40  
41 // Terrain
42 float MaxHeight = 0.1f;
43 TerrainPatch[,] Heightmap;
44 HeightmapLookupValue[] LookupHeightTable;
45  
46 // Picking globals
47 bool Clicked = false;
48 int ClickX = 0;
49 int ClickY = 0;
50 uint LastHit = 0;
51  
52 //warning CS0414: The private field `PrimWorkshop.frmBrowser.PivotPosition' is assigned but its value is never used
53 Vector3 PivotPosition = Vector3.Zero;
54 private bool Pivoting;
55 Point LastPivot;
56  
57 //
58 const int SELECT_BUFSIZE = 512;
59 uint[] SelectBuffer = new uint[SELECT_BUFSIZE];
60  
61 //warning CS0414: The private field `PrimWorkshop.frmBrowser.msg' is assigned but its value is never used
62 NativeMethods.Message msg;
63 private bool AppStillIdle
64 {
65 get { return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); }
66 }
67  
68 /// <summary>
69 /// Default constructor
70 /// </summary>
71 public frmBrowser()
72 {
73 InitializeComponent();
74  
75 // Setup OpenGL
76 glControl.InitializeContexts();
77 glControl.SwapBuffers();
78 glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
79  
80 // Login server URLs
81 cboServer.Items.Add(Settings.AGNI_LOGIN_SERVER);
82 cboServer.Items.Add(Settings.ADITI_LOGIN_SERVER);
83 cboServer.Items.Add("http://osgrid.org:8002/");
84 cboServer.SelectedIndex = 0;
85  
86 // Context menus
87 ExportPrimMenu = new ContextMenu();
88 ExportPrimMenu.MenuItems.Add("Download", new EventHandler(DownloadMenu_Clicked));
89 ExportPrimMenu.MenuItems.Add("Download All Objects", new EventHandler(DownloadAllMenu_Clicked));
90 ExportTerrainMenu = new ContextMenu();
91 ExportTerrainMenu.MenuItems.Add("Teleport", new EventHandler(TeleportMenu_Clicked));
92 ExportTerrainMenu.MenuItems.Add("Export Terrain", new EventHandler(ExportTerrainMenu_Clicked));
93 ExportTerrainMenu.MenuItems.Add("Import Object", new EventHandler(ImportObjectMenu_Clicked));
94 ExportTerrainMenu.MenuItems.Add("Import Sim", new EventHandler(ImportSimMenu_Clicked));
95  
96 // Setup a timer for updating the progress bar
97 ProgressTimer = new System.Timers.Timer(250);
98 ProgressTimer.Elapsed +=
99 delegate(object sender, System.Timers.ElapsedEventArgs e)
100 {
101 UpdatePrimProgress();
102 };
103 ProgressTimer.Start();
104  
105 IdleEvent = new EventHandler(Application_Idle);
106 Application.Idle += IdleEvent;
107  
108 // Show a flat sim before login so the screen isn't so boring
109 InitHeightmap();
110 InitOpenGL();
111 InitCamera();
112  
113 glControl_Resize(null, null);
114 }
115  
116 private void InitLists()
117 {
118 TotalPrims = 0;
119  
120 lock (Textures)
121 {
122 foreach (TextureInfo tex in Textures.Values)
123 {
124 int id = tex.ID;
125 Gl.glDeleteTextures(1, ref id);
126 }
127  
128 Textures.Clear();
129 }
130  
131 lock (RenderPrimList) RenderPrimList.Clear();
132 lock (RenderFoliageList) RenderFoliageList.Clear();
133 }
134  
135 private void InitializeObjects()
136 {
137 InitLists();
138  
139 if (DownloadList != null)
140 lock (DownloadList)
141 DownloadList.Clear();
142  
143 // Initialize the SL client
144 Client = new GridClient();
145 Client.Settings.MULTIPLE_SIMS = false;
146 Client.Settings.ALWAYS_DECODE_OBJECTS = true;
147 Client.Settings.ALWAYS_REQUEST_OBJECTS = true;
148 Client.Settings.SEND_AGENT_UPDATES = true;
149 Client.Settings.USE_ASSET_CACHE = true;
150 //Client.Settings.ASSET_CACHE_DIR = Application.StartupPath + System.IO.Path.DirectorySeparatorChar + "cache";
151 Client.Settings.ALWAYS_REQUEST_PARCEL_ACL = false;
152 Client.Settings.ALWAYS_REQUEST_PARCEL_DWELL = false;
153 // Crank up the throttle on texture downloads
154 Client.Throttle.Texture = 446000.0f;
155  
156 // FIXME: Write our own avatar tracker so we don't double store prims
157 Client.Settings.OBJECT_TRACKING = false; // We use our own object tracking system
158 Client.Settings.AVATAR_TRACKING = true; //but we want to use the libsl avatar system
159  
160 Client.Network.LoginProgress += Network_OnLogin;
161 Client.Network.Disconnected += Network_OnDisconnected;
162 Client.Network.SimChanged += Network_OnCurrentSimChanged;
163 Client.Network.EventQueueRunning += Network_OnEventQueueRunning;
164 Client.Objects.ObjectUpdate += Objects_OnNewPrim;
165 Client.Terrain.LandPatchReceived += new EventHandler<LandPatchReceivedEventArgs>(Terrain_LandPatchReceived);
166 Client.Parcels.SimParcelsDownloaded += new EventHandler<SimParcelsDownloadedEventArgs>(Parcels_SimParcelsDownloaded);
167 Client.Assets.ImageReceiveProgress += new EventHandler<ImageReceiveProgressEventArgs>(Assets_ImageReceiveProgress);
168 // Initialize the camera object
169 InitCamera();
170  
171 // Setup the libsl camera to match our Camera struct
172 UpdateCamera();
173 glControl_Resize(null, null);
174  
175 /*
176 // Enable lighting
177 Gl.glEnable(Gl.GL_LIGHTING);
178 Gl.glEnable(Gl.GL_LIGHT0);
179 float[] lightPosition = { 128.0f, 64.0f, 96.0f, 0.0f };
180 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPosition);
181  
182 // Setup ambient property
183 float[] ambientLight = { 0.2f, 0.2f, 0.2f, 0.0f };
184 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambientLight);
185  
186 // Setup specular property
187 float[] specularLight = { 0.5f, 0.5f, 0.5f, 0.0f };
188 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, specularLight);
189 */
190 }
191  
192 void Objects_NewPrim(object sender, PrimEventArgs e)
193 {
194 throw new NotImplementedException();
195 }
196  
197 void Parcels_SimParcelsDownloaded(object sender, SimParcelsDownloadedEventArgs e)
198 {
199 TotalPrims = 0;
200  
201 e.Parcels.ForEach(
202 delegate(Parcel parcel)
203 {
204 TotalPrims += parcel.TotalPrims;
205 });
206  
207 UpdatePrimProgress(); TotalPrims = 0;
208  
209 e.Parcels.ForEach(
210 delegate(Parcel parcel)
211 {
212 TotalPrims += parcel.TotalPrims;
213 });
214  
215 UpdatePrimProgress();
216 }
217  
218  
219 private void InitOpenGL()
220 {
221 Gl.glShadeModel(Gl.GL_SMOOTH);
222  
223 Gl.glClearDepth(1.0f);
224 Gl.glEnable(Gl.GL_DEPTH_TEST);
225 Gl.glDepthMask(Gl.GL_TRUE);
226 Gl.glDepthFunc(Gl.GL_LEQUAL);
227 Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
228 }
229  
230 private void InitHeightmap()
231 {
232 // Initialize the heightmap
233 Heightmap = new TerrainPatch[16, 16];
234 for (int y = 0; y < 16; y++)
235 {
236 for (int x = 0; x < 16; x++)
237 {
238 Heightmap[y, x] = new TerrainPatch();
239 Heightmap[y, x].Data = new float[16 * 16];
240 }
241 }
242  
243 // Speed up terrain exports with a lookup table
244 LookupHeightTable = new HeightmapLookupValue[256 * 256];
245 for (int i = 0; i < 256; i++)
246 {
247 for (int j = 0; j < 256; j++)
248 {
249 LookupHeightTable[i + (j * 256)] = new HeightmapLookupValue((ushort)(i + (j * 256)), ((float)i * ((float)j / 127.0f)));
250 }
251 }
252 Array.Sort<HeightmapLookupValue>(LookupHeightTable);
253 }
254  
255 private void InitCamera()
256 {
257 Camera = new Camera();
258 Camera.Position = new Vector3(128f, -192f, 90f);
259 Camera.FocalPoint = new Vector3(128f, 128f, 0f);
260 Camera.Zoom = 1.0d;
261 Camera.Far = 512.0d;
262 }
263  
264 private void UpdatePrimProgress()
265 {
266 if (this.InvokeRequired)
267 {
268 BeginInvoke((MethodInvoker)delegate() { UpdatePrimProgress(); });
269 }
270 else
271 {
272 try
273 {
274 if (RenderPrimList != null && RenderFoliageList != null)
275 {
276 int count = RenderPrimList.Count + RenderFoliageList.Count;
277  
278 lblPrims.Text = String.Format("Prims: {0} / {1}", count, TotalPrims);
279 progPrims.Maximum = (TotalPrims > count) ? TotalPrims : count;
280 progPrims.Value = count;
281 }
282 else
283 {
284 lblPrims.Text = String.Format("Prims: 0 / {0}", TotalPrims);
285 progPrims.Maximum = TotalPrims;
286 progPrims.Value = 0;
287 }
288 }
289 catch (Exception ex)
290 {
291 Console.WriteLine(ex);
292 }
293 }
294 }
295  
296 private void UpdateCamera()
297 {
298 if (Client != null)
299 {
300 Client.Self.Movement.Camera.LookAt(Camera.Position, Camera.FocalPoint);
301 Client.Self.Movement.Camera.Far = (float)Camera.Far;
302 }
303  
304 Gl.glPushMatrix();
305 Gl.glMatrixMode(Gl.GL_PROJECTION);
306 Gl.glLoadIdentity();
307  
308 SetPerspective();
309  
310 Gl.glMatrixMode(Gl.GL_MODELVIEW);
311 Gl.glPopMatrix();
312 }
313  
314 private bool ExportObject(RenderablePrim parent, string fileName, out int prims, out int textures, out string error)
315 {
316 // Build a list of primitives (parent+children) to export
317 List<Primitive> primList = new List<Primitive>();
318 primList.Add(parent.Prim);
319  
320 lock (RenderPrimList)
321 {
322 foreach (RenderablePrim render in RenderPrimList.Values)
323 {
324 if (render.Prim.ParentID == parent.Prim.LocalID)
325 primList.Add(render.Prim);
326 }
327 }
328  
329 return ExportObjects(primList, fileName, out prims, out textures, out error);
330 }
331  
332 private bool ExportSim(string fileName, out int prims, out int textures, out string error)
333 {
334 // Add all of the prims in this sim to the export list
335 List<Primitive> primList = new List<Primitive>();
336  
337 lock (RenderPrimList)
338 {
339 foreach (RenderablePrim render in RenderPrimList.Values)
340 {
341 primList.Add(render.Prim);
342 }
343 }
344  
345 return ExportObjects(primList, fileName, out prims, out textures, out error);
346 }
347  
348 private bool ExportObjects(List<Primitive> primList, string fileName, out int prims, out int textures, out string error)
349 {
350 List<UUID> textureList = new List<UUID>();
351 prims = 0;
352 textures = 0;
353  
354 // Write the LLSD to the hard drive in XML format
355 string output = OSDParser.SerializeLLSDXmlString(Helpers.PrimListToOSD(primList));
356 try
357 {
358 // Create a temporary directory
359 string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
360 Directory.CreateDirectory(tempPath);
361  
362 // Write the prim XML file
363 File.WriteAllText(System.IO.Path.Combine(tempPath, "prims.xml"), output);
364 prims = primList.Count;
365  
366 // Build a list of all the referenced textures in this prim list
367 foreach (Primitive prim in primList)
368 {
369 for (int i = 0; i < prim.Textures.FaceTextures.Length; i++)
370 {
371 Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i];
372 if (face != null && face.TextureID != UUID.Zero && face.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
373 {
374 if (!textureList.Contains(face.TextureID))
375 textureList.Add(face.TextureID);
376 }
377 }
378 }
379  
380 // Copy all of relevant textures from the cache to the temp directory
381 foreach (UUID texture in textureList)
382 {
383 string tempFileName = Client.Assets.Cache.AssetFileName(texture);
384  
385 if (!String.IsNullOrEmpty(tempFileName))
386 {
387 File.Copy(tempFileName, System.IO.Path.Combine(tempPath, texture.ToString() + ".jp2"));
388 ++textures;
389 }
390 else
391 {
392 Console.WriteLine("Missing texture file during download: " + texture.ToString());
393 }
394 }
395  
396 // Zip up the directory
397 string[] filenames = Directory.GetFiles(tempPath);
398 using (ZipOutputStream s = new ZipOutputStream(File.Create(fileName)))
399 {
400 s.SetLevel(9);
401 byte[] buffer = new byte[4096];
402  
403 foreach (string file in filenames)
404 {
405 ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(file));
406 entry.DateTime = DateTime.Now;
407 s.PutNextEntry(entry);
408  
409 using (FileStream fs = File.OpenRead(file))
410 {
411 int sourceBytes;
412 do
413 {
414 sourceBytes = fs.Read(buffer, 0, buffer.Length);
415 s.Write(buffer, 0, sourceBytes);
416 } while (sourceBytes > 0);
417 }
418 }
419  
420 s.Finish();
421 s.Close();
422 }
423  
424 error = null;
425 return true;
426 }
427 catch (Exception ex)
428 {
429 error = ex.Message;
430 return false;
431 }
432 }
433  
434 private List<Primitive> ImportObjects(string fileName, out string tempPath, out string error)
435 {
436 tempPath = null;
437 error = null;
438 string primFile = null;
439  
440 try
441 {
442 // Create a temporary directory
443 tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName());
444 Directory.CreateDirectory(tempPath);
445  
446 // Unzip the primpackage
447 using (ZipInputStream s = new ZipInputStream(File.OpenRead(fileName)))
448 {
449 ZipEntry theEntry;
450  
451 // Loop through and confirm there is a prims.xml file
452 while ((theEntry = s.GetNextEntry()) != null)
453 {
454 if (String.Equals("prims.xml", theEntry.Name.ToLower()))
455 {
456 primFile = theEntry.Name;
457 break;
458 }
459 }
460  
461 if (primFile != null)
462 {
463 // Prepend the path to the primFile (that will be created in the next loop)
464 primFile = System.IO.Path.Combine(tempPath, primFile);
465 }
466 else
467 {
468 // Didn't find a prims.xml file, bail out
469 error = "No prims.xml file found in the archive";
470 return null;
471 }
472  
473 // Reset to the beginning of the zip file
474 s.Seek(0, SeekOrigin.Begin);
475  
476 Logger.DebugLog("Unpacking archive to " + tempPath);
477  
478 // Unzip all of the texture and xml files
479 while ((theEntry = s.GetNextEntry()) != null)
480 {
481 string directory = System.IO.Path.GetDirectoryName(theEntry.Name);
482 string file = System.IO.Path.GetFileName(theEntry.Name);
483  
484 // Skip directories
485 if (directory.Length > 0)
486 continue;
487  
488 if (!String.IsNullOrEmpty(file))
489 {
490 string filelow = file.ToLower();
491  
492 if (filelow.EndsWith(".jp2") || filelow.EndsWith(".tga") || filelow.EndsWith(".xml"))
493 {
494 Logger.DebugLog("Unpacking " + file);
495  
496 // Create the full path from the temp path and new filename
497 string filePath = System.IO.Path.Combine(tempPath, file);
498  
499 using (FileStream streamWriter = File.Create(filePath))
500 {
501 const int READ_BUFFER_SIZE = 2048;
502 int size = READ_BUFFER_SIZE;
503 byte[] data = new byte[READ_BUFFER_SIZE];
504  
505 while (true)
506 {
507 size = s.Read(data, 0, data.Length);
508 if (size > 0)
509 streamWriter.Write(data, 0, size);
510 else
511 break;
512 }
513 }
514 }
515 else
516 {
517 Logger.Log("Skipping file " + file, Helpers.LogLevel.Info);
518 }
519 }
520 }
521 }
522  
523 // Decode the .prims file
524 string raw = File.ReadAllText(primFile);
525 OSD osd = OSDParser.DeserializeLLSDXml(raw);
526 return Helpers.OSDToPrimList(osd);
527 }
528 catch (Exception e)
529 {
530 error = e.Message;
531 return null;
532 }
533 }
534  
535 private void DownloadMenu_Clicked(object sender, EventArgs e)
536 {
537 // Confirm that there actually is a selected object
538 RenderablePrim parent;
539 if (RenderPrimList.TryGetValue(LastHit, out parent))
540 {
541 if (parent.Prim.ParentID == 0)
542 {
543 // Valid parent prim is selected, throw up the save file dialog
544 SaveFileDialog dialog = new SaveFileDialog();
545 dialog.Filter = "Prim Package (*.zip)|*.zip";
546  
547 if (dialog.ShowDialog() == DialogResult.OK)
548 {
549 string error;
550 int prims, textures;
551 if (ExportObject(parent, dialog.FileName, out prims, out textures, out error))
552 MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
553 else
554 MessageBox.Show("Export failed: " + error);
555 }
556 }
557 else
558 {
559 // This should have already been fixed in the picking processing code
560 Console.WriteLine("Download menu clicked when a child prim is selected!");
561 glControl.ContextMenu = null;
562 LastHit = 0;
563 }
564 }
565 else
566 {
567 Console.WriteLine("Download menu clicked when there is no selected prim!");
568 glControl.ContextMenu = null;
569 LastHit = 0;
570 }
571 }
572  
573 private void DownloadAllMenu_Clicked(object sender, EventArgs e)
574 {
575 SaveFileDialog dialog = new SaveFileDialog();
576 dialog.Filter = "Prim Package (*.zip)|*.zip";
577  
578 if (dialog.ShowDialog() == DialogResult.OK)
579 {
580 string error;
581 int prims, textures;
582 if (ExportSim(dialog.FileName, out prims, out textures, out error))
583 MessageBox.Show(String.Format("Exported {0} prims and {1} textures", prims, textures));
584 else
585 MessageBox.Show("Export failed: " + error);
586 }
587 }
588  
589 private void ExportTerrainMenu_Clicked(object sender, EventArgs e)
590 {
591 // Valid parent prim is selected, throw up the save file dialog
592 SaveFileDialog dialog = new SaveFileDialog();
593 dialog.Filter = "Terrain RAW (*.raw)|*.raw";
594  
595 if (dialog.ShowDialog() == DialogResult.OK)
596 {
597 BackgroundWorker worker = new BackgroundWorker();
598 worker.DoWork += delegate(object obj, DoWorkEventArgs args)
599 {
600 byte red, green, blue, alpha1, alpha2, alpha3, alpha4, alpha5, alpha6, alpha7, alpha8, alpha9, alpha10;
601  
602 try
603 {
604 FileInfo file = new FileInfo(dialog.FileName);
605 FileStream s = file.Open(FileMode.OpenOrCreate, FileAccess.Write);
606 BinaryWriter binStream = new BinaryWriter(s);
607  
608 for (int y = 0; y < 256; y++)
609 {
610 for (int x = 0; x < 256; x++)
611 {
612 int xBlock = x / 16;
613 int yBlock = y / 16;
614 int xOff = x - (xBlock * 16);
615 int yOff = y - (yBlock * 16);
616  
617 float t = Heightmap[yBlock, xBlock].Data[yOff * 16 + xOff];
618 //float min = Single.MaxValue;
619 int index = 0;
620  
621 // The lookup table is pre-sorted, so we either find an exact match or
622 // the next closest (smaller) match with a binary search
623 index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, t));
624 if (index < 0)
625 index = ~index - 1;
626  
627 index = LookupHeightTable[index].Index;
628  
629 /*for (int i = 0; i < 65536; i++)
630 {
631 if (Math.Abs(t - LookupHeightTable[i].Value) < min)
632 {
633 min = Math.Abs(t - LookupHeightTable[i].Value);
634 index = i;
635 }
636 }*/
637  
638 red = (byte)(index & 0xFF);
639 green = (byte)((index >> 8) & 0xFF);
640 blue = 20;
641 alpha1 = 0; // Land Parcels
642 alpha2 = 0; // For Sale Land
643 alpha3 = 0; // Public Edit Object
644 alpha4 = 0; // Public Edit Land
645 alpha5 = 255; // Safe Land
646 alpha6 = 255; // Flying Allowed
647 alpha7 = 255; // Create Landmark
648 alpha8 = 255; // Outside Scripts
649 alpha9 = red;
650 alpha10 = green;
651  
652 binStream.Write(red);
653 binStream.Write(green);
654 binStream.Write(blue);
655 binStream.Write(alpha1);
656 binStream.Write(alpha2);
657 binStream.Write(alpha3);
658 binStream.Write(alpha4);
659 binStream.Write(alpha5);
660 binStream.Write(alpha6);
661 binStream.Write(alpha7);
662 binStream.Write(alpha8);
663 binStream.Write(alpha9);
664 binStream.Write(alpha10);
665 }
666 }
667  
668 binStream.Close();
669 s.Close();
670  
671 BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Exported heightmap"); });
672 }
673 catch (Exception ex)
674 {
675 BeginInvoke((MethodInvoker)delegate() { System.Windows.Forms.MessageBox.Show("Error exporting heightmap: " + ex.Message); });
676 }
677 };
678  
679 worker.RunWorkerAsync();
680 }
681 }
682  
683 private void TeleportMenu_Clicked(object sender, EventArgs e)
684 {
685 if (Client != null && Client.Network.CurrentSim != null)
686 {
687 if (LastHit >= TERRAIN_START)
688 {
689 // Determine which piece of terrain was clicked on
690 int y = (int)(LastHit - TERRAIN_START) / 16;
691 int x = (int)(LastHit - (TERRAIN_START + (y * 16)));
692  
693 Vector3 targetPos = new Vector3(x * 16 + 8, y * 16 + 8, 0f);
694  
695 Console.WriteLine("Starting local teleport to " + targetPos.ToString());
696 Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, targetPos);
697 }
698 else
699 {
700 // This shouldn't have happened...
701 glControl.ContextMenu = null;
702 }
703 }
704 }
705  
706 private void ImportObjectMenu_Clicked(object sender, EventArgs e)
707 {
708 OpenFileDialog dialog = new OpenFileDialog();
709 dialog.Filter = "Prim Package (*.zip,*.primpackage)|*.zip;*.primpackage";
710  
711 if (dialog.ShowDialog() == DialogResult.OK)
712 {
713 // FIXME: Disable any further imports or exports until this is finished
714  
715 // Import the prims
716 string error, texturePath;
717 List<Primitive> primList = ImportObjects(dialog.FileName, out texturePath, out error);
718 if (primList != null)
719 {
720 // Determine the total height of the object
721 float minHeight = Single.MaxValue;
722 float maxHeight = Single.MinValue;
723  
724 //float totalHeight = 0f;
725  
726 for (int i = 0; i < primList.Count; i++)
727 {
728 Primitive prim = primList[i];
729  
730 // Find the largest scale dimension (quick cheat to avoid figuring in the rotation)
731 float scale = prim.Scale.X;
732 if (prim.Scale.Y > scale) scale = prim.Scale.Y;
733 if (prim.Scale.Z > scale) scale = prim.Scale.Z;
734  
735 float top = prim.Position.Z + (scale * 0.5f);
736 float bottom = top - scale;
737  
738 if (top > maxHeight) maxHeight = top;
739 if (bottom < minHeight) minHeight = bottom;
740 }
741  
742 //totalHeight = maxHeight - minHeight;
743  
744 // Create a progress bar for the import process
745 ProgressBar prog = new ProgressBar();
746 prog.Minimum = 0;
747 prog.Maximum = primList.Count;
748 prog.Value = 0;
749  
750 // List item
751 GlacialComponents.Controls.GLItem item = new GlacialComponents.Controls.GLItem();
752 item.SubItems[0].Text = "Import process";
753 item.SubItems[1].Control = prog;
754  
755 lstDownloads.Items.Add(item);
756 lstDownloads.Invalidate();
757  
758 // Start the import process in the background
759 BackgroundWorker worker = new BackgroundWorker();
760  
761 worker.DoWork += delegate(object s, DoWorkEventArgs ea)
762 {
763 // Set the spot choosing state
764  
765 // Wait for a spot to be chosen
766  
767 // mouse2dto3d()
768  
769 // Add (0, 0, totalHeight * 0.5f) to the clicked position
770  
771 for (int i = 0; i < primList.Count; i++)
772 {
773 Primitive prim = primList[i];
774  
775 for (int j = 0; j < prim.Textures.FaceTextures.Length; j++)
776 {
777 // Check if this texture exists
778  
779 // If not, wait while it uploads
780 }
781  
782 // Create this prim (using weird SL math to get the correct position)
783  
784 // Wait for the callback to fire for this prim being created
785  
786 // Add this prim's localID to a list
787  
788 // Set any additional properties. If this is the root prim, do not apply rotation
789  
790 // Update the progress bar
791 BeginInvoke((MethodInvoker)delegate() { prog.Value = i; });
792 }
793  
794 // Link all of the prims together
795  
796 // Apply root prim rotation
797 };
798  
799 worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
800 {
801 BeginInvoke(
802 (MethodInvoker)delegate()
803 {
804 lstDownloads.Items.Remove(item);
805 lstDownloads.Invalidate();
806 });
807 };
808  
809 worker.RunWorkerAsync();
810 }
811 else
812 {
813 // FIXME: Re-enable imports and exports
814  
815 MessageBox.Show(error);
816 return;
817 }
818 }
819 }
820  
821 private void ImportSimMenu_Clicked(object sender, EventArgs e)
822 {
823 }
824  
825 private void SetPerspective()
826 {
827 Glu.gluPerspective(50.0d * Camera.Zoom, 1.0d, 0.1d, Camera.Far);
828 }
829  
830 private void StartPicking(int cursorX, int cursorY)
831 {
832 int[] viewport = new int[4];
833  
834 Gl.glSelectBuffer(SELECT_BUFSIZE, SelectBuffer);
835 Gl.glRenderMode(Gl.GL_SELECT);
836  
837 Gl.glMatrixMode(Gl.GL_PROJECTION);
838 Gl.glPushMatrix();
839 Gl.glLoadIdentity();
840  
841 Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
842 Glu.gluPickMatrix(cursorX, viewport[3] - cursorY, 5, 5, viewport);
843  
844 SetPerspective();
845  
846 Gl.glMatrixMode(Gl.GL_MODELVIEW);
847  
848 Gl.glInitNames();
849 }
850  
851 private void StopPicking()
852 {
853 int hits;
854  
855 // Resotre the original projection matrix
856 Gl.glMatrixMode(Gl.GL_PROJECTION);
857 Gl.glPopMatrix();
858 Gl.glMatrixMode(Gl.GL_MODELVIEW);
859 Gl.glFlush();
860  
861 // Return to normal rendering mode
862 hits = Gl.glRenderMode(Gl.GL_RENDER);
863  
864 // If there are hits process them
865 if (hits != 0)
866 {
867 ProcessHits(hits, SelectBuffer);
868 }
869 else
870 {
871 LastHit = 0;
872 glControl.ContextMenu = null;
873 }
874 }
875  
876 private void ProcessHits(int hits, uint[] selectBuffer)
877 {
878 uint names = 0;
879 uint numNames = 0;
880 uint minZ = 0xffffffff;
881 uint ptr = 0;
882 uint ptrNames = 0;
883  
884 for (uint i = 0; i < hits; i++)
885 {
886 names = selectBuffer[ptr];
887 ++ptr;
888 if (selectBuffer[ptr] < minZ)
889 {
890 numNames = names;
891 minZ = selectBuffer[ptr];
892 ptrNames = ptr + 2;
893 }
894  
895 ptr += names + 2;
896 }
897  
898 ptr = ptrNames;
899  
900 for (uint i = 0; i < numNames; i++, ptr++)
901 {
902 LastHit = selectBuffer[ptr];
903 }
904  
905 if (LastHit >= TERRAIN_START)
906 {
907 // Terrain was clicked on, turn off the context menu
908 glControl.ContextMenu = ExportTerrainMenu;
909 }
910 else
911 {
912 RenderablePrim render;
913 if (RenderPrimList.TryGetValue(LastHit, out render))
914 {
915 if (render.Prim.ParentID == 0)
916 {
917 Camera.FocalPoint = render.Prim.Position;
918 UpdateCamera();
919 }
920 else
921 {
922 // See if we have the parent
923 RenderablePrim renderParent;
924 if (RenderPrimList.TryGetValue(render.Prim.ParentID, out renderParent))
925 {
926 // Turn on the context menu
927 glControl.ContextMenu = ExportPrimMenu;
928  
929 // Change the clicked on prim to the parent. Camera position stays on the
930 // clicked child but the highlighting is applied to all the children
931 LastHit = renderParent.Prim.LocalID;
932  
933 Camera.FocalPoint = renderParent.Prim.Position + render.Prim.Position;
934 UpdateCamera();
935 }
936 else
937 {
938 Console.WriteLine("Clicked on a child prim with no parent!");
939 LastHit = 0;
940 }
941 }
942 }
943 }
944 }
945  
946 private void Objects_OnNewPrim(object sender, PrimEventArgs e)
947 {
948 Primitive prim = e.Prim;
949 if (prim.PrimData.PCode == PCode.Grass || prim.PrimData.PCode == PCode.Tree || prim.PrimData.PCode == PCode.NewTree)
950 {
951 lock (RenderFoliageList)
952 RenderFoliageList[prim.LocalID] = prim;
953 return;
954 }
955  
956 RenderablePrim render = new RenderablePrim();
957 render.Prim = prim;
958  
959 // FIXME: Handle sculpted prims by calling Render.Plugin.GenerateFacetedSculptMesh() instead
960 render.Mesh = Render.Plugin.GenerateFacetedMesh(prim, DetailLevel.High);
961  
962 // Create a FaceData struct for each face that stores the 3D data
963 // in a Tao.OpenGL friendly format
964 for (int j = 0; j < render.Mesh.Faces.Count; j++)
965 {
966 Face face = render.Mesh.Faces[j];
967 FaceData data = new FaceData();
968  
969 // Vertices for this face
970 data.Vertices = new float[face.Vertices.Count * 3];
971 for (int k = 0; k < face.Vertices.Count; k++)
972 {
973 data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X;
974 data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y;
975 data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z;
976 }
977  
978 // Indices for this face
979 data.Indices = face.Indices.ToArray();
980  
981 // Texture transform for this face
982 Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j);
983 Render.Plugin.TransformTexCoords(face.Vertices, face.Center, teFace, prim.Scale);
984  
985 // Texcoords for this face
986 data.TexCoords = new float[face.Vertices.Count * 2];
987 for (int k = 0; k < face.Vertices.Count; k++)
988 {
989 data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X;
990 data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y;
991 }
992  
993 // Texture for this face
994 if (teFace.TextureID != UUID.Zero &&
995 teFace.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
996 {
997 lock (Textures)
998 {
999 if (!Textures.ContainsKey(teFace.TextureID))
1000 {
1001 // We haven't constructed this image in OpenGL yet, get ahold of it
1002 Client.Assets.RequestImage(teFace.TextureID, ImageType.Normal, TextureDownloader_OnDownloadFinished);
1003 }
1004 }
1005 }
1006  
1007 // Set the UserData for this face to our FaceData struct
1008 face.UserData = data;
1009 render.Mesh.Faces[j] = face;
1010 }
1011  
1012 lock (RenderPrimList) RenderPrimList[prim.LocalID] = render;
1013 }
1014  
1015 private void Terrain_LandPatchReceived(object sender, LandPatchReceivedEventArgs e)
1016 {
1017 if (Client != null && Client.Network.CurrentSim == e.Simulator)
1018 {
1019 Heightmap[e.Y, e.X].Data = e.HeightMap;
1020 }
1021  
1022 // Find the new max height
1023 for (int i = 0; i < e.HeightMap.Length; i++)
1024 {
1025 if (e.HeightMap[i] > MaxHeight)
1026 MaxHeight = e.HeightMap[i];
1027 }
1028 }
1029  
1030 private void Network_OnLogin(object sender, LoginProgressEventArgs e)
1031 {
1032 if (e.Status == LoginStatus.Success)
1033 {
1034 // Success!
1035 }
1036 else if (e.Status == LoginStatus.Failed)
1037 {
1038 BeginInvoke(
1039 (MethodInvoker)delegate()
1040 {
1041 MessageBox.Show(this, String.Format("Error logging in ({0}): {1}",
1042 Client.Network.LoginErrorKey, Client.Network.LoginMessage));
1043 cmdLogin.Text = "Login";
1044 txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
1045 });
1046 }
1047 }
1048  
1049 private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
1050 {
1051 BeginInvoke(
1052 (MethodInvoker)delegate()
1053 {
1054 cmdTeleport.Enabled = false;
1055 DoLogout();
1056 });
1057 }
1058  
1059 private void Network_OnCurrentSimChanged(object sender, SimChangedEventArgs e)
1060 {
1061 Console.WriteLine("CurrentSim set to " + Client.Network.CurrentSim + ", downloading parcel information");
1062  
1063 BeginInvoke((MethodInvoker)delegate() { txtSim.Text = Client.Network.CurrentSim.Name; });
1064  
1065 //InitHeightmap();
1066 InitLists();
1067  
1068 // Disable teleports until the new event queue comes online
1069 if (!Client.Network.CurrentSim.Caps.IsEventQueueRunning)
1070 BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = false; });
1071 }
1072  
1073 private void Network_OnEventQueueRunning(object sender, EventQueueRunningEventArgs e)
1074 {
1075 if (e.Simulator == Client.Network.CurrentSim)
1076 BeginInvoke((MethodInvoker)delegate() { cmdTeleport.Enabled = true; });
1077  
1078 // Now seems like a good time to start requesting parcel information
1079 Client.Parcels.RequestAllSimParcels(Client.Network.CurrentSim, false, 100);
1080 }
1081  
1082 private void RenderScene()
1083 {
1084 try
1085 {
1086 Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
1087 Gl.glLoadIdentity();
1088 Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
1089 Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
1090  
1091 if (Clicked)
1092 StartPicking(ClickX, ClickY);
1093  
1094 // Setup wireframe or solid fill drawing mode
1095 Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
1096  
1097 // Position the camera
1098 Glu.gluLookAt(
1099 Camera.Position.X, Camera.Position.Y, Camera.Position.Z,
1100 Camera.FocalPoint.X, Camera.FocalPoint.Y, Camera.FocalPoint.Z,
1101 0f, 0f, 1f);
1102  
1103 RenderSkybox();
1104  
1105 // Push the world matrix
1106 Gl.glPushMatrix();
1107  
1108 RenderTerrain();
1109 RenderPrims();
1110 RenderAvatars();
1111  
1112 Gl.glDisableClientState(Gl.GL_TEXTURE_COORD_ARRAY);
1113 Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
1114  
1115 if (Clicked)
1116 {
1117 Clicked = false;
1118 StopPicking();
1119 }
1120  
1121 // Pop the world matrix
1122 Gl.glPopMatrix();
1123 Gl.glFlush();
1124  
1125 glControl.Invalidate();
1126 }
1127 catch (Exception)
1128 {
1129 }
1130 }
1131  
1132 static readonly Vector3[] SkyboxVerts = new Vector3[]
1133 {
1134 // Right side
1135 new Vector3( 10.0f, 10.0f, -10.0f ), //Top left
1136 new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
1137 new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
1138 new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom left
1139 // Left side
1140 new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
1141 new Vector3( -10.0f, 10.0f, -10.0f ), //Top right
1142 new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom right
1143 new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
1144 // Top side
1145 new Vector3( -10.0f, 10.0f, 10.0f ), //Top left
1146 new Vector3( 10.0f, 10.0f, 10.0f ), //Top right
1147 new Vector3( 10.0f, 10.0f, -10.0f ), //Bottom right
1148 new Vector3( -10.0f, 10.0f, -10.0f ), //Bottom left
1149 // Bottom side
1150 new Vector3( -10.0f, -10.0f, -10.0f ), //Top left
1151 new Vector3( 10.0f, -10.0f, -10.0f ), //Top right
1152 new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom right
1153 new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom left
1154 // Front side
1155 new Vector3( -10.0f, 10.0f, -10.0f ), //Top left
1156 new Vector3( 10.0f, 10.0f, -10.0f ), //Top right
1157 new Vector3( 10.0f, -10.0f, -10.0f ), //Bottom right
1158 new Vector3( -10.0f, -10.0f, -10.0f ), //Bottom left
1159 // Back side
1160 new Vector3( 10.0f, 10.0f, 10.0f ), //Top left
1161 new Vector3( -10.0f, 10.0f, 10.0f ), //Top right
1162 new Vector3( -10.0f, -10.0f, 10.0f ), //Bottom right
1163 new Vector3( 10.0f, -10.0f, 10.0f ), //Bottom left
1164 };
1165  
1166 private void RenderSkybox()
1167 {
1168 //Gl.glTranslatef(0f, 0f, 0f);
1169 }
1170  
1171 private void RenderTerrain()
1172 {
1173 if (Heightmap != null)
1174 {
1175 int i = 0;
1176  
1177 // No texture
1178 Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
1179  
1180 for (int hy = 0; hy < 16; hy++)
1181 {
1182 for (int hx = 0; hx < 16; hx++)
1183 {
1184 uint patchName = (uint)(TERRAIN_START + i);
1185 Gl.glPushName(patchName);
1186 ++i;
1187  
1188 // Check if this patch is currently selected
1189 bool selected = (LastHit == patchName);
1190  
1191 for (int y = 0; y < 15; y++)
1192 {
1193 Gl.glBegin(Gl.GL_TRIANGLE_STRIP);
1194  
1195 for (int x = 0; x < 15; x++)
1196 {
1197 // Vertex 0
1198 float height = Heightmap[hy, hx].Data[y * 16 + x];
1199 float color = height / MaxHeight;
1200 float red = (selected) ? 1f : color;
1201  
1202 Gl.glColor3f(red, color, color);
1203 Gl.glTexCoord2f(0f, 0f);
1204 Gl.glVertex3f(hx * 16 + x, hy * 16 + y, height);
1205  
1206 // Vertex 1
1207 height = Heightmap[hy, hx].Data[y * 16 + (x + 1)];
1208 color = height / MaxHeight;
1209 red = (selected) ? 1f : color;
1210  
1211 Gl.glColor3f(red, color, color);
1212 Gl.glTexCoord2f(1f, 0f);
1213 Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y, height);
1214  
1215 // Vertex 2
1216 height = Heightmap[hy, hx].Data[(y + 1) * 16 + x];
1217 color = height / MaxHeight;
1218 red = (selected) ? 1f : color;
1219  
1220 Gl.glColor3f(red, color, color);
1221 Gl.glTexCoord2f(0f, 1f);
1222 Gl.glVertex3f(hx * 16 + x, hy * 16 + y + 1, height);
1223  
1224 // Vertex 3
1225 height = Heightmap[hy, hx].Data[(y + 1) * 16 + (x + 1)];
1226 color = height / MaxHeight;
1227 red = (selected) ? 1f : color;
1228  
1229 Gl.glColor3f(red, color, color);
1230 Gl.glTexCoord2f(1f, 1f);
1231 Gl.glVertex3f(hx * 16 + x + 1, hy * 16 + y + 1, height);
1232 }
1233  
1234 Gl.glEnd();
1235 }
1236  
1237 Gl.glPopName();
1238 }
1239 }
1240 }
1241 }
1242  
1243 //int[] CubeMapDefines = new int[]
1244 //{
1245 // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1246 // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1247 // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1248 // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1249 // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1250 // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1251 //};
1252  
1253 private void RenderPrims()
1254 {
1255 if (RenderPrimList != null && RenderPrimList.Count > 0)
1256 {
1257 Gl.glEnable(Gl.GL_TEXTURE_2D);
1258  
1259 lock (RenderPrimList)
1260 {
1261 bool firstPass = true;
1262 Gl.glDisable(Gl.GL_BLEND);
1263 Gl.glEnable(Gl.GL_DEPTH_TEST);
1264  
1265 StartRender:
1266  
1267 foreach (RenderablePrim render in RenderPrimList.Values)
1268 {
1269 RenderablePrim parentRender = RenderablePrim.Empty;
1270 Primitive prim = render.Prim;
1271  
1272 if (prim.ParentID != 0)
1273 {
1274 // Get the parent reference
1275 if (!RenderPrimList.TryGetValue(prim.ParentID, out parentRender))
1276 {
1277 // Can't render a child with no parent prim, skip it
1278 continue;
1279 }
1280 }
1281  
1282 Gl.glPushName(prim.LocalID);
1283 Gl.glPushMatrix();
1284  
1285 if (prim.ParentID != 0)
1286 {
1287 // Child prim
1288 Primitive parent = parentRender.Prim;
1289  
1290 // Apply parent translation and rotation
1291 Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(parent.Position));
1292 Gl.glMultMatrixf(Math3D.CreateRotationMatrix(parent.Rotation));
1293 }
1294  
1295 // Apply prim translation and rotation
1296 Gl.glMultMatrixf(Math3D.CreateTranslationMatrix(prim.Position));
1297 Gl.glMultMatrixf(Math3D.CreateRotationMatrix(prim.Rotation));
1298  
1299 // Scale the prim
1300 Gl.glScalef(prim.Scale.X, prim.Scale.Y, prim.Scale.Z);
1301  
1302 // Draw the prim faces
1303 for (int j = 0; j < render.Mesh.Faces.Count; j++)
1304 {
1305 Face face = render.Mesh.Faces[j];
1306 FaceData data = (FaceData)face.UserData;
1307 Color4 color = face.TextureFace.RGBA;
1308 bool alpha = false;
1309 int textureID = 0;
1310  
1311 if (color.A < 1.0f)
1312 alpha = true;
1313  
1314 #region Texturing
1315  
1316 TextureInfo info;
1317 if (Textures.TryGetValue(face.TextureFace.TextureID, out info))
1318 {
1319 if (info.Alpha)
1320 alpha = true;
1321  
1322 textureID = info.ID;
1323  
1324 // Enable texturing for this face
1325 Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL);
1326 }
1327 else
1328 {
1329 if (face.TextureFace.TextureID == Primitive.TextureEntry.WHITE_TEXTURE ||
1330 face.TextureFace.TextureID == UUID.Zero)
1331 {
1332 Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_FILL);
1333 }
1334 else
1335 {
1336 Gl.glPolygonMode(Gl.GL_FRONT, Gl.GL_LINE);
1337 }
1338 }
1339  
1340 if (firstPass && !alpha || !firstPass && alpha)
1341 {
1342 // Color this prim differently based on whether it is selected or not
1343 if (LastHit == prim.LocalID || (LastHit != 0 && LastHit == prim.ParentID))
1344 {
1345 Gl.glColor4f(1f, color.G * 0.3f, color.B * 0.3f, color.A);
1346 }
1347 else
1348 {
1349 Gl.glColor4f(color.R, color.G, color.B, color.A);
1350 }
1351  
1352 // Bind the texture
1353 Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
1354  
1355 Gl.glTexCoordPointer(2, Gl.GL_FLOAT, 0, data.TexCoords);
1356 Gl.glVertexPointer(3, Gl.GL_FLOAT, 0, data.Vertices);
1357 Gl.glDrawElements(Gl.GL_TRIANGLES, data.Indices.Length, Gl.GL_UNSIGNED_SHORT, data.Indices);
1358 }
1359  
1360 #endregion Texturing
1361 }
1362  
1363 Gl.glPopMatrix();
1364 Gl.glPopName();
1365 }
1366  
1367 if (firstPass)
1368 {
1369 firstPass = false;
1370 Gl.glEnable(Gl.GL_BLEND);
1371 Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
1372 //Gl.glDisable(Gl.GL_DEPTH_TEST);
1373  
1374 goto StartRender;
1375 }
1376 }
1377  
1378 Gl.glEnable(Gl.GL_DEPTH_TEST);
1379 Gl.glDisable(Gl.GL_TEXTURE_2D);
1380 }
1381 }
1382  
1383 private void RenderAvatars()
1384 {
1385 if (Client != null && Client.Network.CurrentSim != null)
1386 {
1387 Gl.glColor3f(0f, 1f, 0f);
1388  
1389 Client.Network.CurrentSim.ObjectsAvatars.ForEach(
1390 delegate(Avatar avatar)
1391 {
1392 Gl.glPushMatrix();
1393 Gl.glTranslatef(avatar.Position.X, avatar.Position.Y, avatar.Position.Z);
1394  
1395 Glu.GLUquadric quad = Glu.gluNewQuadric();
1396 Glu.gluSphere(quad, 1.0d, 10, 10);
1397 Glu.gluDeleteQuadric(quad);
1398  
1399 Gl.glPopMatrix();
1400 }
1401 );
1402  
1403 Gl.glColor3f(1f, 1f, 1f);
1404 }
1405 }
1406  
1407 #region Texture Downloading
1408  
1409 private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset)
1410 {
1411 bool alpha = false;
1412 ManagedImage imgData = null;
1413 byte[] raw = null;
1414  
1415 bool success = (state == TextureRequestState.Finished);
1416  
1417 UUID id = asset.AssetID;
1418  
1419 try
1420 {
1421 // Load the image off the disk
1422 if (success)
1423 {
1424 //ImageDownload download = TextureDownloader.GetTextureToRender(id);
1425 if (OpenJPEG.DecodeToImage(asset.AssetData, out imgData))
1426 {
1427 raw = imgData.ExportRaw();
1428  
1429 if ((imgData.Channels & ManagedImage.ImageChannels.Alpha) != 0)
1430 alpha = true;
1431 }
1432 else
1433 {
1434 success = false;
1435 Console.WriteLine("Failed to decode texture");
1436 }
1437 }
1438  
1439 // Make sure the OpenGL commands run on the main thread
1440 BeginInvoke(
1441 (MethodInvoker)delegate()
1442 {
1443 if (success)
1444 {
1445 int textureID = 0;
1446  
1447 try
1448 {
1449 Gl.glGenTextures(1, out textureID);
1450 Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureID);
1451  
1452 Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_NEAREST); //Gl.GL_NEAREST);
1453 Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
1454 Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
1455 Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
1456 Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE); //Gl.GL_FALSE);
1457  
1458 //Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, bitmap.Width, bitmap.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE,
1459 // bitmapData.Scan0);
1460 //int error = Gl.glGetError();
1461  
1462 int error = Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGBA, imgData.Width, imgData.Height, Gl.GL_BGRA,
1463 Gl.GL_UNSIGNED_BYTE, raw);
1464  
1465 if (error == 0)
1466 {
1467 Textures[id] = new TextureInfo(textureID, alpha);
1468 Console.WriteLine("Created OpenGL texture for " + id.ToString());
1469 }
1470 else
1471 {
1472 Textures[id] = new TextureInfo(0, false);
1473 Console.WriteLine("Error creating OpenGL texture: " + error);
1474 }
1475 }
1476 catch (Exception ex)
1477 {
1478 Console.WriteLine(ex);
1479 }
1480 }
1481  
1482 // Remove this image from the download listbox
1483 lock (DownloadList)
1484 {
1485 GlacialComponents.Controls.GLItem item;
1486 if (DownloadList.TryGetValue(id, out item))
1487 {
1488 DownloadList.Remove(id);
1489 try { lstDownloads.Items.Remove(item); }
1490 catch (Exception) { }
1491 lstDownloads.Invalidate();
1492 }
1493 }
1494 });
1495 }
1496 catch (Exception ex)
1497 {
1498 Console.WriteLine(ex);
1499 }
1500 }
1501  
1502 private void Assets_ImageReceiveProgress(object sender, ImageReceiveProgressEventArgs e)
1503 {
1504 lock (DownloadList)
1505 {
1506 GlacialComponents.Controls.GLItem item;
1507 if (DownloadList.TryGetValue(e.ImageID, out item))
1508 {
1509 // Update an existing item
1510 BeginInvoke(
1511 (MethodInvoker)delegate()
1512 {
1513 ProgressBar prog = (ProgressBar)item.SubItems[1].Control;
1514 if (e.Total >= e.Received)
1515 prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
1516 });
1517 }
1518 else
1519 {
1520 // Progress bar
1521 ProgressBar prog = new ProgressBar();
1522 prog.Minimum = 0;
1523 prog.Maximum = 100;
1524 if (e.Total >= e.Received)
1525 prog.Value = (int)Math.Round((((double)e.Received / (double)e.Total) * 100.0d));
1526 else
1527 prog.Value = 0;
1528  
1529 // List item
1530 item = new GlacialComponents.Controls.GLItem();
1531 item.SubItems[0].Text = e.ImageID.ToString();
1532 item.SubItems[1].Control = prog;
1533  
1534 DownloadList[e.ImageID] = item;
1535  
1536 BeginInvoke(
1537 (MethodInvoker)delegate()
1538 {
1539 lstDownloads.Items.Add(item);
1540 lstDownloads.Invalidate();
1541 });
1542 }
1543 }
1544 }
1545  
1546 #endregion Texture Downloading
1547  
1548 private void frmBrowser_FormClosing(object sender, FormClosingEventArgs e)
1549 {
1550 DoLogout();
1551  
1552 Application.Idle -= IdleEvent;
1553 }
1554  
1555 private void Application_Idle(object sender, EventArgs e)
1556 {
1557 while (AppStillIdle)
1558 {
1559 RenderScene();
1560 }
1561 }
1562  
1563 private void cmdLogin_Click(object sender, EventArgs e)
1564 {
1565 if (cmdLogin.Text == "Login")
1566 {
1567 // Check that all the input boxes are filled in
1568 if (txtFirst.Text.Length == 0)
1569 {
1570 txtFirst.Select();
1571 return;
1572 }
1573 if (txtLast.Text.Length == 0)
1574 {
1575 txtLast.Select();
1576 return;
1577 }
1578 if (txtPass.Text.Length == 0)
1579 {
1580 txtPass.Select();
1581 return;
1582 }
1583  
1584 // Disable input controls
1585 txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = false;
1586 cmdLogin.Text = "Logout";
1587  
1588 // Sanity check that we aren't already logged in
1589 if (Client != null && Client.Network.Connected)
1590 {
1591 Client.Network.Logout();
1592 }
1593  
1594 // Re-initialize everything
1595 InitializeObjects();
1596  
1597 // Start the login
1598 LoginParams loginParams = Client.Network.DefaultLoginParams(txtFirst.Text, txtLast.Text,
1599 txtPass.Text, "Prim Preview", "0.0.1");
1600  
1601 if (!String.IsNullOrEmpty(cboServer.Text))
1602 loginParams.URI = cboServer.Text;
1603  
1604 Client.Network.BeginLogin(loginParams);
1605 }
1606 else
1607 {
1608 DoLogout();
1609 }
1610 }
1611  
1612 private void DoLogout()
1613 {
1614 if (Client != null && Client.Network.Connected)
1615 {
1616 Client.Network.Logout();
1617 return;
1618 }
1619  
1620 // Clear the download list
1621 lstDownloads.Items.Clear();
1622  
1623 // Set the login button back to login state
1624 cmdLogin.Text = "Login";
1625  
1626 // Enable input controls
1627 txtFirst.Enabled = txtLast.Enabled = txtPass.Enabled = true;
1628 }
1629  
1630 private void glControl_Resize(object sender, EventArgs e)
1631 {
1632 Gl.glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
1633  
1634 Gl.glViewport(0, 0, glControl.Width, glControl.Height);
1635  
1636 Gl.glPushMatrix();
1637 Gl.glMatrixMode(Gl.GL_PROJECTION);
1638 Gl.glLoadIdentity();
1639  
1640 SetPerspective();
1641  
1642 Gl.glMatrixMode(Gl.GL_MODELVIEW);
1643 Gl.glPopMatrix();
1644  
1645 // Set the center of the glControl as the default pivot point
1646 LastPivot = glControl.PointToScreen(new Point(glControl.Width / 2, glControl.Height / 2));
1647 }
1648  
1649 private void glControl_MouseClick(object sender, MouseEventArgs e)
1650 {
1651 if ((Control.ModifierKeys & Keys.Alt) == 0 && e.Button == MouseButtons.Left)
1652 {
1653 // Only allow clicking if alt is not being held down
1654 ClickX = e.X;
1655 ClickY = e.Y;
1656 Clicked = true;
1657 }
1658 }
1659  
1660 private void glControl_MouseDown(object sender, MouseEventArgs e)
1661 {
1662 if ((Control.ModifierKeys & Keys.Alt) != 0 && LastHit > 0)
1663 {
1664 // Alt is held down and we have a valid target
1665 Pivoting = true;
1666 PivotPosition = Camera.FocalPoint;
1667  
1668 Control control = (Control)sender;
1669 LastPivot = control.PointToScreen(new Point(e.X, e.Y));
1670 }
1671 }
1672  
1673 private void glControl_MouseMove(object sender, MouseEventArgs e)
1674 {
1675 if (Pivoting)
1676 {
1677 float a, x, y, z;
1678  
1679 Control control = (Control)sender;
1680 Point mouse = control.PointToScreen(new Point(e.X, e.Y));
1681  
1682 // Calculate the deltas from the center of the control to the current position
1683 int deltaX = (int)((mouse.X - LastPivot.X) * -0.5d);
1684 int deltaY = (int)((mouse.Y - LastPivot.Y) * -0.5d);
1685  
1686 // Translate so the focal point is the origin
1687 Vector3 altered = Camera.Position - Camera.FocalPoint;
1688  
1689 // Rotate the translated point by deltaX
1690 a = (float)deltaX * DEG_TO_RAD;
1691 x = (float)((altered.X * Math.Cos(a)) - (altered.Y * Math.Sin(a)));
1692 y = (float)((altered.X * Math.Sin(a)) + (altered.Y * Math.Cos(a)));
1693  
1694 altered.X = x;
1695 altered.Y = y;
1696  
1697 // Rotate the translated point by deltaY
1698 a = (float)deltaY * DEG_TO_RAD;
1699 y = (float)((altered.Y * Math.Cos(a)) - (altered.Z * Math.Sin(a)));
1700 z = (float)((altered.Y * Math.Sin(a)) + (altered.Z * Math.Cos(a)));
1701  
1702 altered.Y = y;
1703 altered.Z = z;
1704  
1705 // Translate back to world space
1706 altered += Camera.FocalPoint;
1707  
1708 // Update the camera
1709 Camera.Position = altered;
1710 UpdateCamera();
1711  
1712 // Update the pivot point
1713 LastPivot = mouse;
1714 }
1715 }
1716  
1717 private void glControl_MouseWheel(object sender, MouseEventArgs e)
1718 {
1719 /*if (e.Delta != 0)
1720 {
1721 Camera.Zoom = Camera.Zoom + (double)(e.Delta / 120) * -0.1d;
1722 if (Camera.Zoom < 0.05d) Camera.Zoom = 0.05d;
1723 UpdateCamera();
1724 }*/
1725  
1726 if (e.Delta != 0)
1727 {
1728 // Calculate the distance to move to/away
1729 float dist = (float)(e.Delta / 120) * 10.0f;
1730  
1731 if (Vector3.Distance(Camera.Position, Camera.FocalPoint) > dist)
1732 {
1733 // Move closer or further away from the focal point
1734 Vector3 toFocal = Camera.FocalPoint - Camera.Position;
1735 toFocal.Normalize();
1736  
1737 toFocal = toFocal * dist;
1738  
1739 Camera.Position += toFocal;
1740 UpdateCamera();
1741 }
1742 }
1743 }
1744  
1745 private void glControl_MouseUp(object sender, MouseEventArgs e)
1746 {
1747 // Stop pivoting if we were previously
1748 Pivoting = false;
1749 }
1750  
1751 private void txtLogin_Enter(object sender, EventArgs e)
1752 {
1753 TextBox input = (TextBox)sender;
1754 input.SelectAll();
1755 }
1756  
1757 private void cmdTeleport_Click(object sender, EventArgs e)
1758 {
1759 if (!String.IsNullOrEmpty(txtSim.Text))
1760 {
1761 // Parse X/Y/Z
1762 int x, y, z;
1763 if (!Int32.TryParse(txtX.Text, out x))
1764 {
1765 txtX.SelectAll();
1766 return;
1767 }
1768 if (!Int32.TryParse(txtY.Text, out y))
1769 {
1770 txtY.SelectAll();
1771 return;
1772 }
1773 if (!Int32.TryParse(txtZ.Text, out z))
1774 {
1775 txtZ.SelectAll();
1776 return;
1777 }
1778  
1779 string simName = txtSim.Text.Trim().ToLower();
1780 Vector3 position = new Vector3(x, y, z);
1781  
1782 if (Client != null && Client.Network.CurrentSim != null)
1783 {
1784 // Check for a local teleport to shortcut the process
1785 if (simName == Client.Network.CurrentSim.Name.ToLower())
1786 {
1787 // Local teleport
1788 Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, position);
1789 }
1790 else
1791 {
1792 // Cross-sim teleport
1793 bool success = false;
1794  
1795 BackgroundWorker worker = new BackgroundWorker();
1796 worker.DoWork += delegate(object s, DoWorkEventArgs ea) { success = Client.Self.Teleport(simName, position); };
1797 worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ea)
1798 {
1799 BeginInvoke((MethodInvoker)
1800 delegate()
1801 {
1802 if (!success)
1803 System.Windows.Forms.MessageBox.Show("Teleport failed");
1804 });
1805 };
1806  
1807 worker.RunWorkerAsync();
1808 }
1809 }
1810 else
1811 {
1812 // Oops! How did the user click this...
1813 cmdTeleport.Enabled = false;
1814 }
1815 }
1816 }
1817 }
1818  
1819 public struct TextureInfo
1820 {
1821 /// <summary>OpenGL Texture ID</summary>
1822 public int ID;
1823 /// <summary>True if this texture has an alpha component</summary>
1824 public bool Alpha;
1825  
1826 public TextureInfo(int id, bool alpha)
1827 {
1828 ID = id;
1829 Alpha = alpha;
1830 }
1831 }
1832  
1833 public struct HeightmapLookupValue : IComparable<HeightmapLookupValue>
1834 {
1835 public ushort Index;
1836 public float Value;
1837  
1838 public HeightmapLookupValue(ushort index, float value)
1839 {
1840 Index = index;
1841 Value = value;
1842 }
1843  
1844 public int CompareTo(HeightmapLookupValue val)
1845 {
1846 return Value.CompareTo(val.Value);
1847 }
1848 }
1849  
1850 public struct RenderablePrim
1851 {
1852 public Primitive Prim;
1853 public FacetedMesh Mesh;
1854  
1855 public readonly static RenderablePrim Empty = new RenderablePrim();
1856 }
1857  
1858 public struct Camera
1859 {
1860 public Vector3 Position;
1861 public Vector3 FocalPoint;
1862 public double Zoom;
1863 public double Far;
1864 }
1865  
1866 public struct NativeMethods
1867 {
1868 [StructLayout(LayoutKind.Sequential)]
1869 public struct Message
1870 {
1871 public IntPtr HWnd;
1872 public uint Msg;
1873 public IntPtr WParam;
1874 public IntPtr LParam;
1875 public uint Time;
1876 public System.Drawing.Point Point;
1877 }
1878  
1879 //[System.Security.SuppressUnmanagedCodeSecurity]
1880 [DllImport("User32.dll", CharSet = CharSet.Auto)]
1881 public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
1882 }
1883  
1884 public static class Math3D
1885 {
1886 // Column-major:
1887 // | 0 4 8 12 |
1888 // | 1 5 9 13 |
1889 // | 2 6 10 14 |
1890 // | 3 7 11 15 |
1891  
1892 public static float[] CreateTranslationMatrix(Vector3 v)
1893 {
1894 float[] mat = new float[16];
1895  
1896 mat[12] = v.X;
1897 mat[13] = v.Y;
1898 mat[14] = v.Z;
1899 mat[0] = mat[5] = mat[10] = mat[15] = 1;
1900  
1901 return mat;
1902 }
1903  
1904 public static float[] CreateRotationMatrix(Quaternion q)
1905 {
1906 float[] mat = new float[16];
1907  
1908 // Transpose the quaternion (don't ask me why)
1909 q.X = q.X * -1f;
1910 q.Y = q.Y * -1f;
1911 q.Z = q.Z * -1f;
1912  
1913 float x2 = q.X + q.X;
1914 float y2 = q.Y + q.Y;
1915 float z2 = q.Z + q.Z;
1916 float xx = q.X * x2;
1917 float xy = q.X * y2;
1918 float xz = q.X * z2;
1919 float yy = q.Y * y2;
1920 float yz = q.Y * z2;
1921 float zz = q.Z * z2;
1922 float wx = q.W * x2;
1923 float wy = q.W * y2;
1924 float wz = q.W * z2;
1925  
1926 mat[0] = 1.0f - (yy + zz);
1927 mat[1] = xy - wz;
1928 mat[2] = xz + wy;
1929 mat[3] = 0.0f;
1930  
1931 mat[4] = xy + wz;
1932 mat[5] = 1.0f - (xx + zz);
1933 mat[6] = yz - wx;
1934 mat[7] = 0.0f;
1935  
1936 mat[8] = xz - wy;
1937 mat[9] = yz + wx;
1938 mat[10] = 1.0f - (xx + yy);
1939 mat[11] = 0.0f;
1940  
1941 mat[12] = 0.0f;
1942 mat[13] = 0.0f;
1943 mat[14] = 0.0f;
1944 mat[15] = 1.0f;
1945  
1946 return mat;
1947 }
1948  
1949 public static float[] CreateScaleMatrix(Vector3 v)
1950 {
1951 float[] mat = new float[16];
1952  
1953 mat[0] = v.X;
1954 mat[5] = v.Y;
1955 mat[10] = v.Z;
1956 mat[15] = 1;
1957  
1958 return mat;
1959 }
1960 }
1961 }