public void Render(IntPtr pRender) { unsafe { ColorTable table = BurnGfxData.Instance.GetMapColorTable(mapId); PixelColor *ptr = (PixelColor *)pRender; int pos = 0; int nextstep = 0; for (int i = 0; i < Width * Height; i++) { byte fileData = data[i]; int x = pos % Width; int y = (pos - x) / Width; ptr[(x + y * Width)] = table.GetColor(fileData); pos += 4; nextstep += 4; if (nextstep >= Width * Height) { pos -= Width * Height; pos++; nextstep = 0; } } } }
// This draws the picture to the given pixel color data // Throws exception on failure public void DrawToPixelData(Stream stream, PixelColor *target, int targetwidth, int targetheight, int x, int y) { int width, height, ox, oy; // Read pixel data PixelColor[] pixeldata = ReadAsPixelData(stream, out width, out height, out ox, out oy); if (pixeldata != null) { // Go for all source pixels // We don't care about the original image offset, so reuse ox/oy for (ox = 0; ox < width; ox++) { for (oy = 0; oy < height; oy++) { // Copy this pixel? if (pixeldata[oy * width + ox].a > 0.5f) { // Calculate target pixel and copy when within bounds int tx = x + ox; int ty = y + oy; if ((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight)) { target[ty * targetwidth + tx] = pixeldata[oy * width + ox]; } } } } } else { throw new InvalidDataException("Failed to read pixeldata"); //mxd. Let's throw exception on failure } }
// Constructor public Plotter(PixelColor *pixels, int width, int height) { // Initialize this.pixels = pixels; this.width = width; this.height = height; }
unsafe void MakeAlphaTestImage(LocalLoadResult loadResult) { if (loadResult.bitmap == null) { return; } int width = loadResult.bitmap.Width; int height = loadResult.bitmap.Height; loadResult.alphatestWidth = width; loadResult.alphatestHeight = height; BitmapData bmpdata = loadResult.bitmap.LockBits(new Rectangle(0, 0, loadResult.bitmap.Size.Width, loadResult.bitmap.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); for (int y = 0; y < height; y++) { PixelColor *line = pixels + y * width; for (int x = 0; x < width; x++) { if (line[x].a == 0) { if (loadResult.alphatest == null) { loadResult.alphatest = new BitArray(width * height, true); } loadResult.alphatest.Set(x + y * width, false); } } } loadResult.bitmap.UnlockBits(bmpdata); }
private unsafe static Bitmap CreateVoxelTexture(PixelColor[] palette) { Bitmap bmp = new Bitmap(16, 16); BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); if (bmpdata != null) { PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); const int numpixels = 256; int i = 255; for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--, i--) { cp->r = palette[i].r; cp->g = palette[i].g; cp->b = palette[i].b; cp->a = palette[i].a; } bmp.UnlockBits(bmpdata); } //scale bitmap, so colors stay (almost) the same when bilinear filtering is enabled Bitmap scaled = new Bitmap(64, 64); using (Graphics gs = Graphics.FromImage(scaled)) { gs.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gs.DrawImage(bmp, new Rectangle(0, 0, 64, 64), new Rectangle(0, 0, 16, 16), GraphicsUnit.Pixel); } bmp.Dispose(); return(scaled); }
// This draws the picture to the given pixel color data // Throws exception on failure public void DrawToPixelData(Stream stream, PixelColor *target, int targetwidth, int targetheight, int x, int y) { PixelColorBlock pixeldata; int width, height, ox, oy, tx, ty; // Read pixel data pixeldata = ReadAsPixelData(stream, out width, out height, out ox, out oy); if (pixeldata != null) { // Go for all source pixels // We don't care about the original image offset, so reuse ox/oy for (ox = 0; ox < width; ox++) { for (oy = 0; oy < height; oy++) { // Copy this pixel? if (pixeldata.Pointer[oy * width + ox].a > 0.5f) { // Calculate target pixel and copy when within bounds tx = x + ox; ty = y + oy; if ((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight)) { target[ty * targetwidth + tx] = pixeldata.Pointer[oy * width + ox]; } } } } } }
// This draws the picture to the given pixel color data // Throws exception on failure public void DrawToPixelData(Stream stream, PixelColor *target, int targetwidth, int targetheight, int x, int y) { // Get bitmap Bitmap bmp = ReadAsBitmap(stream); int width = bmp.Size.Width; int height = bmp.Size.Height; // Lock bitmap pixels BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); PixelColor *pixels = (PixelColor *)bmpdata.Scan0.ToPointer(); // Go for all pixels in the original image for (int ox = 0; ox < width; ox++) { for (int oy = 0; oy < height; oy++) { // Copy this pixel? if (pixels[oy * width + ox].a > 0.5f) { // Calculate target pixel and copy when within bounds int tx = x + ox; int ty = y + oy; if ((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight)) { target[ty * targetwidth + tx] = pixels[oy * width + ox]; } } } } // Done bmp.UnlockBits(bmpdata); bmp.Dispose(); }
// This draws a pixel alpha blended public void DrawPixelAlpha(int x, int y, ref PixelColor c) { // Draw only when within range if ((x >= 0) && (x < visiblewidth) && (y >= 0) && (y < visibleheight)) { // Get the target pixel PixelColor *p = pixels + (y * width + x); // Not drawn on target yet? if (*(int *)p == 0) { // Simply apply color to pixel *p = c; } else { // Blend with pixel float a = c.a * 0.003921568627450980392156862745098f; if (p->a + c.a > 255) { p->a = 255; } else { p->a += c.a; } p->r = (byte)(p->r * (1f - a) + c.r * a); p->g = (byte)(p->g * (1f - a) + c.g * a); p->b = (byte)(p->b * (1f - a) + c.b * a); } } }
// This applies color-correction over a block of pixel data internal unsafe void ApplyColorCorrection(PixelColor *pixels, int numpixels) { for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = correctiontable[cp->r]; cp->g = correctiontable[cp->g]; cp->b = correctiontable[cp->b]; } }
// Constructor public Plotter(PixelColor *pixels, int width, int height, int visiblewidth, int visibleheight) { // Initialize this.pixels = pixels; this.width = width; this.height = height; this.visiblewidth = width; this.visibleheight = height; // We have no destructor GC.SuppressFinalize(this); }
// This loads the image protected override void LocalLoadImage() { // Leave when already loaded if (this.IsImageLoaded) { return; } if ((width == 0) || (height == 0)) { return; } lock (this) { // Create bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); for (int i = 0; i < (width * height); i++) { *pixels = color; pixels++; } bitmap.UnlockBits(bitmapdata); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to create color image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message); loadfailed = true; } // Dispose bitmap if load failed if (loadfailed && (bitmap != null)) { bitmap.Dispose(); bitmap = null; } // Pass on to base base.LocalLoadImage(); } }
// This creates a Bitmap from the given data // Returns null on failure public Bitmap ReadAsBitmap(Stream stream, out int offsetx, out int offsety) { offsetx = int.MinValue; offsety = int.MinValue; int width, height; Bitmap bmp; // Read pixel data PixelColor[] pixeldata = ReadAsPixelData(stream, out width, out height); if (pixeldata != null) { try { // Create bitmap and lock pixels bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *targetdata = (PixelColor *)bitmapdata.Scan0.ToPointer(); //mxd. Copy the pixels int size = pixeldata.Length - 1; for (PixelColor *cp = targetdata + size; cp >= targetdata; cp--) { *cp = pixeldata[size--]; } // Done bmp.UnlockBits(bitmapdata); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to make Doom flat data. " + e.GetType().Name + ": " + e.Message); return(null); } } else { // Failed loading picture bmp = null; } // Return result return(bmp); }
// Constructor public PixelColorBlock(int width, int height) { // Check input if ((width <= 0) || (height <= 0)) { throw new ArgumentException("Cannot allocate a memory block of zero size!"); } // Initialize this.width = width; this.height = height; this.memorysize = width * height * sizeof(PixelColor); this.memory = (PixelColor *)Marshal.AllocCoTaskMem(memorysize); if (this.memory == (PixelColor *)0) { throw new OutOfMemoryException(); } GC.AddMemoryPressure(memorysize); }
private static unsafe void ParallelForEach(PixelColor *startPtr, int width, int height) { Parallel.ForEach(Partitioner.Create(0, height), (h) => { var ptr = startPtr + h.Item1 * width; for (int y = h.Item1; y < h.Item2; y++) { for (int x = 0; x < width; x++) { var c = *ptr; var gray = ((c.Red * 38 + c.Green * 75 + c.Blue * 15) >> 7); (*ptr).Green = (*ptr).Red = (*ptr).Blue = (byte)gray; ptr++; } } }); }
// This creates a Bitmap from the given data // Returns null on failure public Bitmap ReadAsBitmap(Stream stream) { int width, height; Bitmap bmp; // Read pixel data PixelColorBlock pixeldata = ReadAsPixelData(stream, out width, out height); if (pixeldata != null) { try { // Create bitmap and lock pixels bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *targetdata = (PixelColor *)bitmapdata.Scan0.ToPointer(); // Copy the pixels General.CopyMemory(targetdata, pixeldata.Pointer, (uint)(width * height * sizeof(PixelColor))); // Done bmp.UnlockBits(bitmapdata); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to make Doom flat data. " + e.GetType().Name + ": " + e.Message); return(null); } } else { // Failed loading picture bmp = null; } // Return result return(bmp); }
// This loads the image protected override void LocalLoadImage() { IImageReader reader; MemoryStream mem; byte[] membytes; Graphics g = null; // Checks if (this.IsImageLoaded) { return; } if ((width == 0) || (height == 0)) { return; } lock (this) { // Create texture bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor)); bitmap.UnlockBits(bitmapdata); g = Graphics.FromImage(bitmap); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message); loadfailed = true; } if (!loadfailed) { // Go for all patches foreach (TexturePatch p in patches) { // Get the patch data stream Stream patchdata = General.Map.Data.GetPatchData(p.lumpname); if (patchdata != null) { // Copy patch data to memory patchdata.Seek(0, SeekOrigin.Begin); membytes = new byte[(int)patchdata.Length]; patchdata.Read(membytes, 0, (int)patchdata.Length); mem = new MemoryStream(membytes); mem.Seek(0, SeekOrigin.Begin); // Get a reader for the data reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette); if (reader is UnknownImageReader) { // Data is in an unknown format! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); loadfailed = true; } else { // Get the patch mem.Seek(0, SeekOrigin.Begin); Bitmap patchbmp = null; try { patchbmp = reader.ReadAsBitmap(mem); } catch (InvalidDataException) { // Data cannot be read! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); loadfailed = true; } if (patchbmp != null) { // Adjust patch alpha if (p.alpha < 1.0f) { BitmapData bmpdata = null; try { bmpdata = patchbmp.LockBits(new Rectangle(0, 0, patchbmp.Size.Width, patchbmp.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + p.lumpname + "' for alpha adjustment. " + e.GetType().Name + ": " + e.Message); } if (bmpdata != null) { PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); int numpixels = bmpdata.Width * bmpdata.Height; for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->a = (byte)((((float)cp->a * PixelColor.BYTE_TO_FLOAT) * p.alpha) * 255.0f); } patchbmp.UnlockBits(bmpdata); } } // Draw the patch on the texture image Rectangle tgtrect = new Rectangle(p.x, p.y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); patchbmp.Dispose(); } } // Done mem.Dispose(); } else { // Missing a patch lump! General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'"); loadfailed = true; } } } // Dispose bitmap if load failed if (loadfailed && (bitmap != null)) { bitmap.Dispose(); bitmap = null; } // Pass on to base base.LocalLoadImage(); } }
//mxd private Bitmap TransformPatch(Bitmap bitmap, TexturePatch p, Bitmap patchbmp) { //mxd. Flip if (p.FlipX || p.FlipY) { RotateFlipType flip; if (p.FlipX && !p.FlipY) { flip = RotateFlipType.RotateNoneFlipX; } else if (!p.FlipX && p.FlipY) { flip = RotateFlipType.RotateNoneFlipY; } else { flip = RotateFlipType.RotateNoneFlipXY; } patchbmp.RotateFlip(flip); } //mxd. Then rotate. I do it this way because RotateFlip function rotates THEN flips, and GZDoom does it the other way around. if (p.Rotate != 0) { RotateFlipType rotate; switch (p.Rotate) { case 90: rotate = RotateFlipType.Rotate90FlipNone; break; case 180: rotate = RotateFlipType.Rotate180FlipNone; break; default: rotate = RotateFlipType.Rotate270FlipNone; break; } patchbmp.RotateFlip(rotate); } // Adjust patch alpha, apply tint or blend if (p.BlendStyle != TexturePathBlendStyle.NONE || p.RenderStyle != TexturePathRenderStyle.COPY) { BitmapData bmpdata = null; try { bmpdata = patchbmp.LockBits(new Rectangle(0, 0, patchbmp.Size.Width, patchbmp.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + p.LumpName + "\" for alpha adjustment. " + e.GetType().Name + ": " + e.Message); } if (bmpdata != null) { PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); int numpixels = bmpdata.Width * bmpdata.Height; int patchalpha = (int)Math.Round(General.Clamp(p.Alpha, 0f, 1f) * 255); //convert alpha to [0-255] range //mxd. Blend/Tint support if (p.BlendStyle == TexturePathBlendStyle.BLEND) { for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)((cp->r * p.BlendColor.r) * PixelColor.BYTE_TO_FLOAT); cp->g = (byte)((cp->g * p.BlendColor.g) * PixelColor.BYTE_TO_FLOAT); cp->b = (byte)((cp->b * p.BlendColor.b) * PixelColor.BYTE_TO_FLOAT); } } else if (p.BlendStyle == TexturePathBlendStyle.TINT) { float tintammount = p.BlendColor.a * PixelColor.BYTE_TO_FLOAT; // -0.1f; if (tintammount > 0) { float br = p.BlendColor.r * PixelColor.BYTE_TO_FLOAT * tintammount; float bg = p.BlendColor.g * PixelColor.BYTE_TO_FLOAT * tintammount; float bb = p.BlendColor.b * PixelColor.BYTE_TO_FLOAT * tintammount; float invtintammount = 1.0f - tintammount; for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * invtintammount + br) * 255.0f); cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * invtintammount + bg) * 255.0f); cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * invtintammount + bb) * 255.0f); } } } //mxd. Apply RenderStyle if (p.RenderStyle == TexturePathRenderStyle.BLEND) { for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); } } //mxd. We need a copy of underlying part of texture for these styles else if (p.RenderStyle != TexturePathRenderStyle.COPY) { // Copy portion of texture int lockWidth = (p.X + patchbmp.Size.Width > bitmap.Width) ? bitmap.Width - p.X : patchbmp.Size.Width; int lockHeight = (p.Y + patchbmp.Size.Height > bitmap.Height) ? bitmap.Height - p.Y : patchbmp.Size.Height; Bitmap source = new Bitmap(patchbmp.Size.Width, patchbmp.Size.Height); using (Graphics sg = Graphics.FromImage(source)) sg.DrawImageUnscaled(bitmap, new Rectangle(-p.X, -p.Y, lockWidth, lockHeight)); // Lock texture BitmapData texturebmpdata = null; try { texturebmpdata = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture \"" + this.Name + "\" to apply render style. " + e.GetType().Name + ": " + e.Message); } if (texturebmpdata != null) { PixelColor *texturepixels = (PixelColor *)(texturebmpdata.Scan0.ToPointer()); PixelColor *tcp = texturepixels + numpixels - 1; switch (p.RenderStyle) { case TexturePathRenderStyle.ADD: for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Min(255, cp->r + tcp->r); cp->g = (byte)Math.Min(255, cp->g + tcp->g); cp->b = (byte)Math.Min(255, cp->b + tcp->b); cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); tcp--; } break; case TexturePathRenderStyle.SUBTRACT: for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Max(0, tcp->r - cp->r); cp->g = (byte)Math.Max(0, tcp->g - cp->g); cp->b = (byte)Math.Max(0, tcp->b - cp->b); cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); tcp--; } break; case TexturePathRenderStyle.REVERSE_SUBTRACT: for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Max(0, cp->r - tcp->r); cp->g = (byte)Math.Max(0, cp->g - tcp->g); cp->b = (byte)Math.Max(0, cp->b - tcp->b); cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); tcp--; } break; case TexturePathRenderStyle.MODULATE: for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)((cp->r * tcp->r) * PixelColor.BYTE_TO_FLOAT); cp->g = (byte)((cp->g * tcp->g) * PixelColor.BYTE_TO_FLOAT); cp->b = (byte)((cp->b * tcp->b) * PixelColor.BYTE_TO_FLOAT); tcp--; } break; } source.UnlockBits(texturebmpdata); } } patchbmp.UnlockBits(bmpdata); } } return(patchbmp); }
// This loads the image protected override LocalLoadResult LocalLoadImage() { // Checks if (width == 0 || height == 0) { return(new LocalLoadResult(null)); } Graphics g = null; Bitmap bitmap = null; List <LogMessage> messages = new List <LogMessage>(); // Create texture bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); General.ZeroPixels(pixels, width * height); bitmap.UnlockBits(bitmapdata); g = Graphics.FromImage(bitmap); } catch (Exception e) { // Unable to make bitmap messages.Add(new LogMessage(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message)); } int missingpatches = 0; //mxd if (patches.Count == 0) //mxd { //mxd. Empty image will suffice here, I suppose... if (nulltexture) { return(new LocalLoadResult(bitmap, messages)); } // No patches! messages.Add(new LogMessage(ErrorType.Error, "No patches are defined for texture \"" + this.Name + "\"")); } else if (!messages.Any(x => x.Type == ErrorType.Error)) { // Go for all patches foreach (TexturePatch p in patches) { //mxd. Some patches (like "TNT1A0") should be skipped if (p.Skip) { continue; } // Get the patch data stream string patchlocation = string.Empty; //mxd Stream patchdata = General.Map.Data.GetPatchData(p.LumpName, p.HasLongName, ref patchlocation); if (patchdata != null) { // Copy patch data to memory byte[] membytes = new byte[(int)patchdata.Length]; lock (patchdata) //mxd { patchdata.Seek(0, SeekOrigin.Begin); patchdata.Read(membytes, 0, (int)patchdata.Length); } MemoryStream mem = new MemoryStream(membytes); mem.Seek(0, SeekOrigin.Begin); Bitmap patchbmp = ImageDataFormat.TryLoadImage(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette); if (patchbmp == null) { //mxd. Probably that's a flat?.. if (General.Map.Config.MixTexturesFlats) { patchbmp = ImageDataFormat.TryLoadImage(mem, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette); } if (patchbmp == null) { // Data is in an unknown format! if (!nulltexture) { messages.Add(new LogMessage(optional ? ErrorType.Warning : ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.LumpName) + "\" data format could not be read, while loading texture \"" + this.Name + "\"")); } missingpatches++; //mxd } } if (patchbmp != null) { //mxd. Apply transformations from TexturePatch patchbmp = TransformPatch(bitmap, p, patchbmp); // Draw the patch on the texture image Rectangle tgtrect = new Rectangle(p.X, p.Y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); patchbmp.Dispose(); } // Done mem.Dispose(); } else { //mxd. ZDoom can use any known graphic as patch if (General.Map.Config.MixTexturesFlats) { ImageData img = General.Map.Data.GetTextureImage(p.LumpName); if (!(img is UnknownImage) && img != this) { //mxd. Apply transformations from TexturePatch. We don't want to modify the original bitmap here, so make a copy Bitmap bmp = new Bitmap(img.LocalGetBitmap()); Bitmap patchbmp = TransformPatch(bitmap, p, bmp); // Draw the patch on the texture image Rectangle tgtrect = new Rectangle(p.X, p.Y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); patchbmp.Dispose(); continue; } } // Missing a patch lump! if (!nulltexture) { messages.Add(new LogMessage(optional ? ErrorType.Warning : ErrorType.Error, "Missing patch lump \"" + p.LumpName + "\" while loading texture \"" + this.Name + "\"")); } missingpatches++; //mxd } } } // Dispose bitmap if load failed if (!nulltexture && (bitmap != null) && (messages.Any(x => x.Type == ErrorType.Error) || missingpatches >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded { bitmap.Dispose(); bitmap = null; } return(new LocalLoadResult(bitmap, messages)); }
// Background downloading and processing private unsafe void UpdateThread() { HttpWebResponse webresponse = null; bool failed = false; string failmsg = ""; Image downloadimg = null; DateTime starttime = new DateTime(); // Make the GET request HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(ADDRESS); webrequest.Referer = REFERRER; webrequest.Method = "GET"; webrequest.KeepAlive = false; webrequest.Timeout = 5000; webrequest.UserAgent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14 GTB5 (.NET CLR 3.5.30729)"; webrequest.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); try { // Download! webresponse = (HttpWebResponse)webrequest.GetResponse(); } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Web request " + e.GetType().Name + ": " + e.Message; webresponse = null; } if (!failed) { try { // Make image downloadimg = Image.FromStream(webresponse.GetResponseStream()); webresponse.Close(); } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Image read " + e.GetType().Name + ": " + e.Message; downloadimg = null; } } if (!failed) { // Dispose old images if (images != null) { for (int i = 0; i < images.Length; i++) { if (images[i] != null) { images[i].Dispose(); } } } images = null; arrowlocations = null; //#if !DEBUG try { //#endif // Time at which the animation starts DateTime now = DateTime.Now.AddMinutes(ADJUST_TIME_MINUTES); int nearest5min = (int)(Math.Round((double)now.Minute / (double)5) * (double)5); starttime = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0); starttime = starttime.AddMinutes(nearest5min); // Prepare variables to track the rain DateTime incomingtime = new DateTime(); bool isincoming = false; DateTime cleartime = new DateTime(); int clearframecount = 0; // Disassemble the image into separate images FrameDimension fd = new FrameDimension(downloadimg.FrameDimensionsList[0]); int numimages = downloadimg.GetFrameCount(fd); images = new Image[numimages]; downloadimg.SelectActiveFrame(fd, 0); Bitmap firstbmp = new Bitmap(downloadimg); Size sz = firstbmp.Size; BitmapData firstbmpdata = firstbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); for (int i = 0; i < numimages; i++) { downloadimg.SelectActiveFrame(fd, i); Bitmap imgbmp = new Bitmap(downloadimg); Bitmap newbmp = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb); // Start processing the image BitmapData imgbmpdata = imgbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData newbmpdata = newbmp.LockBits(new Rectangle(0, 0, sz.Width, sz.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); PixelColor *fpixels = (PixelColor *)(firstbmpdata.Scan0.ToPointer()); PixelColor *ipixels = (PixelColor *)(imgbmpdata.Scan0.ToPointer()); PixelColor *npixels = (PixelColor *)(newbmpdata.Scan0.ToPointer()); // Go for all pixels bool wholeframeclear = true; for (int y = 0; y < sz.Height; y++) { for (int x = 0; x < sz.Width; x++) { // We compare the pixel of the first image (no clouds) with // the current image to determine if there are clouds here bool isclear = (ipixels->b == fpixels->b) && (ipixels->g == fpixels->g) && (ipixels->r == fpixels->r); // Detect rain at current location if (!isclear && (x >= LOCATION_X - LOCATION_RADIUS) && (x <= LOCATION_X + LOCATION_RADIUS) && (y >= LOCATION_Y - LOCATION_RADIUS) && (y <= LOCATION_Y + LOCATION_RADIUS) && (i > 0)) { wholeframeclear = false; if (!isincoming) { // Rain! incomingtime = starttime.AddMinutes(i * 10); isincoming = true; clearframecount = 0; } if (clearframecount < CLEAR_FRAMES) { clearframecount = 0; } } // Clear pixel? if (isclear) { // This pixel is normal. PixelColor ds = PixelColor.Desaturate(*ipixels); * npixels = PixelColor.Lerp(ds, *ipixels, 0.1f); * npixels = PixelColor.Scale(*npixels, 1.1f); PixelColor add = new PixelColor(0, 10, 10, 10); * npixels = PixelColor.Add(*npixels, add); } else { // This pixel is a cloud. PixelColor mod = new PixelColor(255, 160, 160, 250); * npixels = PixelColor.Modulate(*ipixels, mod); * npixels = PixelColor.Scale(*npixels, 1.8f); } // Next pixel fpixels++; ipixels++; npixels++; } } // Whole frame clear of rain at current location? if (wholeframeclear) { // Count this frame as a clear frame clearframecount++; if (clearframecount == CLEAR_FRAMES) { // The clear time is 3 frames ago cleartime = starttime.AddMinutes((i - 3) * 10); } } // Clean up imgbmp.UnlockBits(imgbmpdata); newbmp.UnlockBits(newbmpdata); images[i] = newbmp; imgbmp.Dispose(); imgbmp = null; } // Show incoming time if (isincoming) { incomingtext = incomingtime.Hour + ":" + incomingtime.Minute.ToString("00"); flashincoming = true; } else { incomingtext = "N / A"; flashincoming = false; } // Show clear time if (clearframecount >= CLEAR_FRAMES) { cleartext = cleartime.Hour + ":" + cleartime.Minute.ToString("00"); flashclear = true; } else { cleartext = "N / A"; flashclear = false; } // Clean up firstbmp.UnlockBits(firstbmpdata); firstbmp.Dispose(); firstbmp = null; downloadimg.Dispose(); downloadimg = null; //#if !DEBUG } catch (Exception e) { failed = true; failmsg = "Failed to update buienradar. Image processing " + e.GetType().Name + ": " + e.Message; downloadimg = null; } //#endif if (images != null) { // Set up some random arrow locations, for decorative reason Random rnd = new Random(); arrowlocations = new Size[images.Length]; Size offset = new Size(radar.Left + 100 + rnd.Next(radar.Width - movearrow1.Width - 100), radar.Top + 100 + rnd.Next(radar.Height - movearrow1.Height - 100)); for (int i = 0; i < images.Length; i++) { arrowlocations[i] = offset + new Size(rnd.Next(100) - 50, rnd.Next(100) - 50); } } // Done firstimagetime = starttime; nextupdatedelay = NORMAL_UPDATE_DELAY; } // Handle failure if (failed) { HandleFail(failmsg); } else { updatefailed = false; } // We're done updating (either successful or failed) UpdateComplete(); }
// This requests loading the image protected virtual void LocalLoadImage() { BitmapData bmpdata = null; lock (this) { // Bitmap loaded successfully? if (bitmap != null) { // Bitmap has incorrect format? if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { if (dynamictexture) { throw new Exception("Dynamic images must be in 32 bits ARGB format."); } //General.ErrorLogger.Add(ErrorType.Warning, "Image '" + name + "' does not have A8R8G8B8 pixel format. Conversion was needed."); Bitmap oldbitmap = bitmap; try { // Convert to desired pixel format bitmap = new Bitmap(oldbitmap.Size.Width, oldbitmap.Size.Height, PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bitmap); g.PageUnit = GraphicsUnit.Pixel; g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = PixelOffsetMode.None; g.Clear(Color.Transparent); g.DrawImage(oldbitmap, 0, 0, oldbitmap.Size.Width, oldbitmap.Size.Height); g.Dispose(); oldbitmap.Dispose(); } catch (Exception e) { bitmap = oldbitmap; General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } } // This applies brightness correction on the image if (usecolorcorrection) { try { // Try locking the bitmap bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } // Bitmap locked? if (bmpdata != null) { // Apply color correction PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); General.Colors.ApplColorCorrection(pixels, bmpdata.Width * bmpdata.Height); bitmap.UnlockBits(bmpdata); } } } else { // Loading failed // We still mark the image as ready so that it will // not try loading again until Reload Resources is used loadfailed = true; bitmap = new Bitmap(Properties.Resources.Failed); } if (bitmap != null) { width = bitmap.Size.Width; height = bitmap.Size.Height; if (dynamictexture) { if ((width != General.NextPowerOf2(width)) || (height != General.NextPowerOf2(height))) { throw new Exception("Dynamic images must have a size in powers of 2."); } } // Do we still have to set a scale? if ((scale.x == 0.0f) && (scale.y == 0.0f)) { if ((General.Map != null) && (General.Map.Config != null)) { scale.x = General.Map.Config.DefaultTextureScale; scale.y = General.Map.Config.DefaultTextureScale; } else { scale.x = 1.0f; scale.y = 1.0f; } } } // Image is ready imagestate = ImageLoadState.Ready; } }
// This requests loading the image protected virtual void LocalLoadImage() { lock (this) { // Bitmap loaded successfully? if (bitmap != null) { // Bitmap has incorrect format? if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { if (dynamictexture) { throw new Exception("Dynamic images must be in 32 bits ARGB format."); } //General.ErrorLogger.Add(ErrorType.Warning, "Image '" + name + "' does not have A8R8G8B8 pixel format. Conversion was needed."); Bitmap oldbitmap = bitmap; try { // Convert to desired pixel format bitmap = new Bitmap(oldbitmap.Size.Width, oldbitmap.Size.Height, PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bitmap); g.PageUnit = GraphicsUnit.Pixel; g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = PixelOffsetMode.None; g.Clear(Color.Transparent); g.DrawImage(oldbitmap, 0, 0, oldbitmap.Size.Width, oldbitmap.Size.Height); g.Dispose(); oldbitmap.Dispose(); } catch (Exception e) { bitmap = oldbitmap; General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } } // This applies brightness correction on the image if (usecolorcorrection) { BitmapData bmpdata = null; try { // Try locking the bitmap bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } // Bitmap locked? if (bmpdata != null) { // Apply color correction PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); General.Colors.ApplyColorCorrection(pixels, bmpdata.Width * bmpdata.Height); bitmap.UnlockBits(bmpdata); } } } else { // Loading failed // We still mark the image as ready so that it will // not try loading again until Reload Resources is used loadfailed = true; bitmap = new Bitmap(Properties.Resources.Failed); } if (bitmap != null) { width = bitmap.Size.Width; height = bitmap.Size.Height; if (dynamictexture) { if ((width != General.NextPowerOf2(width)) || (height != General.NextPowerOf2(height))) { throw new Exception("Dynamic images must have a size in powers of 2."); } } // Do we still have to set a scale? if ((scale.x == 0.0f) && (scale.y == 0.0f)) { if ((General.Map != null) && (General.Map.Config != null)) { scale.x = General.Map.Config.DefaultTextureScale; scale.y = General.Map.Config.DefaultTextureScale; } else { scale.x = 1.0f; scale.y = 1.0f; } } //mxd. Calculate average color? if (General.Map != null && General.Map.Data != null && General.Map.Data.GlowingFlats != null && General.Map.Data.GlowingFlats.ContainsKey(longname) && General.Map.Data.GlowingFlats[longname].CalculateTextureColor) { BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for glow color calculation. " + e.GetType().Name + ": " + e.Message); } if (bmpdata != null) { PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); int numpixels = bmpdata.Width * bmpdata.Height; uint r = 0; uint g = 0; uint b = 0; for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { r += cp->r; g += cp->g; b += cp->b; // Also check alpha if (cp->a > 0 && cp->a < 255) { istranslucent = true; } else if (cp->a == 0) { ismasked = true; } } // Update glow data int br = (int)(r / numpixels); int bg = (int)(g / numpixels); int bb = (int)(b / numpixels); int max = Math.Max(br, Math.Max(bg, bb)); // Black can't glow... if (max == 0) { General.Map.Data.GlowingFlats.Remove(longname); } else { // That's how it's done in GZDoom (and I may be totally wrong about this) br = Math.Min(255, br * 153 / max); bg = Math.Min(255, bg * 153 / max); bb = Math.Min(255, bb * 153 / max); General.Map.Data.GlowingFlats[longname].Color = new PixelColor(255, (byte)br, (byte)bg, (byte)bb); General.Map.Data.GlowingFlats[longname].CalculateTextureColor = false; if (!General.Map.Data.GlowingFlats[longname].Fullbright) { General.Map.Data.GlowingFlats[longname].Brightness = (br + bg + bb) / 3; } } // Release the data bitmap.UnlockBits(bmpdata); } } //mxd. Check if the texture is translucent else if (!loadfailed) { BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for translucency check. " + e.GetType().Name + ": " + e.Message); } if (bmpdata != null) { PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); int numpixels = bmpdata.Width * bmpdata.Height; for (PixelColor *cp = pixels + numpixels - 1; cp >= pixels; cp--) { // Check alpha if (cp->a > 0 && cp->a < 255) { istranslucent = true; } else if (cp->a == 0) { ismasked = true; } } // Release the data bitmap.UnlockBits(bmpdata); } } } // Image is ready imagestate = ImageLoadState.Ready; } }
// This loads the image protected override void LocalLoadImage() { IImageReader reader; BitmapData bitmapdata = null; MemoryStream mem; PixelColor * pixels = (PixelColor *)0; Stream patchdata; byte[] membytes; // Checks if (this.IsImageLoaded) { return; } if ((width == 0) || (height == 0)) { return; } lock (this) { // Create texture bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor)); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message); loadfailed = true; } if (!loadfailed) { // Go for all patches foreach (TexturePatch p in patches) { // Get the patch data stream patchdata = General.Map.Data.GetPatchData(p.lumpname); if (patchdata != null) { // Copy patch data to memory patchdata.Seek(0, SeekOrigin.Begin); membytes = new byte[(int)patchdata.Length]; patchdata.Read(membytes, 0, (int)patchdata.Length); mem = new MemoryStream(membytes); mem.Seek(0, SeekOrigin.Begin); // Get a reader for the data reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette); if (reader is UnknownImageReader) { // Data is in an unknown format! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?"); loadfailed = true; } else { // Draw the patch mem.Seek(0, SeekOrigin.Begin); try { reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y); } catch (InvalidDataException) { // Data cannot be read! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?"); loadfailed = true; } } // Done mem.Dispose(); } else { // Missing a patch lump! General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'. Did you forget to include required resources?"); loadfailed = true; } } // Done bitmap.UnlockBits(bitmapdata); } // Dispose bitmap if load failed if (loadfailed && (bitmap != null)) { bitmap.Dispose(); bitmap = null; } // Pass on to base base.LocalLoadImage(); } }
// This loads the image protected unsafe override LocalLoadResult LocalLoadImage() { Bitmap bitmap = null; string error = null; int imgoffsetx = 0; int pivotz = 0; // Get the lump data stream string voxellocation = string.Empty; //mxd Stream lumpdata = General.Map.Data.GetVoxelData(voxelname, ref voxellocation); if (lumpdata != null) { // Copy lump data to memory lumpdata.Seek(0, SeekOrigin.Begin); byte[] membytes = new byte[(int)lumpdata.Length]; lumpdata.Read(membytes, 0, (int)lumpdata.Length); using (MemoryStream mem = new MemoryStream(membytes)) { mem.Seek(0, SeekOrigin.Begin); PixelColor[] palette = new PixelColor[256]; // Create front projection image from the KVX using (BinaryReader reader = new BinaryReader(mem, Encoding.ASCII)) { reader.ReadInt32(); //numbytes, we don't use that int xsize = reader.ReadInt32(); int ysize = reader.ReadInt32(); int zsize = reader.ReadInt32(); // Sanity check if (xsize == 0 || ysize == 0 || zsize == 0) { error = "Cannot create sprite image for voxel \"" + Path.Combine(voxellocation, voxelname) + "\" for voxel drawing: voxel has invalid size (width: " + xsize + ", height: " + zsize + ", depth: " + ysize; return(new LocalLoadResult(null, error)); } int pivotx = (int)Math.Round(reader.ReadInt32() / 256f); int pivoty = (int)Math.Round(reader.ReadInt32() / 256f); pivotz = (int)Math.Round(reader.ReadInt32() / 256f); // Read offsets int[] xoffset = new int[xsize + 1]; // why is it xsize + 1, not xsize?.. short[,] xyoffset = new short[xsize, ysize + 1]; // why is it ysize + 1, not ysize?.. for (int i = 0; i < xoffset.Length; i++) { xoffset[i] = reader.ReadInt32(); } for (int x = 0; x < xsize; x++) { for (int y = 0; y < ysize + 1; y++) { xyoffset[x, y] = reader.ReadInt16(); } } // Read slabs List <int> offsets = new List <int>(xsize * ysize); for (int x = 0; x < xsize; x++) { for (int y = 0; y < ysize; y++) { offsets.Add(xoffset[x] + xyoffset[x, y] + 28); // for some reason offsets are counted from start of xoffset[]... } } int counter = 0; int slabsend = (int)(reader.BaseStream.Length - 768); // Read palette if (!overridepalette) { reader.BaseStream.Position = slabsend; for (int i = 0; i < 256; i++) { byte r = (byte)(reader.ReadByte() * 4); byte g = (byte)(reader.ReadByte() * 4); byte b = (byte)(reader.ReadByte() * 4); palette[i] = new PixelColor(255, r, g, b); } } else { for (int i = 0; i < 256; i++) { palette[i] = General.Map.Data.Palette[i]; } } // Populate projection pixels array int imgwidth, imgheight; bool checkalpha = false; // Convert angleoffsets to the nearest cardinal direction... angleoffset = General.ClampAngle((angleoffset + 45) / 90 * 90); switch (angleoffset) { case 0: imgwidth = xsize; imgheight = zsize; imgoffsetx = pivotx; break; case 90: imgwidth = ysize; imgheight = zsize; imgoffsetx = imgwidth - pivoty; checkalpha = true; break; case 180: imgwidth = xsize; imgheight = zsize; imgoffsetx = imgwidth - pivotx; checkalpha = true; break; case 270: imgwidth = ysize; imgheight = zsize; imgoffsetx = pivoty; break; default: throw new InvalidDataException("Invalid AngleOffset"); } int numpixels = imgwidth * imgheight; PixelColor[] pixelsarr = new PixelColor[numpixels]; // Read pixel colors for (int x = 0; x < xsize; x++) { for (int y = 0; y < ysize; y++) { reader.BaseStream.Position = offsets[counter]; int next = (counter < offsets.Count - 1 ? offsets[counter + 1] : slabsend); // Read first color from the slab while (reader.BaseStream.Position < next) { int ztop = reader.ReadByte(); int zleng = reader.ReadByte(); if (ztop + zleng > zsize) { break; } byte flags = reader.ReadByte(); if (zleng > 0) { // Skip slab if no flags are given (otherwise some garbage pixels may be drawn) if (flags == 0) { reader.BaseStream.Position += zleng; continue; } List <int> colorindices = new List <int>(zleng); for (int i = 0; i < zleng; i++) { colorindices.Add(reader.ReadByte()); } int z = ztop; int cstart = 0; while (z < ztop + zleng) { // Get pixel position int pixelpos; switch (angleoffset) { case 0: pixelpos = x + z * xsize; break; case 90: pixelpos = y + z * ysize; break; case 180: pixelpos = xsize - x - 1 + z * xsize; break; case 270: pixelpos = ysize - y - 1 + z * ysize; break; default: throw new InvalidDataException("Invalid AngleOffset"); } // Add to projection pixels array if ((checkalpha && pixelsarr[pixelpos].a == 0) || !checkalpha) { pixelsarr[pixelpos] = palette[colorindices[cstart]]; } // Increment counters cstart++; z++; } } } counter++; } } // Draw to bitmap bitmap = new Bitmap(imgwidth, imgheight, PixelFormat.Format32bppArgb); BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, imgwidth, imgheight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { error = "Cannot lock image for drawing voxel \"" + Path.Combine(voxellocation, voxelname) + "\". " + e.GetType().Name + ": " + e.Message; bitmap = null; } if (bmpdata != null) { // Apply pixels to image PixelColor *pixels = (PixelColor *)bmpdata.Scan0.ToPointer(); int i = 0; for (PixelColor *cp = pixels; cp < pixels + numpixels; cp++, i++) { if (pixelsarr[i].a == 255) { cp->r = pixelsarr[i].r; cp->g = pixelsarr[i].g; cp->b = pixelsarr[i].b; cp->a = 255; } } bitmap.UnlockBits(bmpdata); } } } lumpdata.Dispose(); } else { // Missing voxel lump! error = "Missing voxel lump \"" + voxelname + "\". Forgot to include required resources?"; } return(new LocalLoadResult(bitmap, error, () => { scale.x = 1.0f; scale.y = 1.0f; offsetx = imgoffsetx; offsety = pivotz; })); }
// This loads the image protected override void LocalLoadImage() { // Checks if (this.IsImageLoaded || width == 0 || height == 0) { return; } BitmapData bitmapdata = null; PixelColor *pixels = (PixelColor *)0; lock (this) { // Create texture bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor)); } catch (Exception e) { // Unable to make bitmap General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message); loadfailed = true; } int missingpatches = 0; //mxd if (!loadfailed) { // Go for all patches foreach (TexturePatch p in patches) { // Get the patch data stream string patchlocation = string.Empty; //mxd Stream patchdata = General.Map.Data.GetPatchData(p.LumpName, p.HasLongName, ref patchlocation); if (patchdata != null) { // Copy patch data to memory byte[] membytes = new byte[(int)patchdata.Length]; lock (patchdata) //mxd { patchdata.Seek(0, SeekOrigin.Begin); patchdata.Read(membytes, 0, (int)patchdata.Length); } MemoryStream mem = new MemoryStream(membytes); mem.Seek(0, SeekOrigin.Begin); // Get a reader for the data IImageReader reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette); if (reader is UnknownImageReader) { //mxd. Probably that's a flat?.. if (General.Map.Config.MixTexturesFlats) { reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette); } if (reader is UnknownImageReader) { // Data is in an unknown format! General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.LumpName) + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } } if (!(reader is UnknownImageReader)) { // Draw the patch mem.Seek(0, SeekOrigin.Begin); try { reader.DrawToPixelData(mem, pixels, width, height, p.X, p.Y); } catch (InvalidDataException) { // Data cannot be read! General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.LumpName + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } } // Done mem.Dispose(); } else { // Missing a patch lump! General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.LumpName + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); loadfailed = true; missingpatches++; //mxd } } // Done bitmap.UnlockBits(bitmapdata); } // Dispose bitmap if load failed if ((bitmap != null) && (loadfailed || missingpatches >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded { bitmap.Dispose(); bitmap = null; loadfailed = true; } // Pass on to base base.LocalLoadImage(); } }
// This requests loading the image protected virtual void LocalLoadImage() { BitmapData bmpdata = null; lock (this) { // Bitmap loaded successfully? if (bitmap != null) { // Bitmap has incorrect format? if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { // villsa if (General.Map.FormatInterface.InDoom64Mode) { ColorPalette ncp = bitmap.Palette; foreach (TextureIndexInfo tp in General.Map.Config.ThingPalettes) { // sprite contains alternate palette? if (General.Map.Data.ThingPalette.ContainsKey(tp.Title) && tp.Index == palindex) { Playpal pal = General.Map.Data.ThingPalette[tp.Title]; for (int i = 0; i < 255; i++) { // copy alternate palette over ncp.Entries[i] = pal[i].ToColor(); } } } } //General.ErrorLogger.Add(ErrorType.Warning, "Image '" + name + "' does not have A8R8G8B8 pixel format. Conversion was needed."); Bitmap oldbitmap = bitmap; try { // Convert to desired pixel format bitmap = new Bitmap(oldbitmap.Size.Width, oldbitmap.Size.Height, PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(bitmap); g.PageUnit = GraphicsUnit.Pixel; g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = PixelOffsetMode.None; g.Clear(Color.Transparent); g.DrawImage(oldbitmap, 0, 0, oldbitmap.Size.Width, oldbitmap.Size.Height); g.Dispose(); oldbitmap.Dispose(); } catch (Exception e) { bitmap = oldbitmap; General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } } // This applies brightness correction on the image if (usecolorcorrection) { try { // Try locking the bitmap bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } catch (Exception e) { General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } // Bitmap locked? if (bmpdata != null) { // Apply color correction PixelColor *pixels = (PixelColor *)(bmpdata.Scan0.ToPointer()); General.Colors.ApplColorCorrection(pixels, bmpdata.Width * bmpdata.Height); bitmap.UnlockBits(bmpdata); } } } else { // Loading failed // We still mark the image as ready so that it will // not try loading again until Reload Resources is used loadfailed = true; bitmap = new Bitmap(Properties.Resources.Failed); } if (bitmap != null) { width = bitmap.Size.Width; height = bitmap.Size.Height; // Do we still have to set a scale? if ((scale.x == 0.0f) && (scale.y == 0.0f)) { if ((General.Map != null) && (General.Map.Config != null)) { scale.x = General.Map.Config.DefaultTextureScale; scale.y = General.Map.Config.DefaultTextureScale; } else { scale.x = 1.0f; scale.y = 1.0f; } } } // Image is ready imagestate = ImageLoadState.Ready; } }
// This loads the image protected override LocalLoadResult LocalLoadImage() { // Checks if (width == 0 || height == 0) { return(new LocalLoadResult(null)); } BitmapData bitmapdata = null; PixelColor *pixels = (PixelColor *)0; Bitmap bitmap = null; List <LogMessage> messages = new List <LogMessage>(); // Create texture bitmap try { if (bitmap != null) { bitmap.Dispose(); } bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); pixels = (PixelColor *)bitmapdata.Scan0.ToPointer(); General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor)); } catch (Exception e) { // Unable to make bitmap messages.Add(new LogMessage(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message)); } int missingpatches = 0; //mxd if (!messages.Any(x => x.Type == ErrorType.Error)) { // Go for all patches foreach (TexturePatch p in patches) { // Get the patch data stream string patchlocation = string.Empty; //mxd Stream patchdata = General.Map.Data.GetPatchData(p.LumpName, p.HasLongName, ref patchlocation); if (patchdata != null) { // Get a reader for the data Bitmap patchbmp = ImageDataFormat.TryLoadImage(patchdata, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette); if (patchbmp == null) { //mxd. Probably that's a flat?.. if (General.Map.Config.MixTexturesFlats) { patchbmp = ImageDataFormat.TryLoadImage(patchdata, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette); } if (patchbmp == null) { // Data is in an unknown format! messages.Add(new LogMessage(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.LumpName) + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?")); missingpatches++; //mxd } } if (patchbmp != null) { // Draw the patch DrawToPixelData(patchbmp, pixels, width, height, p.X, p.Y); patchbmp.Dispose(); } // Done patchdata.Dispose(); } else { // Missing a patch lump! messages.Add(new LogMessage(ErrorType.Error, "Missing patch lump \"" + p.LumpName + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?")); missingpatches++; //mxd } } // Done bitmap.UnlockBits(bitmapdata); } // Dispose bitmap if load failed if ((bitmap != null) && (messages.Any(x => x.Type == ErrorType.Error) || missingpatches >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded { bitmap.Dispose(); bitmap = null; } return(new LocalLoadResult(bitmap, messages)); }