29 using System.Diagnostics;
31 using System.Drawing.Imaging;
34 using OpenSim.Framework;
35 using OpenSim.Region.Framework.Interfaces;
36 using OpenSim.Services.Interfaces;
38 namespace OpenSim.
Region.CoreModules.
World.Warp3DMap
40 public static class TerrainSplat
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");
49 private static readonly
UUID[] DEFAULT_TERRAIN_DETAIL =
new UUID[]
57 private static readonly Color[] DEFAULT_TERRAIN_COLOR =
new Color[]
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)
65 private static readonly
UUID TERRAIN_CACHE_MAGIC =
new UUID(
"2c0c7ef2-56be-4eb8-aacb-76712c535b4b");
69 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
70 private static string LogHeader =
"[WARP3D TERRAIN SPLAT]";
84 UUID[] textureIDs,
float[] startHeights,
float[] heightRanges,
85 Vector3d regionPosition,
IAssetService assetService,
bool textureTerrain)
87 Debug.Assert(textureIDs.Length == 4);
88 Debug.Assert(startHeights.Length == 4);
89 Debug.Assert(heightRanges.Length == 4);
91 Bitmap[] detailTexture =
new Bitmap[4];
96 for (
int i = 0; i < textureIDs.Length; i++)
98 if (textureIDs[i] ==
UUID.Zero)
99 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
102 #region Texture Fetching
104 if (assetService != null)
106 for (
int i = 0; i < 4; i++)
109 UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
112 asset = assetService.GetCached(cacheID.ToString());
117 using (System.IO.MemoryStream stream =
new System.IO.MemoryStream(asset.Data))
118 detailTexture[i] = (Bitmap)Image.FromStream(stream);
122 m_log.Warn(
"Failed to decode cached terrain texture " + cacheID +
123 " (textureID: " + textureIDs[i] +
"): " + ex.Message);
127 if (detailTexture[i] == null)
130 asset = assetService.Get(textureIDs[i].ToString());
136 try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
139 m_log.Warn(
"Failed to decode terrain texture " + asset.ID +
": " + ex.Message);
143 if (detailTexture[i] != null)
146 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
148 using (Bitmap origBitmap = detailTexture[i])
150 detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
156 using (System.IO.MemoryStream stream =
new System.IO.MemoryStream())
158 detailTexture[i].Save(stream, ImageFormat.Png);
159 data = stream.ToArray();
167 Flags = AssetFlags.Collectable,
169 ID = cacheID.ToString(),
173 Type = (sbyte)AssetType.Unknown
175 newAsset.Metadata.ContentType =
"image/png";
176 assetService.Store(newAsset);
182 #endregion Texture Fetching
186 for (
int i = 0; i < 4; i++)
188 if (detailTexture[i] == null)
190 m_log.DebugFormat(
"{0} Missing terrain texture for layer {1}. Filling with solid default color",
193 detailTexture[i] =
new Bitmap(256, 256, PixelFormat.Format24bppRgb);
194 using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
196 using (SolidBrush brush =
new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
197 gfx.FillRectangle(brush, 0, 0, 256, 256);
202 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
204 detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256);
211 float[,] layermap =
new float[256, 256];
214 int xFactor = terrain.Width / 256;
215 int yFactor = terrain.Height / 256;
220 for (
int y = 0; y < 256; y++)
222 for (
int x = 0; x < 256; x++)
224 float height = (float)terrain[x * xFactor, y * yFactor];
226 float pctX = (float)x / 255f;
227 float pctY = (float)y / 255f;
231 float startHeight = ImageUtils.Bilinear(
237 startHeight = Utils.Clamp(startHeight, 0f, 255f);
239 float heightRange = ImageUtils.Bilinear(
245 heightRange = Utils.Clamp(heightRange, 0f, 255f);
249 Vector3 vec =
new Vector3
251 ((
float)regionPosition.X + (x * xFactor)) * 0.20319f,
252 ((
float)regionPosition.Y + (y * yFactor)) * 0.20319f,
256 float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
257 float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
258 float noise = (lowFreq + highFreq) * 2f;
261 float layer = ((height + noise - startHeight) / heightRange) * 4f;
262 if (Single.IsNaN(layer))
264 layermap[x, y] = Utils.Clamp(layer, 0f, 3f);
270 #region Texture Compositing
272 Bitmap output =
new Bitmap(256, 256, PixelFormat.Format24bppRgb);
273 BitmapData outputData = output.LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
280 BitmapData[] datas =
new BitmapData[]
282 detailTexture[0].LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
283 detailTexture[1].LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
284 detailTexture[2].LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
285 detailTexture[3].LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
289 int[] comps =
new int[]
291 (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
292 (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
293 (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
294 (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
297 for (
int y = 0; y < 256; y++)
299 for (
int x = 0; x < 256; x++)
301 float layer = layermap[x, y];
304 int l0 = (int)Math.Floor(layer);
305 int l1 = Math.Min(l0 + 1, 3);
307 byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
308 byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
309 byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
311 float aB = *(ptrA + 0);
312 float aG = *(ptrA + 1);
313 float aR = *(ptrA + 2);
315 float bB = *(ptrB + 0);
316 float bG = *(ptrB + 1);
317 float bR = *(ptrB + 2);
319 float layerDiff = layer - l0;
322 *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
323 *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
324 *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
328 for (
int i = 0; i < detailTexture.Length; i++)
329 detailTexture[i].UnlockBits(datas[i]);
332 for (
int i = 0; i < detailTexture.Length; i++)
333 if (detailTexture[i] != null)
334 detailTexture[i].Dispose();
336 output.UnlockBits(outputData);
339 output.RotateFlip(RotateFlipType.RotateNoneFlipY);
341 #endregion Texture Compositing
346 public static Bitmap ResizeBitmap(Bitmap b,
int nWidth,
int nHeight)
348 m_log.DebugFormat(
"{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>",
349 LogHeader, b.Width, b.Height, nWidth, nHeight);
350 Bitmap result =
new Bitmap(nWidth, nHeight);
351 using (Graphics g = Graphics.FromImage(result))
352 g.DrawImage(b, 0, 0, nWidth, nHeight);
356 public static Bitmap SplatSimple(
float[] heightmap)
358 const float BASE_HSV_H = 93f / 360f;
359 const float BASE_HSV_S = 44f / 100f;
360 const float BASE_HSV_V = 34f / 100f;
362 Bitmap img =
new Bitmap(256, 256);
363 BitmapData bitmapData = img.LockBits(
new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
367 for (
int y = 255; y >= 0; y--)
369 for (
int x = 0; x < 256; x++)
371 float normHeight = heightmap[y * 256 + x] / 255f;
372 normHeight = Utils.Clamp(normHeight, BASE_HSV_V, 1.0f);
374 Color4 color = Color4.FromHSV(BASE_HSV_H, BASE_HSV_S, normHeight);
376 byte* ptr = (byte*)bitmapData.Scan0 + y * bitmapData.Stride + x * 3;
377 *(ptr + 0) = (byte)(color.B * 255f);
378 *(ptr + 1) = (byte)(color.G * 255f);
379 *(ptr + 2) = (byte)(color.R * 255f);
384 img.UnlockBits(bitmapData);
Asset class. All Assets are reference by this class or a class derived from this class ...