corrade-vassal – Blame information for rev 1
?pathlinks?
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 | } |