mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-31 21:00:56 +00:00
Vertical patch offsets for masked patches are now handled correctly based on the game configuration
This commit is contained in:
parent
5191e9822a
commit
ea15732e8d
4 changed files with 64 additions and 12 deletions
|
@ -98,6 +98,7 @@ common
|
||||||
compatibility
|
compatibility
|
||||||
{
|
{
|
||||||
fixnegativepatchoffsets = true;
|
fixnegativepatchoffsets = true;
|
||||||
|
fixmaskedpatchoffsets = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ common
|
||||||
compatibility
|
compatibility
|
||||||
{
|
{
|
||||||
fixnegativepatchoffsets = true;
|
fixnegativepatchoffsets = true;
|
||||||
|
fixmaskedpatchoffsets = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,13 @@ namespace CodeImp.DoomBuilder.Config
|
||||||
{
|
{
|
||||||
public struct CompatibilityOptions
|
public struct CompatibilityOptions
|
||||||
{
|
{
|
||||||
public readonly bool FixNegativePatchOffsets;
|
public bool FixNegativePatchOffsets;
|
||||||
|
public bool FixMaskedPatchOffsets;
|
||||||
|
|
||||||
public CompatibilityOptions(Configuration cfg)
|
public CompatibilityOptions(Configuration cfg)
|
||||||
{
|
{
|
||||||
FixNegativePatchOffsets = cfg.ReadSetting("compatibility.fixnegativepatchoffsets", false);
|
FixNegativePatchOffsets = cfg.ReadSetting("compatibility.fixnegativepatchoffsets", false);
|
||||||
|
FixMaskedPatchOffsets = cfg.ReadSetting("compatibility.fixmaskedpatchoffsets", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#region ================== Namespaces
|
#region ================== Namespaces
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
@ -80,10 +81,12 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = null;
|
||||||
List<LogMessage> messages = new List<LogMessage>();
|
List<LogMessage> messages = new List<LogMessage>();
|
||||||
int[] columnumpatches = new int[width];
|
int[] columnumpatches = new int[width];
|
||||||
|
BitArray columnmasked = new BitArray(width, false);
|
||||||
bool hasnegativeoffsetpatch = false;
|
bool hasnegativeoffsetpatch = false;
|
||||||
Dictionary<TexturePatch, Bitmap> patchbmps = new Dictionary<TexturePatch, Bitmap>();
|
Dictionary<TexturePatch, Bitmap> patchbmps = new Dictionary<TexturePatch, Bitmap>();
|
||||||
|
|
||||||
bool fixnegativeoffsets = General.Map.Config.Compatibility.FixNegativePatchOffsets;
|
bool fixnegativeoffsets = General.Map.Config.Compatibility.FixNegativePatchOffsets;
|
||||||
|
bool fixmaskedoffsets = General.Map.Config.Compatibility.FixMaskedPatchOffsets;
|
||||||
|
|
||||||
// Create texture bitmap
|
// Create texture bitmap
|
||||||
try
|
try
|
||||||
|
@ -150,18 +153,26 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
// There's a bug in vanilla Doom where negative patch offsets are ignored (the patch y offset is set to 0). If
|
// There's a bug in vanilla Doom where negative patch offsets are ignored (the patch y offset is set to 0). If
|
||||||
// the configuration is for an engine that doesn't fix the bug we have to emulate that behavior
|
// the configuration is for an engine that doesn't fix the bug we have to emulate that behavior
|
||||||
// See https://doomwiki.org/wiki/Vertical_offsets_are_ignored_in_texture_patches
|
// See https://doomwiki.org/wiki/Vertical_offsets_are_ignored_in_texture_patches
|
||||||
if (!fixnegativeoffsets && hasnegativeoffsetpatch)
|
if (!fixnegativeoffsets || !fixmaskedoffsets)
|
||||||
{
|
{
|
||||||
// Check which columns have more than one patch
|
// Check which columns have more than one patch
|
||||||
foreach(TexturePatch p in patches)
|
foreach(TexturePatch p in patches)
|
||||||
{
|
{
|
||||||
if (patchbmps[p] == null) continue;
|
if (patchbmps[p] == null) continue;
|
||||||
|
|
||||||
|
bool ismaked = BitmapIsMasked(patchbmps[p]);
|
||||||
|
|
||||||
for (int x = 0; x < patchbmps[p].Width; x++)
|
for (int x = 0; x < patchbmps[p].Width; x++)
|
||||||
{
|
{
|
||||||
int ox = p.X + x;
|
int ox = p.X + x;
|
||||||
if (ox >= 0 && ox < columnumpatches.Length)
|
if (ox >= 0 && ox < columnumpatches.Length)
|
||||||
|
{
|
||||||
|
if(!fixnegativeoffsets)
|
||||||
columnumpatches[ox]++;
|
columnumpatches[ox]++;
|
||||||
|
|
||||||
|
if (!fixmaskedoffsets && ismaked)
|
||||||
|
columnmasked[ox] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +183,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
if(patchbmps.ContainsKey(p) && patchbmps[p] != null)
|
if(patchbmps.ContainsKey(p) && patchbmps[p] != null)
|
||||||
{
|
{
|
||||||
// Draw the patch
|
// Draw the patch
|
||||||
DrawToPixelData(patchbmps[p], pixels, width, height, p.X, p.Y, fixnegativeoffsets, columnumpatches);
|
DrawToPixelData(patchbmps[p], pixels, width, height, p.X, p.Y, fixnegativeoffsets, fixmaskedoffsets, columnumpatches, columnmasked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +206,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
// This draws the picture to the given pixel color data
|
// This draws the picture to the given pixel color data
|
||||||
static unsafe void DrawToPixelData(Bitmap bmp, PixelColor* target, int targetwidth, int targetheight, int x, int y, bool fixnegativeoffsets, int[] columnumpatches)
|
static unsafe void DrawToPixelData(Bitmap bmp, PixelColor* target, int targetwidth, int targetheight, int x, int y, bool fixnegativeoffsets, bool fixmaskedoffsets, int[] columnumpatches, BitArray columnmasked)
|
||||||
{
|
{
|
||||||
// Get bitmap
|
// Get bitmap
|
||||||
int width = bmp.Size.Width;
|
int width = bmp.Size.Width;
|
||||||
|
@ -206,10 +217,6 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||||
PixelColor* pixels = (PixelColor*)bmpdata.Scan0.ToPointer();
|
PixelColor* pixels = (PixelColor*)bmpdata.Scan0.ToPointer();
|
||||||
|
|
||||||
// Negative vertical offsets not allowed?
|
|
||||||
if (y < 0 && !fixnegativeoffsets)
|
|
||||||
y = 0;
|
|
||||||
|
|
||||||
// Go for all pixels in the original image
|
// Go for all pixels in the original image
|
||||||
for (int ox = 0; ox < width; ox++)
|
for (int ox = 0; ox < width; ox++)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +226,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
// If we have to emulate the negative vertical offset bug we also have to recalculate the height of the
|
// If we have to emulate the negative vertical offset bug we also have to recalculate the height of the
|
||||||
// patch that is actually drawn, since it'll only draw as many pixels as it'd draw as if the negative
|
// patch that is actually drawn, since it'll only draw as many pixels as it'd draw as if the negative
|
||||||
// vertical offset was taken into account
|
// vertical offset was taken into account
|
||||||
if (patchy < 0 && !fixnegativeoffsets && tx < width && tx >= 0 && tx < columnumpatches.Length && columnumpatches[tx] > 1)
|
if ((patchy < 0 && !fixnegativeoffsets && tx < width && tx >= 0 && tx < columnumpatches.Length && columnumpatches[tx] > 1) && !(!fixmaskedoffsets && tx >= 0 && tx < columnmasked.Length && columnmasked[tx] == true))
|
||||||
drawheight = height + patchy;
|
drawheight = height + patchy;
|
||||||
|
|
||||||
for (int oy = 0; oy < drawheight; oy++)
|
for (int oy = 0; oy < drawheight; oy++)
|
||||||
|
@ -227,8 +234,18 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
// Copy this pixel?
|
// Copy this pixel?
|
||||||
if (pixels[oy * width + ox].a > 0.5f)
|
if (pixels[oy * width + ox].a > 0.5f)
|
||||||
{
|
{
|
||||||
|
int realy = y;
|
||||||
|
|
||||||
|
if (!fixmaskedoffsets && tx >= 0 && tx < columnmasked.Length && columnmasked[tx] == true)
|
||||||
|
{
|
||||||
|
if (tx >= 0 && tx < columnumpatches.Length && columnumpatches[tx] == 1)
|
||||||
|
realy = 0;
|
||||||
|
}
|
||||||
|
else if (y < 0 && !fixnegativeoffsets)
|
||||||
|
realy = 0;
|
||||||
|
|
||||||
// Calculate target pixel and copy when within bounds
|
// Calculate target pixel and copy when within bounds
|
||||||
int ty = y + oy;
|
int ty = realy + oy;
|
||||||
if ((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight))
|
if ((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight))
|
||||||
target[ty * targetwidth + tx] = pixels[oy * width + ox];
|
target[ty * targetwidth + tx] = pixels[oy * width + ox];
|
||||||
}
|
}
|
||||||
|
@ -239,6 +256,37 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
bmp.UnlockBits(bmpdata);
|
bmp.UnlockBits(bmpdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the given bitmap has masked pixels
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bmp">Bitmap to check</param>
|
||||||
|
/// <returns>true if masked, false if not masked</returns>
|
||||||
|
internal static unsafe bool BitmapIsMasked(Bitmap bmp)
|
||||||
|
{
|
||||||
|
// Get bitmap
|
||||||
|
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();
|
||||||
|
|
||||||
|
for (int ox = 0; ox < width; ox++)
|
||||||
|
{
|
||||||
|
for (int oy = 0; oy < height; oy++)
|
||||||
|
{
|
||||||
|
if (pixels[oy * width + ox].a <= 0.5f)
|
||||||
|
{
|
||||||
|
bmp.UnlockBits(bmpdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bmp.UnlockBits(bmpdata);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue