aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoronefang2020-09-10 21:20:23 +1000
committeronefang2020-09-10 21:20:23 +1000
commit2940f325436f5b07dcfbac03545b3eb96e20ffcf (patch)
tree71babe10d710dac41431d20c8a22387d48f5130b
parentAnother ini file I forgot in the last commit. (diff)
downloadopensim-SC-2940f325436f5b07dcfbac03545b3eb96e20ffcf.zip
opensim-SC-2940f325436f5b07dcfbac03545b3eb96e20ffcf.tar.gz
opensim-SC-2940f325436f5b07dcfbac03545b3eb96e20ffcf.tar.bz2
opensim-SC-2940f325436f5b07dcfbac03545b3eb96e20ffcf.tar.xz
Warp3DCachedImageModule from Christopher Latza.
From - https://clatza.dev/OpenSim/OpenSim.Modules.Warp3DCachedImageModule.git Commit ad0aa59f53ae77c85a7c745d9af5aa70187568ba on 17/5/20 1:37 AM
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/.gitignore287
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/LICENSE25
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/prebuild.xml41
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Perlin.cs264
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/TerrainSplat.cs470
-rw-r--r--addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Warp3DImageModule.cs1073
6 files changed, 2160 insertions, 0 deletions
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/.gitignore b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/.gitignore
new file mode 100644
index 0000000..a752eac
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/.gitignore
@@ -0,0 +1,287 @@
1## Ignore Visual Studio temporary files, build results, and
2## files generated by popular Visual Studio add-ons.
3##
4## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5
6# User-specific files
7*.suo
8*.user
9*.userosscache
10*.sln.docstates
11
12# User-specific files (MonoDevelop/Xamarin Studio)
13*.userprefs
14
15# Build results
16[Dd]ebug/
17[Dd]ebugPublic/
18[Rr]elease/
19[Rr]eleases/
20x64/
21x86/
22bld/
23[Bb]in/
24[Oo]bj/
25[Ll]og/
26
27# Visual Studio 2015 cache/options directory
28.vs/
29# Uncomment if you have tasks that create the project's static files in wwwroot
30#wwwroot/
31
32# MSTest test Results
33[Tt]est[Rr]esult*/
34[Bb]uild[Ll]og.*
35
36# NUNIT
37*.VisualState.xml
38TestResult.xml
39
40# Build Results of an ATL Project
41[Dd]ebugPS/
42[Rr]eleasePS/
43dlldata.c
44
45# .NET Core
46project.lock.json
47project.fragment.lock.json
48artifacts/
49**/Properties/launchSettings.json
50
51*_i.c
52*_p.c
53*_i.h
54*.ilk
55*.meta
56*.obj
57*.pch
58*.pdb
59*.pgc
60*.pgd
61*.rsp
62*.sbr
63*.tlb
64*.tli
65*.tlh
66*.tmp
67*.tmp_proj
68*.log
69*.vspscc
70*.vssscc
71.builds
72*.pidb
73*.svclog
74*.scc
75
76# Chutzpah Test files
77_Chutzpah*
78
79# Visual C++ cache files
80ipch/
81*.aps
82*.ncb
83*.opendb
84*.opensdf
85*.sdf
86*.cachefile
87*.VC.db
88*.VC.VC.opendb
89
90# Visual Studio profiler
91*.psess
92*.vsp
93*.vspx
94*.sap
95
96# TFS 2012 Local Workspace
97$tf/
98
99# Guidance Automation Toolkit
100*.gpState
101
102# ReSharper is a .NET coding add-in
103_ReSharper*/
104*.[Rr]e[Ss]harper
105*.DotSettings.user
106
107# JustCode is a .NET coding add-in
108.JustCode
109
110# TeamCity is a build add-in
111_TeamCity*
112
113# DotCover is a Code Coverage Tool
114*.dotCover
115
116# Visual Studio code coverage results
117*.coverage
118*.coveragexml
119
120# NCrunch
121_NCrunch_*
122.*crunch*.local.xml
123nCrunchTemp_*
124
125# MightyMoose
126*.mm.*
127AutoTest.Net/
128
129# Web workbench (sass)
130.sass-cache/
131
132# Installshield output folder
133[Ee]xpress/
134
135# DocProject is a documentation generator add-in
136DocProject/buildhelp/
137DocProject/Help/*.HxT
138DocProject/Help/*.HxC
139DocProject/Help/*.hhc
140DocProject/Help/*.hhk
141DocProject/Help/*.hhp
142DocProject/Help/Html2
143DocProject/Help/html
144
145# Click-Once directory
146publish/
147
148# Publish Web Output
149*.[Pp]ublish.xml
150*.azurePubxml
151# TODO: Comment the next line if you want to checkin your web deploy settings
152# but database connection strings (with potential passwords) will be unencrypted
153*.pubxml
154*.publishproj
155
156# Microsoft Azure Web App publish settings. Comment the next line if you want to
157# checkin your Azure Web App publish settings, but sensitive information contained
158# in these scripts will be unencrypted
159PublishScripts/
160
161# NuGet Packages
162*.nupkg
163# The packages folder can be ignored because of Package Restore
164**/packages/*
165# except build/, which is used as an MSBuild target.
166!**/packages/build/
167# Uncomment if necessary however generally it will be regenerated when needed
168#!**/packages/repositories.config
169# NuGet v3's project.json files produces more ignorable files
170*.nuget.props
171*.nuget.targets
172
173# Microsoft Azure Build Output
174csx/
175*.build.csdef
176
177# Microsoft Azure Emulator
178ecf/
179rcf/
180
181# Windows Store app package directories and files
182AppPackages/
183BundleArtifacts/
184Package.StoreAssociation.xml
185_pkginfo.txt
186
187# Visual Studio cache files
188# files ending in .cache can be ignored
189*.[Cc]ache
190# but keep track of directories ending in .cache
191!*.[Cc]ache/
192
193# Others
194ClientBin/
195~$*
196*~
197*.dbmdl
198*.dbproj.schemaview
199*.jfm
200*.pfx
201*.publishsettings
202orleans.codegen.cs
203
204# Since there are multiple workflows, uncomment next line to ignore bower_components
205# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206#bower_components/
207
208# RIA/Silverlight projects
209Generated_Code/
210
211# Backup & report files from converting an old project file
212# to a newer Visual Studio version. Backup files are not needed,
213# because we have git ;-)
214_UpgradeReport_Files/
215Backup*/
216UpgradeLog*.XML
217UpgradeLog*.htm
218
219# SQL Server files
220*.mdf
221*.ldf
222
223# Business Intelligence projects
224*.rdl.data
225*.bim.layout
226*.bim_*.settings
227
228# Microsoft Fakes
229FakesAssemblies/
230
231# GhostDoc plugin setting file
232*.GhostDoc.xml
233
234# Node.js Tools for Visual Studio
235.ntvs_analysis.dat
236node_modules/
237
238# Typescript v1 declaration files
239typings/
240
241# Visual Studio 6 build log
242*.plg
243
244# Visual Studio 6 workspace options file
245*.opt
246
247# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
248*.vbw
249
250# Visual Studio LightSwitch build output
251**/*.HTMLClient/GeneratedArtifacts
252**/*.DesktopClient/GeneratedArtifacts
253**/*.DesktopClient/ModelManifest.xml
254**/*.Server/GeneratedArtifacts
255**/*.Server/ModelManifest.xml
256_Pvt_Extensions
257
258# Paket dependency manager
259.paket/paket.exe
260paket-files/
261
262# FAKE - F# Make
263.fake/
264
265# JetBrains Rider
266.idea/
267*.sln.iml
268
269# CodeRush
270.cr/
271
272# Python Tools for Visual Studio (PTVS)
273__pycache__/
274*.pyc
275
276# Cake - Uncomment if you are using it
277# tools/**
278# !tools/packages.config
279
280# Telerik's JustMock configuration file
281*.jmconfig
282
283# BizTalk build output
284*.btp.cs
285*.btm.cs
286*.odx.cs
287*.xsd.cs \ No newline at end of file
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/LICENSE b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/LICENSE
new file mode 100644
index 0000000..570f732
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/LICENSE
@@ -0,0 +1,25 @@
1Copyright (c) Contributors, http://opensimulator.org/
2See CONTRIBUTORS.TXT for a full list of copyright holders.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 * Neither the name of the OpenSimulator Project nor the
12 names of its contributors may be used to endorse or promote products
13 derived from this software without specific prior written permission.
14
15THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
16IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
19DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/prebuild.xml b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/prebuild.xml
new file mode 100644
index 0000000..df5b460
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/prebuild.xml
@@ -0,0 +1,41 @@
1<Project frameworkVersion="v4_6" name="OpenSim.Modules.Warp3DCachedImageModule" path="addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src" type="Library">
2 <Configuration name="Debug">
3 <Options>
4 <OutputPath>../../../bin</OutputPath>
5 </Options>
6 </Configuration>
7 <Configuration name="Release">
8 <Options>
9 <OutputPath>../../../bin</OutputPath>
10 </Options>
11 </Configuration>
12
13 <ReferencePath>../../../bin</ReferencePath>
14 <Reference name="System" localCopy="false"/>
15 <Reference name="System.Xml"/>
16 <Reference name="System.Drawing"/>
17 <Reference name="System.Runtime.Remoting"/>
18 <Reference name="Nini.dll" path="../../../bin"/>
19 <Reference name="log4net.dll" path="../../../bin"/>
20 <Reference name="XMLRPC.dll" path="../../../bin"/>
21 <Reference name="CSJ2K.dll" path="../../../bin"/>
22 <Reference name="Warp3D.dll" path="../../../bin"/>
23 <Reference name="Mono.Addins.dll" path="../../../bin"/>
24 <Reference name="OpenMetaverseTypes.dll" path="../../../bin"/>
25 <Reference name="OpenSim.Region.PhysicsModules.SharedBase.dll" path="../../../bin"/>
26 <Reference name="OpenMetaverse.dll" path="../../../bin"/>
27 <Reference name="OpenMetaverse.StructuredData.dll" path="../../../bin"/>
28 <Reference name="HttpServer_OpenSim.dll" path="../../../bin"/>
29 <Reference name="OpenSim.Region.Framework" path="../../../bin"/>
30 <Reference name="OpenSim.Framework" path="../../../bin"/>
31 <Reference name="OpenSim.Framework.Console" path="../../../bin"/>
32 <Reference name="OpenSim.Framework.Servers" path="../../../bin"/>
33 <Reference name="OpenSim.Framework.Servers.HttpServer" path="../../../bin"/>
34 <Reference name="OpenSim.Services.Interfaces" path="../../../bin"/>
35 <Reference name="OpenSim.Server.Base" path="../../../bin"/>
36 <Reference name="OpenSim.Data" path="../../../bin"/>
37
38 <Files>
39 <Match pattern="*.cs" recurse="true"/>
40 </Files>
41</Project>
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Perlin.cs b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Perlin.cs
new file mode 100644
index 0000000..2279b76
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Perlin.cs
@@ -0,0 +1,264 @@
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
28using System;
29using OpenMetaverse;
30
31namespace OpenSim.Region.CoreModules.World.Warp3DMap
32{
33 public static class Perlin
34 {
35 // We use a hardcoded seed to keep the noise generation consistent between runs
36 private const int SEED = 42;
37
38 private const int SAMPLE_SIZE = 1024;
39 private const int B = SAMPLE_SIZE;
40 private const int BM = SAMPLE_SIZE - 1;
41 private const int N = 0x1000;
42
43 private static readonly int[] p = new int[SAMPLE_SIZE + SAMPLE_SIZE + 2];
44 private static readonly float[,] g3 = new float[SAMPLE_SIZE + SAMPLE_SIZE + 2, 3];
45 private static readonly float[,] g2 = new float[SAMPLE_SIZE + SAMPLE_SIZE + 2, 2];
46 private static readonly float[] g1 = new float[SAMPLE_SIZE + SAMPLE_SIZE + 2];
47
48 static Perlin()
49 {
50 Random rng = new Random(SEED);
51 int i, j, k;
52
53 for (i = 0; i < B; i++)
54 {
55 p[i] = i;
56 g1[i] = (float)((rng.Next() % (B + B)) - B) / B;
57
58 for (j = 0; j < 2; j++)
59 g2[i, j] = (float)((rng.Next() % (B + B)) - B) / B;
60 normalize2(g2, i);
61
62 for (j = 0; j < 3; j++)
63 g3[i, j] = (float)((rng.Next() % (B + B)) - B) / B;
64 normalize3(g3, i);
65 }
66
67 while (--i > 0)
68 {
69 k = p[i];
70 p[i] = p[j = rng.Next() % B];
71 p[j] = k;
72 }
73
74 for (i = 0; i < B + 2; i++)
75 {
76 p[B + i] = p[i];
77 g1[B + i] = g1[i];
78 for (j = 0; j < 2; j++)
79 g2[B + i, j] = g2[i, j];
80 for (j = 0; j < 3; j++)
81 g3[B + i, j] = g3[i, j];
82 }
83 }
84
85 public static float noise1(float arg)
86 {
87 int bx0, bx1;
88 float rx0, rx1, sx, t, u, v;
89
90 t = arg + N;
91 bx0 = ((int)t) & BM;
92 bx1 = (bx0 + 1) & BM;
93 rx0 = t - (int)t;
94 rx1 = rx0 - 1f;
95
96 sx = s_curve(rx0);
97
98 u = rx0 * g1[p[bx0]];
99 v = rx1 * g1[p[bx1]];
100
101 return Utils.Lerp(u, v, sx);
102 }
103
104 public static float noise2(float x, float y)
105 {
106 int bx, by, b00, b10, b01, b11;
107 float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
108 int i, j;
109
110 t = x + N;
111 rx0 = t - (int)t;
112 bx = ((int)t) & BM;
113 i = p[bx];
114 bx = (bx + 1) & BM;
115 j = p[bx];
116
117 t = y + N;
118 ry0 = t - (int)t;
119 by = ((int)t) & BM;
120 b00 = p[i + by];
121 b10 = p[j + by];
122
123 by = (by + 1) & BM;
124 b01 = p[i + by];
125 b11 = p[j + by];
126
127 sx = s_curve(rx0);
128 u = rx0 * g2[b00, 0] + ry0 * g2[b00, 1];
129 rx1 = rx0 - 1f;
130 v = rx1 * g2[b10, 0] + ry0 * g2[b10, 1];
131 a = Utils.Lerp(u, v, sx);
132
133 ry1 = ry0 - 1f;
134 u = rx0 * g2[b01, 0] + ry1 * g2[b01, 1];
135 v = rx1 * g2[b11, 0] + ry1 * g2[b11, 1];
136 b = Utils.Lerp(u, v, sx);
137
138 sy = s_curve(ry0);
139 return Utils.Lerp(a, b, sy);
140 }
141
142 public static float noise3(float x, float y, float z)
143 {
144 int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
145 float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
146 int i, j;
147
148 t = x + N;
149 bx0 = ((int)t) & BM;
150 bx1 = (bx0 + 1) & BM;
151 rx0 = t - (int)t;
152 rx1 = rx0 - 1f;
153
154 t = y + N;
155 by0 = ((int)t) & BM;
156 by1 = (by0 + 1) & BM;
157 ry0 = t - (int)t;
158 ry1 = ry0 - 1f;
159
160 t = z + N;
161 bz0 = ((int)t) & BM;
162 bz1 = (bz0 + 1) & BM;
163 rz0 = t - (int)t;
164 rz1 = rz0 - 1f;
165
166 i = p[bx0];
167 j = p[bx1];
168
169 b00 = p[i + by0];
170 b10 = p[j + by0];
171 b01 = p[i + by1];
172 b11 = p[j + by1];
173
174 t = s_curve(rx0);
175 sy = s_curve(ry0);
176 sz = s_curve(rz0);
177
178 u = rx0 * g3[b00 + bz0, 0] + ry0 * g3[b00 + bz0, 1] + rz0 * g3[b00 + bz0, 2];
179 v = rx1 * g3[b10 + bz0, 0] + ry0 * g3[b10 + bz0, 1] + rz0 * g3[b10 + bz0, 2];
180 a = Utils.Lerp(u, v, t);
181
182 u = rx0 * g3[b01 + bz0, 0] + ry1 * g3[b01 + bz0, 1] + rz0 * g3[b01 + bz0, 2];
183 v = rx1 * g3[b11 + bz0, 0] + ry1 * g3[b11 + bz0, 1] + rz0 * g3[b11 + bz0, 2];
184 b = Utils.Lerp(u, v, t);
185
186 c = Utils.Lerp(a, b, sy);
187
188 u = rx0 * g3[b00 + bz1, 0] + ry0 * g3[b00 + bz1, 1] + rz1 * g3[b00 + bz1, 2];
189 v = rx1 * g3[b10 + bz1, 0] + ry0 * g3[b10 + bz1, 1] + rz1 * g3[b10 + bz1, 2];
190 a = Utils.Lerp(u, v, t);
191
192 u = rx0 * g3[b01 + bz1, 0] + ry1 * g3[b01 + bz1, 1] + rz1 * g3[b01 + bz1, 2];
193 v = rx1 * g3[b11 + bz1, 0] + ry1 * g3[b11 + bz1, 1] + rz1 * g3[b11 + bz1, 2];
194 b = Utils.Lerp(u, v, t);
195
196 d = Utils.Lerp(a, b, sy);
197 return Utils.Lerp(c, d, sz);
198 }
199
200 public static float turbulence1(float x, float freq)
201 {
202 float t;
203
204 for (t = 0f; freq >= 1f; freq *= 0.5f)
205 {
206 t += noise1(freq * x) / freq;
207 }
208 return t;
209 }
210
211 public static float turbulence2(float x, float y, float freq)
212 {
213 float t;
214
215 for (t = 0f; freq >= 1f; freq *= 0.5f)
216 t += noise2(freq * x, freq * y) / freq;
217
218 return t;
219 }
220
221 public static float turbulence3(float x, float y, float z, float freq)
222 {
223 float t;
224
225 for (t = 0f; freq >= 1f; freq *= 0.5f)
226 {
227 t += noise3(freq * x, freq * y, freq * z) / freq;
228 }
229 return t;
230 }
231
232 private static void normalize2(float[,] v, int i)
233 {
234 float s;
235 float a = v[i, 0];
236 float b = v[i, 1];
237
238 s = (float)Math.Sqrt(a * a + b * b);
239 s = 1.0f / s;
240 v[i, 0] = a * s;
241 v[i, 1] = b * s;
242 }
243
244 private static void normalize3(float[,] v, int i)
245 {
246 float s;
247 float a = v[i, 0];
248 float b = v[i, 1];
249 float c = v[i, 2];
250
251 s = (float)Math.Sqrt(a * a + b * b + c * c);
252 s = 1.0f / s;
253
254 v[i, 0] = a * s;
255 v[i, 1] = b * s;
256 v[i, 2] = c * s;
257 }
258
259 private static float s_curve(float t)
260 {
261 return t * t * (3f - 2f * t);
262 }
263 }
264}
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/TerrainSplat.cs b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/TerrainSplat.cs
new file mode 100644
index 0000000..f60beaf
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/TerrainSplat.cs
@@ -0,0 +1,470 @@
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
28using System;
29using System.Diagnostics;
30using System.Drawing;
31using System.Drawing.Imaging;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Services.Interfaces;
37
38namespace OpenSim.Region.CoreModules.World.Warp3DMap
39{
40 public static class TerrainSplat
41 {
42 #region Constants
43
44 private static readonly UUID DIRT_DETAIL = new UUID("0bc58228-74a0-7e83-89bc-5c23464bcec5");
45 private static readonly UUID GRASS_DETAIL = new UUID("63338ede-0037-c4fd-855b-015d77112fc8");
46 private static readonly UUID MOUNTAIN_DETAIL = new UUID("303cd381-8560-7579-23f1-f0a880799740");
47 private static readonly UUID ROCK_DETAIL = new UUID("53a2f406-4895-1d13-d541-d2e3b86bc19c");
48
49 private static readonly UUID[] DEFAULT_TERRAIN_DETAIL = new UUID[]
50 {
51 DIRT_DETAIL,
52 GRASS_DETAIL,
53 MOUNTAIN_DETAIL,
54 ROCK_DETAIL
55 };
56
57 private static readonly Color[] DEFAULT_TERRAIN_COLOR = new Color[]
58 {
59 Color.FromArgb(255, 164, 136, 117),
60 Color.FromArgb(255, 65, 87, 47),
61 Color.FromArgb(255, 157, 145, 131),
62 Color.FromArgb(255, 125, 128, 130)
63 };
64
65 private static readonly UUID TERRAIN_CACHE_MAGIC = new UUID("2c0c7ef2-56be-4eb8-aacb-76712c535b4b");
66
67 #endregion Constants
68
69 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
70 private static string LogHeader = "[WARP3D TERRAIN SPLAT]";
71
72 /// <summary>
73 /// Builds a composited terrain texture given the region texture
74 /// and heightmap settings
75 /// </summary>
76 /// <param name="terrain">Terrain heightmap</param>
77 /// <param name="regionInfo">Region information including terrain texture parameters</param>
78 /// <returns>A 256x256 square RGB texture ready for rendering</returns>
79 /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
80 /// Note we create a 256x256 dimension texture even if the actual terrain is larger.
81 /// </remarks>
82
83 public static Bitmap Splat(ITerrainChannel terrain, UUID[] textureIDs,
84 float[] startHeights, float[] heightRanges,
85 uint regionPositionX, uint regionPositionY,
86 IAssetService assetService, IJ2KDecoder decoder,
87 bool textureTerrain, bool averagetextureTerrain,
88 int twidth, int theight)
89 {
90 Debug.Assert(textureIDs.Length == 4);
91 Debug.Assert(startHeights.Length == 4);
92 Debug.Assert(heightRanges.Length == 4);
93
94 Bitmap[] detailTexture = new Bitmap[4];
95
96 byte[] mapColorsRed = new byte[4];
97 byte[] mapColorsGreen = new byte[4];
98 byte[] mapColorsBlue = new byte[4];
99
100 bool usecolors = false;
101
102 if (textureTerrain)
103 {
104 // Swap empty terrain textureIDs with default IDs
105 for(int i = 0; i < textureIDs.Length; i++)
106 {
107 if(textureIDs[i] == UUID.Zero)
108 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
109 }
110
111 #region Texture Fetching
112
113 if(assetService != null)
114 {
115 for(int i = 0; i < 4; i++)
116 {
117 AssetBase asset = null;
118
119 // asset cache indexes are strings
120 string cacheName ="MAP-Patch" + textureIDs[i].ToString();
121
122 // Try to fetch a cached copy of the decoded/resized version of this texture
123 asset = assetService.GetCached(cacheName);
124 if(asset != null)
125 {
126 try
127 {
128 using(System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
129 detailTexture[i] = (Bitmap)Image.FromStream(stream);
130
131 if(detailTexture[i].PixelFormat != PixelFormat.Format24bppRgb ||
132 detailTexture[i].Width != 16 || detailTexture[i].Height != 16)
133 {
134 detailTexture[i].Dispose();
135 detailTexture[i] = null;
136 }
137 }
138 catch(Exception ex)
139 {
140 m_log.Warn("Failed to decode cached terrain patch texture" + textureIDs[i] + "): " + ex.Message);
141 }
142 }
143
144 if(detailTexture[i] == null)
145 {
146 // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
147 asset = assetService.Get(textureIDs[i].ToString());
148 if(asset != null)
149 {
150 try
151 {
152 detailTexture[i] = (Bitmap)decoder.DecodeToImage(asset.Data);
153 }
154 catch(Exception ex)
155 {
156 m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
157 }
158 }
159
160 if(detailTexture[i] != null)
161 {
162 if(detailTexture[i].PixelFormat != PixelFormat.Format24bppRgb ||
163 detailTexture[i].Width != 16 || detailTexture[i].Height != 16)
164 using(Bitmap origBitmap = detailTexture[i])
165 detailTexture[i] = Util.ResizeImageSolid(origBitmap, 16, 16);
166
167 // Save the decoded and resized texture to the cache
168 byte[] data;
169 using(System.IO.MemoryStream stream = new System.IO.MemoryStream())
170 {
171 detailTexture[i].Save(stream, ImageFormat.Png);
172 data = stream.ToArray();
173 }
174
175 // Cache a PNG copy of this terrain texture
176 AssetBase newAsset = new AssetBase
177 {
178 Data = data,
179 Description = "PNG",
180 Flags = AssetFlags.Collectable,
181 FullID = UUID.Zero,
182 ID = cacheName,
183 Local = true,
184 Name = String.Empty,
185 Temporary = true,
186 Type = (sbyte)AssetType.Unknown
187 };
188 newAsset.Metadata.ContentType = "image/png";
189 assetService.Store(newAsset);
190 }
191 }
192 }
193 }
194
195 #endregion Texture Fetching
196 if(averagetextureTerrain)
197 {
198 for(int t = 0; t < 4; t++)
199 {
200 usecolors = true;
201 if(detailTexture[t] == null)
202 {
203 mapColorsRed[t] = DEFAULT_TERRAIN_COLOR[t].R;
204 mapColorsGreen[t] = DEFAULT_TERRAIN_COLOR[t].G;
205 mapColorsBlue[t] = DEFAULT_TERRAIN_COLOR[t].B;
206 continue;
207 }
208
209 int npixeis = 0;
210 int cR = 0;
211 int cG = 0;
212 int cB = 0;
213
214 BitmapData bmdata = detailTexture[t].LockBits(new Rectangle(0, 0, 16, 16),
215 ImageLockMode.ReadOnly, detailTexture[t].PixelFormat);
216
217 npixeis = bmdata.Height * bmdata.Width;
218 int ylen = bmdata.Height * bmdata.Stride;
219
220 unsafe
221 {
222 for(int y = 0; y < ylen; y += bmdata.Stride)
223 {
224 byte* ptrc = (byte*)bmdata.Scan0 + y;
225 for(int x = 0 ; x < bmdata.Width; ++x)
226 {
227 cR += *(ptrc++);
228 cG += *(ptrc++);
229 cB += *(ptrc++);
230 }
231 }
232
233 }
234 detailTexture[t].UnlockBits(bmdata);
235 detailTexture[t].Dispose();
236
237 mapColorsRed[t] = (byte)Util.Clamp(cR / npixeis, 0 , 255);
238 mapColorsGreen[t] = (byte)Util.Clamp(cG / npixeis, 0 , 255);
239 mapColorsBlue[t] = (byte)Util.Clamp(cB / npixeis, 0 , 255);
240 }
241 }
242 else
243 {
244 // Fill in any missing textures with a solid color
245 for(int i = 0; i < 4; i++)
246 {
247 if(detailTexture[i] == null)
248 {
249 m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color", LogHeader, i);
250
251 // Create a solid color texture for this layer
252 detailTexture[i] = new Bitmap(16, 16, PixelFormat.Format24bppRgb);
253 using(Graphics gfx = Graphics.FromImage(detailTexture[i]))
254 {
255 using(SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
256 gfx.FillRectangle(brush, 0, 0, 16, 16);
257 }
258 }
259 else
260 {
261 if(detailTexture[i].Width != 16 || detailTexture[i].Height != 16)
262 {
263 using(Bitmap origBitmap = detailTexture[i])
264 detailTexture[i] = Util.ResizeImageSolid(origBitmap, 16, 16);
265 }
266 }
267 }
268 }
269 }
270 else
271 {
272 usecolors = true;
273 for(int t = 0; t < 4; t++)
274 {
275 mapColorsRed[t] = DEFAULT_TERRAIN_COLOR[t].R;
276 mapColorsGreen[t] = DEFAULT_TERRAIN_COLOR[t].G;
277 mapColorsBlue[t] = DEFAULT_TERRAIN_COLOR[t].B;
278 }
279 }
280
281 #region Layer Map
282
283 float xFactor = terrain.Width / twidth;
284 float yFactor = terrain.Height / theight;
285
286 #endregion Layer Map
287
288 #region Texture Compositing
289
290 Bitmap output = new Bitmap(twidth, theight, PixelFormat.Format24bppRgb);
291 BitmapData outputData = output.LockBits(new Rectangle(0, 0, twidth, theight), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
292
293 // Unsafe work as we lock down the source textures for quicker access and access the
294 // pixel data directly
295 float invtwitdthMinus1 = 1.0f / (twidth - 1);
296 float invtheightMinus1 = 1.0f / (theight - 1);
297 int ty;
298 int tx;
299 float pctx;
300 float pcty;
301 float height;
302 float layer;
303 float layerDiff;
304 int l0;
305 int l1;
306 uint yglobalpos;
307
308 if(usecolors)
309 {
310 float a;
311 float b;
312 unsafe
313 {
314 byte* ptrO;
315 for(int y = 0; y < theight; ++y)
316 {
317 pcty = y * invtheightMinus1;
318 ptrO = (byte*)outputData.Scan0 + y * outputData.Stride;
319 ty = (int)(y * yFactor);
320 yglobalpos = (uint)ty + regionPositionY;
321
322 for(int x = 0; x < twidth; ++x)
323 {
324 tx = (int)(x * xFactor);
325 pctx = x * invtwitdthMinus1;
326 height = (float)terrain[tx, ty];
327 layer = getLayerTex(height, pctx, pcty,
328 (uint)tx + regionPositionX, yglobalpos,
329 startHeights, heightRanges);
330
331 // Select two textures
332 l0 = (int)layer;
333 l1 = Math.Min(l0 + 1, 3);
334
335 layerDiff = layer - l0;
336
337 a = mapColorsRed[l0];
338 b = mapColorsRed[l1];
339 *(ptrO++) = (byte)(a + layerDiff * (b - a));
340
341 a = mapColorsGreen[l0];
342 b = mapColorsGreen[l1];
343 *(ptrO++) = (byte)(a + layerDiff * (b - a));
344
345 a = mapColorsBlue[l0];
346 b = mapColorsBlue[l1];
347 *(ptrO++) = (byte)(a + layerDiff * (b - a));
348 }
349 }
350 }
351 }
352 else
353 {
354 float aB;
355 float aG;
356 float aR;
357 float bB;
358 float bG;
359 float bR;
360
361 unsafe
362 {
363 // Get handles to all of the texture data arrays
364 BitmapData[] datas = new BitmapData[]
365 {
366 detailTexture[0].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
367 detailTexture[1].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
368 detailTexture[2].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
369 detailTexture[3].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
370 };
371
372 byte* ptr;
373 byte* ptrO;
374 for(int y = 0; y < theight; y++)
375 {
376 pcty = y * invtheightMinus1;
377 int ypatch = ((int)(y * yFactor) & 0x0f) * datas[0].Stride;
378 ptrO = (byte*)outputData.Scan0 + y * outputData.Stride;
379 ty = (int)(y * yFactor);
380 yglobalpos = (uint)ty + regionPositionY;
381
382 for(int x = 0; x < twidth; x++)
383 {
384 tx = (int)(x * xFactor);
385 pctx = x * invtwitdthMinus1;
386 height = (float)terrain[tx, ty];
387 layer = getLayerTex(height, pctx, pcty,
388 (uint)tx + regionPositionX, yglobalpos,
389 startHeights, heightRanges);
390
391 // Select two textures
392 l0 = (int)layer;
393 layerDiff = layer - l0;
394
395 int patchOffset = (tx & 0x0f) * 3 + ypatch;
396
397 ptr = (byte*)datas[l0].Scan0 + patchOffset;
398 aB = *(ptr++);
399 aG = *(ptr++);
400 aR = *(ptr);
401
402 l1 = Math.Min(l0 + 1, 3);
403 ptr = (byte*)datas[l1].Scan0 + patchOffset;
404 bB = *(ptr++);
405 bG = *(ptr++);
406 bR = *(ptr);
407
408
409 // Interpolate between the two selected textures
410 *(ptrO++) = (byte)(aB + layerDiff * (bB - aB));
411 *(ptrO++) = (byte)(aG + layerDiff * (bG - aG));
412 *(ptrO++) = (byte)(aR + layerDiff * (bR - aR));
413 }
414 }
415
416 for(int i = 0; i < detailTexture.Length; i++)
417 detailTexture[i].UnlockBits(datas[i]);
418 }
419
420 for(int i = 0; i < detailTexture.Length; i++)
421 if(detailTexture[i] != null)
422 detailTexture[i].Dispose();
423 }
424
425 output.UnlockBits(outputData);
426
427//output.Save("terr.png",ImageFormat.Png);
428
429 #endregion Texture Compositing
430
431 return output;
432 }
433
434 [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
435 private static float getLayerTex(float height, float pctX, float pctY, uint X, uint Y,
436 float[] startHeights, float[] heightRanges)
437 {
438 // Use bilinear interpolation between the four corners of start height and
439 // height range to select the current values at this position
440 float startHeight = ImageUtils.Bilinear(
441 startHeights[0], startHeights[2],
442 startHeights[1], startHeights[3],
443 pctX, pctY);
444 if (float.IsNaN(startHeight))
445 return 0;
446
447 startHeight = Utils.Clamp(startHeight, 0f, 255f);
448
449 float heightRange = ImageUtils.Bilinear(
450 heightRanges[0], heightRanges[2],
451 heightRanges[1], heightRanges[3],
452 pctX, pctY);
453 heightRange = Utils.Clamp(heightRange, 0f, 255f);
454 if(heightRange == 0f || float.IsNaN(heightRange))
455 return 0;
456
457 // Generate two frequencies of perlin noise based on our global position
458 // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
459 float sX = X * 0.20319f;
460 float sY = Y * 0.20319f;
461
462 float noise = Perlin.noise2(sX * 0.222222f, sY * 0.222222f) * 13.0f;
463 noise += Perlin.turbulence2(sX, sY, 2f) * 4.5f;
464
465 // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
466 float layer = ((height + noise - startHeight) / heightRange) * 4f;
467 return Utils.Clamp(layer, 0f, 3f);
468 }
469 }
470}
diff --git a/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Warp3DImageModule.cs b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Warp3DImageModule.cs
new file mode 100644
index 0000000..8e50a16
--- /dev/null
+++ b/addon-modules/OpenSim.Modules.Warp3DCachedImageModule/src/Warp3DImageModule.cs
@@ -0,0 +1,1073 @@
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
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Drawing.Imaging;
32using System.IO;
33using System.Reflection;
34using System.Runtime;
35
36using CSJ2K;
37using Nini.Config;
38using log4net;
39using Warp3D;
40using Mono.Addins;
41
42using OpenSim.Framework;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Region.PhysicsModules.SharedBase;
46using OpenSim.Services.Interfaces;
47
48using OpenMetaverse;
49using OpenMetaverse.Assets;
50using OpenMetaverse.Imaging;
51using OpenMetaverse.Rendering;
52using OpenMetaverse.StructuredData;
53
54using WarpRenderer = Warp3D.Warp3D;
55using System.Drawing.Drawing2D;
56
57[assembly: Addin("Warp3DCachedImageModule", "1.1")]
58[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
59namespace OpenSim.Region.CoreModules.World.Warp3DMap
60{
61 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "Warp3DCachedImageModule")]
62 public class Warp3DImageModule : IMapImageGenerator, INonSharedRegionModule
63 {
64 private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216);
65 // private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 128);
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69#pragma warning disable 414
70 private static string LogHeader = "[WARP 3D CACHED IMAGE MODULE]";
71#pragma warning restore 414
72 private const float m_cameraHeight = 4096f;
73
74 internal Scene m_scene;
75 private IRendering m_primMesher;
76 internal IJ2KDecoder m_imgDecoder;
77
78 // caches per rendering
79 private Dictionary<string, warp_Texture> m_warpTextures = new Dictionary<string, warp_Texture>();
80 private Dictionary<UUID, int> m_colors = new Dictionary<UUID, int>();
81
82 private IConfigSource m_config;
83 private bool m_drawPrimVolume = true; // true if should render the prims on the tile
84 private bool m_textureTerrain = true; // true if to create terrain splatting texture
85 private bool m_textureAverageTerrain = false; // replace terrain textures by their average color
86 private bool m_texturePrims = true; // true if should texture the rendered prims
87 private float m_texturePrimSize = 48f; // size of prim before we consider texturing it
88 private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes
89 private float m_renderMinHeight = -100f;
90 private float m_renderMaxHeight = 4096f;
91
92 private String m_cacheDirectory = "";
93 private bool m_enable_date = false;
94 private bool m_enable_regionName = false;
95 private bool m_enable_regionPosition = false;
96 private bool m_enable_refreshEveryMonth = false;
97 private bool m_enable_HostedBy = false;
98 private String m_enable_HostedByText = "";
99
100 private bool m_Enabled = false;
101
102 // private Bitmap lastImage = null;
103 private DateTime lastImageTime = DateTime.MinValue;
104
105 #region Region Module interface
106
107 public void Initialise(IConfigSource source)
108 {
109 m_config = source;
110
111 string[] configSections = new string[] { "Map", "Startup" };
112
113 if (Util.GetConfigVarFromSections<string>(
114 m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DCachedImageModule")
115 return;
116
117 m_Enabled = true;
118
119 m_drawPrimVolume =
120 Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume);
121 m_textureTerrain =
122 Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain);
123 m_textureAverageTerrain =
124 Util.GetConfigVarFromSections<bool>(m_config, "AverageTextureColorOnMapTile", configSections, m_textureAverageTerrain);
125 if (m_textureAverageTerrain)
126 m_textureTerrain = true;
127 m_texturePrims =
128 Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims);
129 m_texturePrimSize =
130 Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize);
131 m_renderMeshes =
132 Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes);
133 m_cacheDirectory =
134 Util.GetConfigVarFromSections<string>(m_config, "CacheDirectory", configSections, System.IO.Path.Combine(new DirectoryInfo(".").FullName, "MapImageCache"));
135
136
137 m_enable_date = Util.GetConfigVarFromSections<bool>(m_config, "enableDate", configSections, false);
138 m_enable_regionName = Util.GetConfigVarFromSections<bool>(m_config, "enableName", configSections, false);
139 m_enable_regionPosition = Util.GetConfigVarFromSections<bool>(m_config, "enablePosition", configSections, false);
140 m_enable_refreshEveryMonth = Util.GetConfigVarFromSections<bool>(m_config, "RefreshEveryMonth", configSections, true);
141 m_enable_HostedBy = Util.GetConfigVarFromSections<bool>(m_config, "enableHostedBy", configSections, false);
142 m_enable_HostedByText = Util.GetConfigVarFromSections<String>(m_config, "HosterText", configSections, String.Empty);
143
144 m_renderMaxHeight = Util.GetConfigVarFromSections<float>(m_config, "RenderMaxHeight", configSections, m_renderMaxHeight);
145 m_renderMinHeight = Util.GetConfigVarFromSections<float>(m_config, "RenderMinHeight", configSections, m_renderMinHeight);
146
147 if (!Directory.Exists(m_cacheDirectory))
148 Directory.CreateDirectory(m_cacheDirectory);
149
150 if (m_renderMaxHeight < 100f)
151 m_renderMaxHeight = 100f;
152 else if (m_renderMaxHeight > m_cameraHeight - 10f)
153 m_renderMaxHeight = m_cameraHeight - 10f;
154
155 if (m_renderMinHeight < -100f)
156 m_renderMinHeight = -100f;
157 else if (m_renderMinHeight > m_renderMaxHeight - 10f)
158 m_renderMinHeight = m_renderMaxHeight - 10f;
159 }
160
161 public void AddRegion(Scene scene)
162 {
163 if (!m_Enabled)
164 return;
165
166 m_scene = scene;
167
168 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
169 if (renderers.Count > 0)
170 m_log.Info("[MAPTILE]: Loaded prim mesher " + renderers[0]);
171 else
172 m_log.Info("[MAPTILE]: No prim mesher loaded, prim rendering will be disabled");
173
174 m_scene.RegisterModuleInterface<IMapImageGenerator>(this);
175 }
176
177 public void RegionLoaded(Scene scene)
178 {
179 if (!m_Enabled)
180 return;
181
182 m_imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
183 }
184
185 public void RemoveRegion(Scene scene)
186 {
187 }
188
189 public void Close()
190 {
191 }
192
193 public string Name
194 {
195 get { return "Warp3DImageModule"; }
196 }
197
198 public Type ReplaceableInterface
199 {
200 get { return null; }
201 }
202
203 #endregion
204
205 #region IMapImageGenerator Members
206
207 private Vector3 cameraPos;
208 private Vector3 cameraDir;
209 private int viewWitdh = 256;
210 private int viewHeight = 256;
211 private float fov;
212 private bool orto;
213
214 public static string fillInt(int _i, int _l)
215 {
216 String _return = _i.ToString();
217
218 while (_return.Length < _l)
219 {
220 _return = 0 + _return;
221 }
222
223 return _return;
224 }
225
226 public static int getCurrentUnixTime()
227 {
228 return (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
229 }
230
231 public static String unixTimeToDateString(int unixTime)
232 {
233 DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
234 long unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond);
235 DateTime _date = new DateTime(unixStart.Ticks + unixTimeStampInTicks, System.DateTimeKind.Utc);
236
237 return fillInt(_date.Day, 2) + "." + fillInt(_date.Month, 2) + "." + fillInt(_date.Year, 4) + " " + fillInt(_date.Hour, 2) + ":" + fillInt(_date.Minute, 2);
238 }
239
240 private void writeDateOnMap(ref Bitmap _map)
241 {
242 RectangleF rectf = new RectangleF(2, 1, 200, 25);
243
244 Graphics g = Graphics.FromImage(_map);
245 g.SmoothingMode = SmoothingMode.AntiAlias;
246 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
247 g.PixelOffsetMode = PixelOffsetMode.HighQuality;
248 g.DrawString(unixTimeToDateString(getCurrentUnixTime()), new Font("Arial", 8), Brushes.White, rectf);
249 g.Flush();
250 }
251
252 private void writeNameOnMap(ref Bitmap _map)
253 {
254 RectangleF rectf = new RectangleF(2, m_scene.RegionInfo.RegionSizeX - 15, 200, 25);
255
256 Graphics g = Graphics.FromImage(_map);
257 g.SmoothingMode = SmoothingMode.AntiAlias;
258 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
259 g.PixelOffsetMode = PixelOffsetMode.HighQuality;
260 g.DrawString(m_scene.Name, new Font("Arial", 8), Brushes.White, rectf);
261 g.Flush();
262 }
263
264 private void writePositionOnMap(ref Bitmap _map)
265 {
266 RectangleF rectf = new RectangleF(m_scene.RegionInfo.RegionSizeY - 85, m_scene.RegionInfo.RegionSizeX - 15, 80, 25);
267
268 Graphics g = Graphics.FromImage(_map);
269 g.SmoothingMode = SmoothingMode.AntiAlias;
270 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
271 g.PixelOffsetMode = PixelOffsetMode.HighQuality;
272 g.DrawString(m_scene.RegionInfo.RegionLocX + ", " + m_scene.RegionInfo.RegionLocY, new Font("Arial", 8), Brushes.White, rectf);
273 g.Flush();
274 }
275
276 private void writeHostedByOnMap(ref Bitmap _map)
277 {
278 RectangleF rectf = new RectangleF(2, m_scene.RegionInfo.RegionSizeX - 15, 200, 25);
279
280 Graphics g = Graphics.FromImage(_map);
281 g.SmoothingMode = SmoothingMode.AntiAlias;
282 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
283 g.PixelOffsetMode = PixelOffsetMode.HighQuality;
284 g.DrawString(m_enable_HostedByText, new Font("Arial", 8), Brushes.Gray, rectf);
285 g.Flush();
286 }
287
288
289 public Bitmap CreateMapTile()
290 {
291 if ((File.GetCreationTime(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")).Month != DateTime.Now.Month) && m_enable_refreshEveryMonth == true)
292 File.Delete(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp"));
293
294 if (File.Exists(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")))
295 {
296 return new Bitmap(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp"));
297 }
298 else
299 {
300 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
301 if (renderers.Count > 0)
302 {
303 m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
304 }
305
306 cameraPos = new Vector3(
307 (m_scene.RegionInfo.RegionSizeX) * 0.5f,
308 (m_scene.RegionInfo.RegionSizeY) * 0.5f,
309 m_cameraHeight);
310
311 cameraDir = -Vector3.UnitZ;
312 viewWitdh = (int)m_scene.RegionInfo.RegionSizeX;
313 viewHeight = (int)m_scene.RegionInfo.RegionSizeY;
314 orto = true;
315
316 // fov = warp_Math.rad2deg(2f * (float)Math.Atan2(viewWitdh, 4096f));
317 // orto = false;
318
319 Bitmap tile = GenImage();
320
321 if (m_enable_date)
322 writeDateOnMap(ref tile);
323
324 if (m_enable_regionName)
325 writeNameOnMap(ref tile);
326
327 if (m_enable_regionPosition)
328 writePositionOnMap(ref tile);
329
330 if (m_enable_HostedBy)
331 writeHostedByOnMap(ref tile);
332
333 tile.Save(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp"));
334
335 // image may be reloaded elsewhere, so no compression format
336 string filename = "MAP-" + m_scene.RegionInfo.RegionID.ToString() + ".png";
337 tile.Save(filename, ImageFormat.Png);
338 m_primMesher = null;
339 return tile;
340 }
341 }
342
343 public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float pfov, int width, int height, bool useTextures)
344 {
345 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
346 if (renderers.Count > 0)
347 {
348 m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
349 }
350
351 cameraPos = camPos;
352 cameraDir = camDir;
353 viewWitdh = width;
354 viewHeight = height;
355 fov = pfov;
356 orto = false;
357
358 Bitmap tile = GenImage();
359 m_primMesher = null;
360 return tile;
361 }
362
363 private Bitmap GenImage()
364 {
365 m_colors.Clear();
366 m_warpTextures.Clear();
367
368 WarpRenderer renderer = new WarpRenderer();
369
370 if (!renderer.CreateScene(viewWitdh, viewHeight))
371 return new Bitmap(viewWitdh, viewHeight);
372
373 #region Camera
374
375 warp_Vector pos = ConvertVector(cameraPos);
376 warp_Vector lookat = warp_Vector.add(pos, ConvertVector(cameraDir));
377
378 if (orto)
379 renderer.Scene.defaultCamera.setOrthographic(true, viewWitdh, viewHeight);
380 else
381 renderer.Scene.defaultCamera.setFov(fov);
382
383 renderer.Scene.defaultCamera.setPos(pos);
384 renderer.Scene.defaultCamera.lookAt(lookat);
385 #endregion Camera
386
387 renderer.Scene.setAmbient(warp_Color.getColor(192, 191, 173));
388 renderer.Scene.addLight("Light1", new warp_Light(new warp_Vector(0f, 1f, 8f), warp_Color.White, 0, 320, 40));
389
390 CreateWater(renderer);
391 CreateTerrain(renderer);
392 if (m_drawPrimVolume)
393 CreateAllPrims(renderer);
394
395 renderer.Render();
396 Bitmap bitmap = renderer.Scene.getImage();
397
398 renderer.Scene.destroy();
399 renderer.Reset();
400 renderer = null;
401
402 m_colors.Clear();
403 m_warpTextures.Clear();
404
405 GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
406 GC.Collect();
407 GC.WaitForPendingFinalizers();
408 GC.Collect();
409 GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.Default;
410 return bitmap;
411 }
412
413 public byte[] WriteJpeg2000Image()
414 {
415 try
416 {
417 using (Bitmap mapbmp = CreateMapTile())
418 return OpenJPEG.EncodeFromImage(mapbmp, false);
419 }
420 catch (Exception e)
421 {
422 // JPEG2000 encoder failed
423 m_log.Error("[WARP 3D IMAGE MODULE]: Failed generating terrain map: ", e);
424 }
425
426 return null;
427 }
428
429 #endregion
430
431 #region Rendering Methods
432
433 // Add a water plane to the renderer.
434 private void CreateWater(WarpRenderer renderer)
435 {
436 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
437
438 renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f);
439 renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX * 0.5f,
440 waterHeight,
441 m_scene.RegionInfo.RegionSizeY * 0.5f);
442
443 warp_Material waterMaterial = new warp_Material(ConvertColor(WATER_COLOR));
444 renderer.Scene.addMaterial("WaterMat", waterMaterial);
445 renderer.SetObjectMaterial("Water", "WaterMat");
446 }
447
448 // Add a terrain to the renderer.
449 // Note that we create a 'low resolution' 257x257 vertex terrain rather than trying for
450 // full resolution. This saves a lot of memory especially for very large regions.
451 private void CreateTerrain(WarpRenderer renderer)
452 {
453 ITerrainChannel terrain = m_scene.Heightmap;
454
455 float regionsx = m_scene.RegionInfo.RegionSizeX;
456 float regionsy = m_scene.RegionInfo.RegionSizeY;
457
458 // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding
459
460 int bitWidth;
461 int bitHeight;
462
463 const double log2inv = 1.4426950408889634073599246810019;
464 bitWidth = (int)Math.Ceiling((Math.Log(terrain.Width) * log2inv));
465 bitHeight = (int)Math.Ceiling((Math.Log(terrain.Height) * log2inv));
466
467 if (bitWidth > 8) // more than 256 is very heavy :(
468 bitWidth = 8;
469 if (bitHeight > 8)
470 bitHeight = 8;
471
472 int twidth = (int)Math.Pow(2, bitWidth);
473 int theight = (int)Math.Pow(2, bitHeight);
474
475 float diff = regionsx / twidth;
476
477 int npointsx = (int)(regionsx / diff);
478 int npointsy = (int)(regionsy / diff);
479
480 float invsx = 1.0f / (npointsx * diff);
481 float invsy = 1.0f / (npointsy * diff);
482
483 npointsx++;
484 npointsy++;
485
486 // Create all the vertices for the terrain
487 warp_Object obj = new warp_Object();
488 warp_Vector pos;
489 float x, y;
490 float tv;
491 for (y = 0; y < regionsy; y += diff)
492 {
493 tv = y * invsy;
494 for (x = 0; x < regionsx; x += diff)
495 {
496 pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]);
497 obj.addVertex(new warp_Vertex(pos, x * invsx, tv));
498 }
499 pos = ConvertVector(x, y, (float)terrain[(int)(x - diff), (int)y]);
500 obj.addVertex(new warp_Vertex(pos, 1.0f, tv));
501 }
502
503 int lastY = (int)(y - diff);
504 for (x = 0; x < regionsx; x += diff)
505 {
506 pos = ConvertVector(x, y, (float)terrain[(int)x, lastY]);
507 obj.addVertex(new warp_Vertex(pos, x * invsx, 1.0f));
508 }
509 pos = ConvertVector(x, y, (float)terrain[(int)(x - diff), lastY]);
510 obj.addVertex(new warp_Vertex(pos, 1.0f, 1.0f));
511
512 // create triangles.
513 int limx = npointsx - 1;
514 int limy = npointsy - 1;
515 for (int j = 0; j < limy; j++)
516 {
517 for (int i = 0; i < limx; i++)
518 {
519 int v = j * npointsx + i;
520
521 // Make two triangles for each of the squares in the grid of vertices
522 obj.addTriangle(
523 v,
524 v + 1,
525 v + npointsx);
526
527 obj.addTriangle(
528 v + npointsx + 1,
529 v + npointsx,
530 v + 1);
531 }
532 }
533
534 renderer.Scene.addObject("Terrain", obj);
535
536 UUID[] textureIDs = new UUID[4];
537 float[] startHeights = new float[4];
538 float[] heightRanges = new float[4];
539
540 OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
541
542 textureIDs[0] = regionInfo.TerrainTexture1;
543 textureIDs[1] = regionInfo.TerrainTexture2;
544 textureIDs[2] = regionInfo.TerrainTexture3;
545 textureIDs[3] = regionInfo.TerrainTexture4;
546
547 startHeights[0] = (float)regionInfo.Elevation1SW;
548 startHeights[1] = (float)regionInfo.Elevation1NW;
549 startHeights[2] = (float)regionInfo.Elevation1SE;
550 startHeights[3] = (float)regionInfo.Elevation1NE;
551
552 heightRanges[0] = (float)regionInfo.Elevation2SW;
553 heightRanges[1] = (float)regionInfo.Elevation2NW;
554 heightRanges[2] = (float)regionInfo.Elevation2SE;
555 heightRanges[3] = (float)regionInfo.Elevation2NE;
556
557 warp_Texture texture;
558 using (Bitmap image = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
559 m_scene.RegionInfo.WorldLocX, m_scene.RegionInfo.WorldLocY,
560 m_scene.AssetService, m_imgDecoder, m_textureTerrain, m_textureAverageTerrain,
561 twidth, twidth))
562 texture = new warp_Texture(image);
563
564 warp_Material material = new warp_Material(texture);
565 renderer.Scene.addMaterial("TerrainMat", material);
566 renderer.SetObjectMaterial("Terrain", "TerrainMat");
567 }
568
569 private void CreateAllPrims(WarpRenderer renderer)
570 {
571 if (m_primMesher == null)
572 return;
573
574 m_scene.ForEachSOG(
575 delegate (SceneObjectGroup group)
576 {
577 foreach (SceneObjectPart child in group.Parts)
578 CreatePrim(renderer, child);
579 }
580 );
581 }
582
583 private void UVPlanarMap(Vertex v, Vector3 scale, out float tu, out float tv)
584 {
585 Vector3 scaledPos = v.Position * scale;
586 float d = v.Normal.X;
587 if (d >= 0.5f)
588 {
589 tu = 2f * scaledPos.Y;
590 tv = scaledPos.X * v.Normal.Z - scaledPos.Z * v.Normal.X;
591 }
592 else if (d <= -0.5f)
593 {
594 tu = -2f * scaledPos.Y;
595 tv = -scaledPos.X * v.Normal.Z + scaledPos.Z * v.Normal.X;
596 }
597 else if (v.Normal.Y > 0f)
598 {
599 tu = -2f * scaledPos.X;
600 tv = scaledPos.Y * v.Normal.Z - scaledPos.Z * v.Normal.Y;
601 }
602 else
603 {
604 tu = 2f * scaledPos.X;
605 tv = -scaledPos.Y * v.Normal.Z + scaledPos.Z * v.Normal.Y;
606 }
607
608 tv *= 2f;
609 }
610
611 private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim)
612 {
613 if ((PCode)prim.Shape.PCode != PCode.Prim)
614 return;
615
616 Vector3 ppos = prim.GetWorldPosition();
617 if (ppos.Z < m_renderMinHeight || ppos.Z > m_renderMaxHeight)
618 return;
619
620 warp_Vector primPos = ConvertVector(ppos);
621 warp_Quaternion primRot = ConvertQuaternion(prim.GetWorldRotation());
622 warp_Matrix m = warp_Matrix.quaternionMatrix(primRot);
623
624 float screenFactor = renderer.Scene.EstimateBoxProjectedArea(primPos, ConvertVector(prim.Scale), m);
625 if (screenFactor < 0)
626 return;
627
628 int p2 = (int)(-(float)Math.Log(screenFactor) * 1.442695f * 0.5 - 1);
629
630 if (p2 < 0)
631 p2 = 0;
632 else if (p2 > 3)
633 p2 = 3;
634
635 DetailLevel lod = (DetailLevel)(3 - p2);
636
637 FacetedMesh renderMesh = null;
638 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
639
640 if (m_renderMeshes)
641 {
642 if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
643 {
644 // Try fetchinng the asset
645 byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
646 if (sculptAsset != null)
647 {
648 // Is it a mesh?
649 if (omvPrim.Sculpt.Type == SculptType.Mesh)
650 {
651 AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
652 FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, lod, out renderMesh);
653 meshAsset = null;
654 }
655 else // It's sculptie
656 {
657 if (m_imgDecoder != null)
658 {
659 Image sculpt = m_imgDecoder.DecodeToImage(sculptAsset);
660 if (sculpt != null)
661 {
662 renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, lod);
663 sculpt.Dispose();
664 }
665 }
666 }
667 }
668 else
669 {
670 m_log.WarnFormat("[Warp3D] failed to get mesh or sculpt asset {0} of prim {1} at {2}",
671 omvPrim.Sculpt.SculptTexture.ToString(), prim.Name, prim.GetWorldPosition().ToString());
672 }
673 }
674 }
675
676 // If not a mesh or sculptie, try the regular mesher
677 if (renderMesh == null)
678 {
679 renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, lod);
680 }
681
682 if (renderMesh == null)
683 return;
684
685 string primID = prim.UUID.ToString();
686
687 // Create the prim faces
688 // TODO: Implement the useTextures flag behavior
689 for (int i = 0; i < renderMesh.Faces.Count; i++)
690 {
691 Face face = renderMesh.Faces[i];
692 string meshName = primID + i.ToString();
693
694 // Avoid adding duplicate meshes to the scene
695 if (renderer.Scene.objectData.ContainsKey(meshName))
696 continue;
697
698 warp_Object faceObj = new warp_Object();
699
700 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
701 Color4 faceColor = teFace.RGBA;
702 if (faceColor.A == 0)
703 continue;
704
705 string materialName = String.Empty;
706 if (m_texturePrims)
707 {
708 // if(lod > DetailLevel.Low)
709 {
710 // materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, lod == DetailLevel.Low);
711 materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, false, prim);
712 if (String.IsNullOrEmpty(materialName))
713 continue;
714 int c = renderer.Scene.material(materialName).getColor();
715 if ((c & warp_Color.MASKALPHA) == 0)
716 continue;
717 }
718 }
719 else
720 materialName = GetOrCreateMaterial(renderer, faceColor);
721
722 if (renderer.Scene.material(materialName).getTexture() == null)
723 {
724 // uv map details dont not matter for color;
725 for (int j = 0; j < face.Vertices.Count; j++)
726 {
727 Vertex v = face.Vertices[j];
728 warp_Vector pos = ConvertVector(v.Position);
729 warp_Vertex vert = new warp_Vertex(pos, v.TexCoord.X, v.TexCoord.Y);
730 faceObj.addVertex(vert);
731 }
732 }
733 else
734 {
735 float tu;
736 float tv;
737 float offsetu = teFace.OffsetU + 0.5f;
738 float offsetv = teFace.OffsetV + 0.5f;
739 float scaleu = teFace.RepeatU;
740 float scalev = teFace.RepeatV;
741 float rotation = teFace.Rotation;
742 float rc = 0;
743 float rs = 0;
744 if (rotation != 0)
745 {
746 rc = (float)Math.Cos(rotation);
747 rs = (float)Math.Sin(rotation);
748 }
749
750 for (int j = 0; j < face.Vertices.Count; j++)
751 {
752 warp_Vertex vert;
753 Vertex v = face.Vertices[j];
754 warp_Vector pos = ConvertVector(v.Position);
755 if (teFace.TexMapType == MappingType.Planar)
756 UVPlanarMap(v, prim.Scale, out tu, out tv);
757 else
758 {
759 tu = v.TexCoord.X - 0.5f;
760 tv = 0.5f - v.TexCoord.Y;
761 }
762 if (rotation != 0)
763 {
764 float tur = tu * rc - tv * rs;
765 float tvr = tu * rs + tv * rc;
766 tur *= scaleu;
767 tur += offsetu;
768
769 tvr *= scalev;
770 tvr += offsetv;
771 vert = new warp_Vertex(pos, tur, tvr);
772 }
773 else
774 {
775 tu *= scaleu;
776 tu += offsetu;
777 tv *= scalev;
778 tv += offsetv;
779 vert = new warp_Vertex(pos, tu, tv);
780 }
781
782 faceObj.addVertex(vert);
783 }
784 }
785
786 for (int j = 0; j < face.Indices.Count; j += 3)
787 {
788 faceObj.addTriangle(
789 face.Indices[j + 0],
790 face.Indices[j + 1],
791 face.Indices[j + 2]);
792 }
793
794 faceObj.scaleSelf(prim.Scale.X, prim.Scale.Z, prim.Scale.Y);
795 faceObj.transform(m);
796 faceObj.setPos(primPos);
797
798 renderer.Scene.addObject(meshName, faceObj);
799 renderer.SetObjectMaterial(meshName, materialName);
800 }
801 }
802
803 private int GetFaceColor(Primitive.TextureEntryFace face)
804 {
805 int color;
806 Color4 ctmp = Color4.White;
807
808 if (face.TextureID == UUID.Zero)
809 return warp_Color.White;
810
811 if (!m_colors.TryGetValue(face.TextureID, out color))
812 {
813 bool fetched = false;
814
815 // Attempt to fetch the texture metadata
816 string cacheName = "MAPCLR" + face.TextureID.ToString();
817 AssetBase metadata = m_scene.AssetService.GetCached(cacheName);
818 if (metadata != null)
819 {
820 OSDMap map = null;
821 try { map = OSDParser.Deserialize(metadata.Data) as OSDMap; } catch { }
822
823 if (map != null)
824 {
825 ctmp = map["X-RGBA"].AsColor4();
826 fetched = true;
827 }
828 }
829
830 if (!fetched)
831 {
832 // Fetch the texture, decode and get the average color,
833 // then save it to a temporary metadata asset
834 AssetBase textureAsset = m_scene.AssetService.Get(face.TextureID.ToString());
835 if (textureAsset != null)
836 {
837 int width, height;
838 ctmp = GetAverageColor(textureAsset.FullID, textureAsset.Data, out width, out height);
839
840 OSDMap data = new OSDMap { { "X-RGBA", OSD.FromColor4(ctmp) } };
841 metadata = new AssetBase
842 {
843 Data = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)),
844 Description = "Metadata for texture color" + face.TextureID.ToString(),
845 Flags = AssetFlags.Collectable,
846 FullID = UUID.Zero,
847 ID = cacheName,
848 Local = true,
849 Temporary = true,
850 Name = String.Empty,
851 Type = (sbyte)AssetType.Unknown
852 };
853 m_scene.AssetService.Store(metadata);
854 }
855 else
856 {
857 ctmp = new Color4(0.5f, 0.5f, 0.5f, 1.0f);
858 }
859 }
860 color = ConvertColor(ctmp);
861 m_colors[face.TextureID] = color;
862 }
863
864 return color;
865 }
866
867 private string GetOrCreateMaterial(WarpRenderer renderer, Color4 color)
868 {
869 string name = color.ToString();
870
871 warp_Material material = renderer.Scene.material(name);
872 if (material != null)
873 return name;
874
875 renderer.AddMaterial(name, ConvertColor(color));
876 return name;
877 }
878
879 public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID, bool useAverageTextureColor, SceneObjectPart sop)
880 {
881 int color = ConvertColor(faceColor);
882 string idstr = textureID.ToString() + color.ToString();
883 string materialName = "MAPMAT" + idstr;
884
885 if (renderer.Scene.material(materialName) != null)
886 return materialName;
887
888 warp_Material mat = new warp_Material();
889 warp_Texture texture = GetTexture(textureID, sop);
890 if (texture != null)
891 {
892 if (useAverageTextureColor)
893 color = warp_Color.multiply(color, texture.averageColor);
894 else
895 mat.setTexture(texture);
896 }
897 else
898 color = warp_Color.multiply(color, warp_Color.Grey);
899
900 mat.setColor(color);
901 renderer.Scene.addMaterial(materialName, mat);
902
903 return materialName;
904 }
905
906 private warp_Texture GetTexture(UUID id, SceneObjectPart sop)
907 {
908 warp_Texture ret = null;
909 if (id == UUID.Zero)
910 return ret;
911
912 if (m_warpTextures.TryGetValue(id.ToString(), out ret))
913 return ret;
914
915 byte[] asset = m_scene.AssetService.GetData(id.ToString());
916
917 if (asset != null)
918 {
919 try
920 {
921 using (Bitmap img = (Bitmap)m_imgDecoder.DecodeToImage(asset))
922 ret = new warp_Texture(img, 8); // reduce textures size to 256x256
923 }
924 catch (Exception e)
925 {
926 m_log.WarnFormat("[Warp3D]: Failed to decode texture {0} for prim {1} at {2}, exception {3}", id.ToString(), sop.Name, sop.GetWorldPosition().ToString(), e.Message);
927 }
928 }
929 else
930 m_log.WarnFormat("[Warp3D]: missing texture {0} data for prim {1} at {2}",
931 id.ToString(), sop.Name, sop.GetWorldPosition().ToString());
932
933 m_warpTextures[id.ToString()] = ret;
934 return ret;
935 }
936
937 #endregion Rendering Methods
938
939 #region Static Helpers
940 // Note: axis change.
941 private static warp_Vector ConvertVector(float x, float y, float z)
942 {
943 return new warp_Vector(x, z, y);
944 }
945
946 private static warp_Vector ConvertVector(Vector3 vector)
947 {
948 return new warp_Vector(vector.X, vector.Z, vector.Y);
949 }
950
951 private static warp_Quaternion ConvertQuaternion(Quaternion quat)
952 {
953 return new warp_Quaternion(quat.X, quat.Z, quat.Y, -quat.W);
954 }
955
956 private static int ConvertColor(Color4 color)
957 {
958 int c = warp_Color.getColor((byte)(color.R * 255f), (byte)(color.G * 255f), (byte)(color.B * 255f), (byte)(color.A * 255f));
959 return c;
960 }
961
962 private static Vector3 SurfaceNormal(Vector3 c1, Vector3 c2, Vector3 c3)
963 {
964 Vector3 edge1 = new Vector3(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
965 Vector3 edge2 = new Vector3(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
966
967 Vector3 normal = Vector3.Cross(edge1, edge2);
968 normal.Normalize();
969
970 return normal;
971 }
972
973 public Color4 GetAverageColor(UUID textureID, byte[] j2kData, out int width, out int height)
974 {
975 ulong r = 0;
976 ulong g = 0;
977 ulong b = 0;
978 ulong a = 0;
979 int pixelBytes;
980
981 try
982 {
983 using (MemoryStream stream = new MemoryStream(j2kData))
984 using (Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream))
985 {
986 width = bitmap.Width;
987 height = bitmap.Height;
988
989 BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
990 pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
991
992 // Sum up the individual channels
993 unsafe
994 {
995 if (pixelBytes == 4)
996 {
997 for (int y = 0; y < height; y++)
998 {
999 byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
1000
1001 for (int x = 0; x < width; x++)
1002 {
1003 b += row[x * pixelBytes + 0];
1004 g += row[x * pixelBytes + 1];
1005 r += row[x * pixelBytes + 2];
1006 a += row[x * pixelBytes + 3];
1007 }
1008 }
1009 }
1010 else
1011 {
1012 for (int y = 0; y < height; y++)
1013 {
1014 byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
1015
1016 for (int x = 0; x < width; x++)
1017 {
1018 b += row[x * pixelBytes + 0];
1019 g += row[x * pixelBytes + 1];
1020 r += row[x * pixelBytes + 2];
1021 }
1022 }
1023 }
1024 }
1025 }
1026 // Get the averages for each channel
1027 const decimal OO_255 = 1m / 255m;
1028 decimal totalPixels = (decimal)(width * height);
1029
1030 decimal rm = ((decimal)r / totalPixels) * OO_255;
1031 decimal gm = ((decimal)g / totalPixels) * OO_255;
1032 decimal bm = ((decimal)b / totalPixels) * OO_255;
1033 decimal am = ((decimal)a / totalPixels) * OO_255;
1034
1035 if (pixelBytes == 3)
1036 am = 1m;
1037
1038 return new Color4((float)rm, (float)gm, (float)bm, (float)am);
1039
1040 }
1041 catch (Exception ex)
1042 {
1043 m_log.WarnFormat(
1044 "[WARP 3D IMAGE MODULE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}",
1045 textureID, j2kData.Length, ex.Message);
1046
1047 width = 0;
1048 height = 0;
1049 return new Color4(0.5f, 0.5f, 0.5f, 1.0f);
1050 }
1051 }
1052
1053 #endregion Static Helpers
1054 }
1055
1056 public static class ImageUtils
1057 {
1058 /// <summary>
1059 /// Performs bilinear interpolation between four values
1060 /// </summary>
1061 /// <param name="v00">First, or top left value</param>
1062 /// <param name="v01">Second, or top right value</param>
1063 /// <param name="v10">Third, or bottom left value</param>
1064 /// <param name="v11">Fourth, or bottom right value</param>
1065 /// <param name="xPercent">Interpolation value on the X axis, between 0.0 and 1.0</param>
1066 /// <param name="yPercent">Interpolation value on fht Y axis, between 0.0 and 1.0</param>
1067 /// <returns>The bilinearly interpolated result</returns>
1068 public static float Bilinear(float v00, float v01, float v10, float v11, float xPercent, float yPercent)
1069 {
1070 return Utils.Lerp(Utils.Lerp(v00, v01, xPercent), Utils.Lerp(v10, v11, xPercent), yPercent);
1071 }
1072 }
1073}