Actively dispose of Bitmaps in Warp3D image module and world map module once we've finished with them.
This might help with memory leakage issues though I suspect it won't.0.7.4.1
parent
3b25021180
commit
2b0de66216
|
@ -204,7 +204,10 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||||
Bitmap bitmap = renderer.Scene.getImage();
|
Bitmap bitmap = renderer.Scene.getImage();
|
||||||
|
|
||||||
if (m_useAntiAliasing)
|
if (m_useAntiAliasing)
|
||||||
bitmap = ImageUtils.ResizeImage(bitmap, viewport.Width, viewport.Height);
|
{
|
||||||
|
using (Bitmap origBitmap = bitmap)
|
||||||
|
bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height);
|
||||||
|
}
|
||||||
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
@ -318,8 +321,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||||
uint globalX, globalY;
|
uint globalX, globalY;
|
||||||
Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
|
Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
|
||||||
|
|
||||||
Bitmap image = TerrainSplat.Splat(heightmap, textureIDs, startHeights, heightRanges, new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain);
|
warp_Texture texture;
|
||||||
warp_Texture texture = new warp_Texture(image);
|
|
||||||
|
using (
|
||||||
|
Bitmap image
|
||||||
|
= TerrainSplat.Splat(
|
||||||
|
heightmap, textureIDs, startHeights, heightRanges,
|
||||||
|
new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain))
|
||||||
|
{
|
||||||
|
texture = new warp_Texture(image);
|
||||||
|
}
|
||||||
|
|
||||||
warp_Material material = new warp_Material(texture);
|
warp_Material material = new warp_Material(texture);
|
||||||
material.setReflectivity(50);
|
material.setReflectivity(50);
|
||||||
renderer.Scene.addMaterial("TerrainColor", material);
|
renderer.Scene.addMaterial("TerrainColor", material);
|
||||||
|
@ -546,42 +558,46 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream);
|
int pixelBytes;
|
||||||
width = bitmap.Width;
|
|
||||||
height = bitmap.Height;
|
|
||||||
|
|
||||||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
using (Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream))
|
||||||
int pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
|
|
||||||
|
|
||||||
// Sum up the individual channels
|
|
||||||
unsafe
|
|
||||||
{
|
{
|
||||||
if (pixelBytes == 4)
|
width = bitmap.Width;
|
||||||
|
height = bitmap.Height;
|
||||||
|
|
||||||
|
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||||
|
pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
|
||||||
|
|
||||||
|
// Sum up the individual channels
|
||||||
|
unsafe
|
||||||
{
|
{
|
||||||
for (int y = 0; y < height; y++)
|
if (pixelBytes == 4)
|
||||||
{
|
{
|
||||||
byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
|
for (int y = 0; y < height; y++)
|
||||||
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
{
|
||||||
b += row[x * pixelBytes + 0];
|
byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
|
||||||
g += row[x * pixelBytes + 1];
|
|
||||||
r += row[x * pixelBytes + 2];
|
for (int x = 0; x < width; x++)
|
||||||
a += row[x * pixelBytes + 3];
|
{
|
||||||
|
b += row[x * pixelBytes + 0];
|
||||||
|
g += row[x * pixelBytes + 1];
|
||||||
|
r += row[x * pixelBytes + 2];
|
||||||
|
a += row[x * pixelBytes + 3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
{
|
||||||
byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
|
for (int y = 0; y < height; y++)
|
||||||
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
{
|
||||||
b += row[x * pixelBytes + 0];
|
byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);
|
||||||
g += row[x * pixelBytes + 1];
|
|
||||||
r += row[x * pixelBytes + 2];
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
b += row[x * pixelBytes + 0];
|
||||||
|
g += row[x * pixelBytes + 1];
|
||||||
|
r += row[x * pixelBytes + 2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,218 +84,234 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||||
Debug.Assert(heightRanges.Length == 4);
|
Debug.Assert(heightRanges.Length == 4);
|
||||||
|
|
||||||
Bitmap[] detailTexture = new Bitmap[4];
|
Bitmap[] detailTexture = new Bitmap[4];
|
||||||
|
Bitmap output = null;
|
||||||
|
BitmapData outputData = null;
|
||||||
|
|
||||||
if (textureTerrain)
|
try
|
||||||
{
|
{
|
||||||
// Swap empty terrain textureIDs with default IDs
|
if (textureTerrain)
|
||||||
for (int i = 0; i < textureIDs.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (textureIDs[i] == UUID.Zero)
|
// Swap empty terrain textureIDs with default IDs
|
||||||
textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
|
for (int i = 0; i < textureIDs.Length; i++)
|
||||||
}
|
|
||||||
|
|
||||||
#region Texture Fetching
|
|
||||||
|
|
||||||
if (assetService != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
{
|
||||||
AssetBase asset;
|
if (textureIDs[i] == UUID.Zero)
|
||||||
UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
|
textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
|
||||||
|
}
|
||||||
// Try to fetch a cached copy of the decoded/resized version of this texture
|
|
||||||
asset = assetService.GetCached(cacheID.ToString());
|
#region Texture Fetching
|
||||||
if (asset != null)
|
|
||||||
|
if (assetService != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
try
|
AssetBase asset;
|
||||||
{
|
UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
|
||||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
|
|
||||||
detailTexture[i] = (Bitmap)Image.FromStream(stream);
|
// Try to fetch a cached copy of the decoded/resized version of this texture
|
||||||
}
|
asset = assetService.GetCached(cacheID.ToString());
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
m_log.Warn("Failed to decode cached terrain texture " + cacheID +
|
|
||||||
" (textureID: " + textureIDs[i] + "): " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detailTexture[i] == null)
|
|
||||||
{
|
|
||||||
// Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
|
|
||||||
asset = assetService.Get(textureIDs[i].ToString());
|
|
||||||
if (asset != null)
|
if (asset != null)
|
||||||
{
|
{
|
||||||
try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
|
try
|
||||||
|
{
|
||||||
|
using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
|
||||||
|
detailTexture[i] = (Bitmap)Image.FromStream(stream);
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
|
m_log.Warn("Failed to decode cached terrain texture " + cacheID +
|
||||||
|
" (textureID: " + textureIDs[i] + "): " + ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detailTexture[i] != null)
|
if (detailTexture[i] == null)
|
||||||
{
|
{
|
||||||
Bitmap bitmap = detailTexture[i];
|
// Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
|
||||||
|
asset = assetService.Get(textureIDs[i].ToString());
|
||||||
// Make sure this texture is the correct size, otherwise resize
|
if (asset != null)
|
||||||
if (bitmap.Width != 256 || bitmap.Height != 256)
|
|
||||||
bitmap = ImageUtils.ResizeImage(bitmap, 256, 256);
|
|
||||||
|
|
||||||
// Save the decoded and resized texture to the cache
|
|
||||||
byte[] data;
|
|
||||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
|
|
||||||
{
|
{
|
||||||
bitmap.Save(stream, ImageFormat.Png);
|
try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
|
||||||
data = stream.ToArray();
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache a PNG copy of this terrain texture
|
if (detailTexture[i] != null)
|
||||||
AssetBase newAsset = new AssetBase
|
|
||||||
{
|
{
|
||||||
Data = data,
|
Bitmap bitmap = detailTexture[i];
|
||||||
Description = "PNG",
|
|
||||||
Flags = AssetFlags.Collectable,
|
// Make sure this texture is the correct size, otherwise resize
|
||||||
FullID = cacheID,
|
if (bitmap.Width != 256 || bitmap.Height != 256)
|
||||||
ID = cacheID.ToString(),
|
{
|
||||||
Local = true,
|
using (Bitmap origBitmap = bitmap)
|
||||||
Name = String.Empty,
|
{
|
||||||
Temporary = true,
|
bitmap = ImageUtils.ResizeImage(origBitmap, 256, 256);
|
||||||
Type = (sbyte)AssetType.Unknown
|
}
|
||||||
};
|
}
|
||||||
newAsset.Metadata.ContentType = "image/png";
|
|
||||||
assetService.Store(newAsset);
|
// Save the decoded and resized texture to the cache
|
||||||
|
byte[] data;
|
||||||
|
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
|
||||||
|
{
|
||||||
|
bitmap.Save(stream, ImageFormat.Png);
|
||||||
|
data = stream.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache a PNG copy of this terrain texture
|
||||||
|
AssetBase newAsset = new AssetBase
|
||||||
|
{
|
||||||
|
Data = data,
|
||||||
|
Description = "PNG",
|
||||||
|
Flags = AssetFlags.Collectable,
|
||||||
|
FullID = cacheID,
|
||||||
|
ID = cacheID.ToString(),
|
||||||
|
Local = true,
|
||||||
|
Name = String.Empty,
|
||||||
|
Temporary = true,
|
||||||
|
Type = (sbyte)AssetType.Unknown
|
||||||
|
};
|
||||||
|
newAsset.Metadata.ContentType = "image/png";
|
||||||
|
assetService.Store(newAsset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Texture Fetching
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Texture Fetching
|
// Fill in any missing textures with a solid color
|
||||||
}
|
for (int i = 0; i < 4; i++)
|
||||||
|
|
||||||
// Fill in any missing textures with a solid color
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
if (detailTexture[i] == null)
|
|
||||||
{
|
{
|
||||||
// Create a solid color texture for this layer
|
if (detailTexture[i] == null)
|
||||||
detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
|
||||||
using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
|
|
||||||
{
|
{
|
||||||
using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
|
// Create a solid color texture for this layer
|
||||||
gfx.FillRectangle(brush, 0, 0, 256, 256);
|
detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||||
|
using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
|
||||||
|
{
|
||||||
|
using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
|
||||||
|
gfx.FillRectangle(brush, 0, 0, 256, 256);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
#region Layer Map
|
||||||
#region Layer Map
|
|
||||||
|
float[] layermap = new float[256 * 256];
|
||||||
float[] layermap = new float[256 * 256];
|
|
||||||
|
|
||||||
for (int y = 0; y < 256; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < 256; x++)
|
|
||||||
{
|
|
||||||
float height = heightmap[y * 256 + x];
|
|
||||||
|
|
||||||
float pctX = (float)x / 255f;
|
|
||||||
float pctY = (float)y / 255f;
|
|
||||||
|
|
||||||
// Use bilinear interpolation between the four corners of start height and
|
|
||||||
// height range to select the current values at this position
|
|
||||||
float startHeight = ImageUtils.Bilinear(
|
|
||||||
startHeights[0],
|
|
||||||
startHeights[2],
|
|
||||||
startHeights[1],
|
|
||||||
startHeights[3],
|
|
||||||
pctX, pctY);
|
|
||||||
startHeight = Utils.Clamp(startHeight, 0f, 255f);
|
|
||||||
|
|
||||||
float heightRange = ImageUtils.Bilinear(
|
|
||||||
heightRanges[0],
|
|
||||||
heightRanges[2],
|
|
||||||
heightRanges[1],
|
|
||||||
heightRanges[3],
|
|
||||||
pctX, pctY);
|
|
||||||
heightRange = Utils.Clamp(heightRange, 0f, 255f);
|
|
||||||
|
|
||||||
// Generate two frequencies of perlin noise based on our global position
|
|
||||||
// The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
|
|
||||||
Vector3 vec = new Vector3
|
|
||||||
(
|
|
||||||
((float)regionPosition.X + x) * 0.20319f,
|
|
||||||
((float)regionPosition.Y + y) * 0.20319f,
|
|
||||||
height * 0.25f
|
|
||||||
);
|
|
||||||
|
|
||||||
float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
|
|
||||||
float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
|
|
||||||
float noise = (lowFreq + highFreq) * 2f;
|
|
||||||
|
|
||||||
// Combine the current height, generated noise, start height, and height range parameters, then scale all of it
|
|
||||||
float layer = ((height + noise - startHeight) / heightRange) * 4f;
|
|
||||||
if (Single.IsNaN(layer)) layer = 0f;
|
|
||||||
layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Layer Map
|
|
||||||
|
|
||||||
#region Texture Compositing
|
|
||||||
|
|
||||||
Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
|
||||||
BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
// Get handles to all of the texture data arrays
|
|
||||||
BitmapData[] datas = new BitmapData[]
|
|
||||||
{
|
|
||||||
detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
|
|
||||||
detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
|
|
||||||
detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
|
|
||||||
detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] comps = new int[]
|
|
||||||
{
|
|
||||||
(datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
|
||||||
(datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
|
||||||
(datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
|
||||||
(datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int y = 0; y < 256; y++)
|
for (int y = 0; y < 256; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < 256; x++)
|
for (int x = 0; x < 256; x++)
|
||||||
{
|
{
|
||||||
float layer = layermap[y * 256 + x];
|
float height = heightmap[y * 256 + x];
|
||||||
|
|
||||||
// Select two textures
|
float pctX = (float)x / 255f;
|
||||||
int l0 = (int)Math.Floor(layer);
|
float pctY = (float)y / 255f;
|
||||||
int l1 = Math.Min(l0 + 1, 3);
|
|
||||||
|
// Use bilinear interpolation between the four corners of start height and
|
||||||
byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
|
// height range to select the current values at this position
|
||||||
byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
|
float startHeight = ImageUtils.Bilinear(
|
||||||
byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
|
startHeights[0],
|
||||||
|
startHeights[2],
|
||||||
float aB = *(ptrA + 0);
|
startHeights[1],
|
||||||
float aG = *(ptrA + 1);
|
startHeights[3],
|
||||||
float aR = *(ptrA + 2);
|
pctX, pctY);
|
||||||
|
startHeight = Utils.Clamp(startHeight, 0f, 255f);
|
||||||
float bB = *(ptrB + 0);
|
|
||||||
float bG = *(ptrB + 1);
|
float heightRange = ImageUtils.Bilinear(
|
||||||
float bR = *(ptrB + 2);
|
heightRanges[0],
|
||||||
|
heightRanges[2],
|
||||||
float layerDiff = layer - l0;
|
heightRanges[1],
|
||||||
|
heightRanges[3],
|
||||||
// Interpolate between the two selected textures
|
pctX, pctY);
|
||||||
*(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
|
heightRange = Utils.Clamp(heightRange, 0f, 255f);
|
||||||
*(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
|
|
||||||
*(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
|
// Generate two frequencies of perlin noise based on our global position
|
||||||
|
// The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
|
||||||
|
Vector3 vec = new Vector3
|
||||||
|
(
|
||||||
|
((float)regionPosition.X + x) * 0.20319f,
|
||||||
|
((float)regionPosition.Y + y) * 0.20319f,
|
||||||
|
height * 0.25f
|
||||||
|
);
|
||||||
|
|
||||||
|
float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
|
||||||
|
float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
|
||||||
|
float noise = (lowFreq + highFreq) * 2f;
|
||||||
|
|
||||||
|
// Combine the current height, generated noise, start height, and height range parameters, then scale all of it
|
||||||
|
float layer = ((height + noise - startHeight) / heightRange) * 4f;
|
||||||
|
if (Single.IsNaN(layer)) layer = 0f;
|
||||||
|
layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Layer Map
|
||||||
|
|
||||||
|
#region Texture Compositing
|
||||||
|
|
||||||
|
output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||||
|
outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
// Get handles to all of the texture data arrays
|
||||||
|
BitmapData[] datas = new BitmapData[]
|
||||||
|
{
|
||||||
|
detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
|
||||||
|
detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
|
||||||
|
detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
|
||||||
|
detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
|
||||||
|
};
|
||||||
|
|
||||||
|
int[] comps = new int[]
|
||||||
|
{
|
||||||
|
(datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||||
|
(datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||||
|
(datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||||
|
(datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int y = 0; y < 256; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 256; x++)
|
||||||
|
{
|
||||||
|
float layer = layermap[y * 256 + x];
|
||||||
|
|
||||||
|
// Select two textures
|
||||||
|
int l0 = (int)Math.Floor(layer);
|
||||||
|
int l1 = Math.Min(l0 + 1, 3);
|
||||||
|
|
||||||
|
byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
|
||||||
|
byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
|
||||||
|
byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
|
||||||
|
|
||||||
|
float aB = *(ptrA + 0);
|
||||||
|
float aG = *(ptrA + 1);
|
||||||
|
float aR = *(ptrA + 2);
|
||||||
|
|
||||||
|
float bB = *(ptrB + 0);
|
||||||
|
float bG = *(ptrB + 1);
|
||||||
|
float bR = *(ptrB + 2);
|
||||||
|
|
||||||
|
float layerDiff = layer - l0;
|
||||||
|
|
||||||
|
// Interpolate between the two selected textures
|
||||||
|
*(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
|
||||||
|
*(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
|
||||||
|
*(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
detailTexture[i].UnlockBits(datas[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
detailTexture[i].UnlockBits(datas[i]);
|
if (detailTexture[i] != null)
|
||||||
|
detailTexture[i].Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
output.UnlockBits(outputData);
|
output.UnlockBits(outputData);
|
||||||
|
|
|
@ -1343,14 +1343,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
if (terrain == null)
|
if (terrain == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_log.DebugFormat("[WORLDMAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
byte[] data = terrain.WriteJpeg2000Image();
|
byte[] data = terrain.WriteJpeg2000Image();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
byte[] overlay = GenerateOverlay();
|
byte[] overlay = GenerateOverlay();
|
||||||
|
|
||||||
m_log.Debug("[WORLDMAP]: STORING MAPTILE IMAGE");
|
|
||||||
|
|
||||||
UUID terrainImageID = UUID.Random();
|
UUID terrainImageID = UUID.Random();
|
||||||
UUID parcelImageID = UUID.Zero;
|
UUID parcelImageID = UUID.Zero;
|
||||||
|
|
||||||
|
@ -1365,7 +1365,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||||
asset.Flags = AssetFlags.Maptile;
|
asset.Flags = AssetFlags.Maptile;
|
||||||
|
|
||||||
// Store the new one
|
// Store the new one
|
||||||
m_log.DebugFormat("[WORLDMAP]: Storing map tile {0}", asset.ID);
|
m_log.DebugFormat("[WORLDMAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
m_scene.AssetService.Store(asset);
|
m_scene.AssetService.Store(asset);
|
||||||
|
|
||||||
if (overlay != null)
|
if (overlay != null)
|
||||||
|
|
Loading…
Reference in New Issue