diff options
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs new file mode 100644 index 0000000..de2c3fc --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Security.Cryptography; // for computing md5 hash | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | |||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | |||
46 | using Ionic.Zlib; | ||
47 | |||
48 | // You will need to uncomment these lines if you are adding a region module to some other assembly which does not already | ||
49 | // specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans | ||
50 | // the available DLLs | ||
51 | //[assembly: Addin("MyModule", "1.0")] | ||
52 | //[assembly: AddinDependency("OpenSim", "0.5")] | ||
53 | |||
54 | namespace OpenSim.Region.OptionalModules.MaterialsDemoModule | ||
55 | { | ||
56 | /// <summary> | ||
57 | /// | ||
58 | // # # ## ##### # # # # # #### | ||
59 | // # # # # # # ## # # ## # # # | ||
60 | // # # # # # # # # # # # # # # | ||
61 | // # ## # ###### ##### # # # # # # # # ### | ||
62 | // ## ## # # # # # ## # # ## # # | ||
63 | // # # # # # # # # # # # #### | ||
64 | // | ||
65 | // | ||
66 | // | ||
67 | ////////////// WARNING ////////////////////////////////////////////////////////////////// | ||
68 | /// This is an *Experimental* module for developing support for materials-capable viewers | ||
69 | /// This module should NOT be used in a production environment! It may cause data corruption and | ||
70 | /// viewer crashes. It should be only used to evaluate implementations of materials. | ||
71 | /// | ||
72 | /// CURRENTLY NO MATERIALS ARE PERSISTED ACROSS SIMULATOR RESTARTS OR ARE STORED IN ANY INVENTORY OR ASSETS | ||
73 | /// This may change in future implementations. | ||
74 | /// | ||
75 | /// To enable this module, add this string at the bottom of OpenSim.ini: | ||
76 | /// [MaterialsDemoModule] | ||
77 | /// | ||
78 | /// </summary> | ||
79 | /// | ||
80 | |||
81 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] | ||
82 | public class MaterialsDemoModule : INonSharedRegionModule | ||
83 | { | ||
84 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
85 | |||
86 | public string Name { get { return "MaterialsDemoModule"; } } | ||
87 | |||
88 | public Type ReplaceableInterface { get { return null; } } | ||
89 | |||
90 | private Scene m_scene = null; | ||
91 | private bool m_enabled = false; | ||
92 | |||
93 | public void Initialise(IConfigSource source) | ||
94 | { | ||
95 | m_enabled = (source.Configs["MaterialsDemoModule"] != null); | ||
96 | if (!m_enabled) | ||
97 | return; | ||
98 | |||
99 | m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); | ||
100 | |||
101 | } | ||
102 | |||
103 | public void Close() | ||
104 | { | ||
105 | if (!m_enabled) | ||
106 | return; | ||
107 | |||
108 | m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); | ||
109 | } | ||
110 | |||
111 | public void AddRegion(Scene scene) | ||
112 | { | ||
113 | if (!m_enabled) | ||
114 | return; | ||
115 | |||
116 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
117 | m_scene = scene; | ||
118 | m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); | ||
119 | } | ||
120 | |||
121 | void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) | ||
122 | { | ||
123 | string capsBase = "/CAPS/" + caps.CapsObjectPath; | ||
124 | |||
125 | IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); | ||
126 | caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); | ||
127 | |||
128 | // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET | ||
129 | // and POST handlers, (at least at the time this was originally written), so we first set up a POST | ||
130 | // handler normally and then add a GET handler via MainServer | ||
131 | |||
132 | IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); | ||
133 | MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); | ||
134 | } | ||
135 | |||
136 | public void RemoveRegion(Scene scene) | ||
137 | { | ||
138 | if (!m_enabled) | ||
139 | return; | ||
140 | |||
141 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
142 | } | ||
143 | |||
144 | public void RegionLoaded(Scene scene) | ||
145 | { | ||
146 | if (!m_enabled) | ||
147 | return; | ||
148 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName); | ||
149 | } | ||
150 | |||
151 | public string RenderMaterialsPostCap(string request, string path, | ||
152 | string param, IOSHttpRequest httpRequest, | ||
153 | IOSHttpResponse httpResponse) | ||
154 | { | ||
155 | m_log.Debug("[MaterialsDemoModule]: POST cap handler"); | ||
156 | |||
157 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
158 | OSDMap resp = new OSDMap(); | ||
159 | |||
160 | OSDMap materialsFromViewer = null; | ||
161 | |||
162 | if (req.ContainsKey("Zipped")) | ||
163 | { | ||
164 | OSD osd = null; | ||
165 | |||
166 | byte[] inBytes = req["Zipped"].AsBinary(); | ||
167 | |||
168 | try | ||
169 | { | ||
170 | osd = ZDecompressBytesToOsd(inBytes); | ||
171 | |||
172 | if (osd != null && osd is OSDMap) | ||
173 | { | ||
174 | materialsFromViewer = osd as OSDMap; | ||
175 | |||
176 | if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) | ||
177 | { | ||
178 | OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; | ||
179 | if (matsOsd is OSDArray) | ||
180 | { | ||
181 | OSDArray matsArr = matsOsd as OSDArray; | ||
182 | |||
183 | try | ||
184 | { | ||
185 | foreach (OSDMap matsMap in matsArr) | ||
186 | { | ||
187 | m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); | ||
188 | |||
189 | uint matLocalID = 0; | ||
190 | try { matLocalID = matsMap["ID"].AsUInteger(); } | ||
191 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } | ||
192 | m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); | ||
193 | |||
194 | |||
195 | OSDMap mat = null; | ||
196 | try { mat = matsMap["Material"] as OSDMap; } | ||
197 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } | ||
198 | m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); | ||
199 | |||
200 | UUID id = HashOsd(mat); | ||
201 | m_knownMaterials[id] = mat; | ||
202 | |||
203 | |||
204 | var sop = m_scene.GetSceneObjectPart(matLocalID); | ||
205 | if (sop == null) | ||
206 | m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); | ||
207 | else | ||
208 | { | ||
209 | var te = sop.Shape.Textures; | ||
210 | |||
211 | if (te == null) | ||
212 | { | ||
213 | m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | int face = -1; | ||
218 | |||
219 | if (matsMap.ContainsKey("Face")) | ||
220 | { | ||
221 | face = matsMap["Face"].AsInteger(); | ||
222 | if (te.FaceTextures == null) // && face == 0) | ||
223 | { | ||
224 | if (te.DefaultTexture == null) | ||
225 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); | ||
226 | else | ||
227 | { | ||
228 | if (te.DefaultTexture.MaterialID == null) | ||
229 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); | ||
230 | else | ||
231 | { | ||
232 | te.DefaultTexture.MaterialID = id; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | if (te.FaceTextures.Length >= face - 1) | ||
239 | { | ||
240 | if (te.FaceTextures[face] == null) | ||
241 | te.DefaultTexture.MaterialID = id; | ||
242 | else | ||
243 | te.FaceTextures[face].MaterialID = id; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | if (te.DefaultTexture != null) | ||
250 | te.DefaultTexture.MaterialID = id; | ||
251 | } | ||
252 | |||
253 | m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); | ||
254 | |||
255 | sop.UpdateTextureEntry(te); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | catch (Exception e) | ||
261 | { | ||
262 | m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | catch (Exception e) | ||
269 | { | ||
270 | m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); | ||
271 | //return ""; | ||
272 | } | ||
273 | m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); | ||
274 | } | ||
275 | |||
276 | |||
277 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
278 | |||
279 | m_log.Debug("[MaterialsDemoModule]: cap request: " + request); | ||
280 | m_log.Debug("[MaterialsDemoModule]: cap response: " + response); | ||
281 | return response; | ||
282 | } | ||
283 | |||
284 | |||
285 | public string RenderMaterialsGetCap(string request, string path, | ||
286 | string param, IOSHttpRequest httpRequest, | ||
287 | IOSHttpResponse httpResponse) | ||
288 | { | ||
289 | m_log.Debug("[MaterialsDemoModule]: GET cap handler"); | ||
290 | |||
291 | OSDMap resp = new OSDMap(); | ||
292 | |||
293 | |||
294 | int matsCount = 0; | ||
295 | |||
296 | OSDArray allOsd = new OSDArray(); | ||
297 | |||
298 | foreach (KeyValuePair<UUID, OSDMap> kvp in m_knownMaterials) | ||
299 | { | ||
300 | OSDMap matMap = new OSDMap(); | ||
301 | |||
302 | matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); | ||
303 | |||
304 | matMap["Material"] = kvp.Value; | ||
305 | allOsd.Add(matMap); | ||
306 | matsCount++; | ||
307 | } | ||
308 | |||
309 | |||
310 | resp["Zipped"] = ZCompressOSD(allOsd, false); | ||
311 | m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); | ||
312 | |||
313 | return OSDParser.SerializeLLSDXmlString(resp); | ||
314 | } | ||
315 | |||
316 | public Dictionary<UUID, OSDMap> m_knownMaterials = new Dictionary<UUID, OSDMap>(); | ||
317 | |||
318 | /// <summary> | ||
319 | /// computes a UUID by hashing a OSD object | ||
320 | /// </summary> | ||
321 | /// <param name="osd"></param> | ||
322 | /// <returns></returns> | ||
323 | private static UUID HashOsd(OSD osd) | ||
324 | { | ||
325 | using (var md5 = MD5.Create()) | ||
326 | using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) | ||
327 | return new UUID(md5.ComputeHash(ms), 0); | ||
328 | } | ||
329 | |||
330 | public static OSD ZCompressOSD(OSD inOsd, bool useHeader = true) | ||
331 | { | ||
332 | OSD osd = null; | ||
333 | |||
334 | using (MemoryStream msSinkCompressed = new MemoryStream()) | ||
335 | { | ||
336 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, | ||
337 | Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) | ||
338 | { | ||
339 | CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); | ||
340 | zOut.Close(); | ||
341 | } | ||
342 | |||
343 | msSinkCompressed.Seek(0L, SeekOrigin.Begin); | ||
344 | osd = OSD.FromBinary( msSinkCompressed.ToArray()); | ||
345 | } | ||
346 | |||
347 | return osd; | ||
348 | } | ||
349 | |||
350 | |||
351 | public static OSD ZDecompressBytesToOsd(byte[] input) | ||
352 | { | ||
353 | OSD osd = null; | ||
354 | |||
355 | using (MemoryStream msSinkUnCompressed = new MemoryStream()) | ||
356 | { | ||
357 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) | ||
358 | { | ||
359 | CopyStream(new MemoryStream(input), zOut); | ||
360 | zOut.Close(); | ||
361 | } | ||
362 | msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); | ||
363 | osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); | ||
364 | } | ||
365 | |||
366 | return osd; | ||
367 | } | ||
368 | |||
369 | static void CopyStream(System.IO.Stream input, System.IO.Stream output) | ||
370 | { | ||
371 | byte[] buffer = new byte[2048]; | ||
372 | int len; | ||
373 | while ((len = input.Read(buffer, 0, 2048)) > 0) | ||
374 | { | ||
375 | output.Write(buffer, 0, len); | ||
376 | } | ||
377 | |||
378 | output.Flush(); | ||
379 | } | ||
380 | |||
381 | } | ||
382 | } \ No newline at end of file | ||