mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 14:31:50 +00:00
Some more work done on TEXTURES support
This commit is contained in:
parent
ab74b041c5
commit
2047756694
9 changed files with 374 additions and 51 deletions
|
@ -663,6 +663,7 @@
|
|||
<None Include="Resources\Close.png" />
|
||||
<Compile Include="Config\AllTexturesSet.cs" />
|
||||
<Compile Include="Config\FlagTranslation.cs" />
|
||||
<Compile Include="Data\HighResImage.cs" />
|
||||
<Compile Include="Data\PK3FileImage.cs" />
|
||||
<Compile Include="Data\PK3StructuredReader.cs" />
|
||||
<Compile Include="ZDoom\ActorStructure.cs" />
|
||||
|
|
202
Source/Data/HighResImage.cs
Normal file
202
Source/Data/HighResImage.cs
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
||||
* This program is released under GNU General Public License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.Data
|
||||
{
|
||||
internal sealed unsafe class HighResImage : ImageData
|
||||
{
|
||||
#region ================== Variables
|
||||
|
||||
private List<TexturePatch> patches;
|
||||
private float scalex;
|
||||
private float scaley;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Disposer
|
||||
|
||||
// Constructor
|
||||
public HighResImage(string name, int width, int height, float scalex, float scaley)
|
||||
{
|
||||
// Initialize
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scalex = scalex;
|
||||
this.scaley = scaley;
|
||||
this.scaledwidth = (float)width * scalex;
|
||||
this.scaledheight = (float)height * scaley;
|
||||
this.patches = new List<TexturePatch>();
|
||||
SetName(name);
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This adds a patch to the texture
|
||||
public void AddPatch(TexturePatch patch)
|
||||
{
|
||||
// Add it
|
||||
patches.Add(patch);
|
||||
}
|
||||
|
||||
// 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.WriteLogLine("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.WriteLogLine("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.WriteLogLine("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.WriteLogLine("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.WriteLogLine("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();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -158,7 +158,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// This loads the textures
|
||||
public override ICollection<ImageData> LoadTextures(PatchNames pnames)
|
||||
{
|
||||
List<ImageData> images = new List<ImageData>();
|
||||
Dictionary<long, ImageData> images = new Dictionary<long, ImageData>();
|
||||
ICollection<ImageData> collection;
|
||||
List<ImageData> imgset = new List<ImageData>();
|
||||
|
||||
|
@ -184,19 +184,6 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// Add images from texture directory
|
||||
collection = LoadDirectoryImages(TEXTURES_DIR, false, true);
|
||||
AddImagesToList(images, collection);
|
||||
|
||||
// Load TEXTURES lump file
|
||||
imgset.Clear();
|
||||
string texturesfile = FindFirstFile("TEXTURES", false);
|
||||
if((texturesfile != null) && FileExists(texturesfile))
|
||||
{
|
||||
MemoryStream filedata = LoadFile(texturesfile);
|
||||
WADReader.LoadHighresTextures(filedata, texturesfile, ref imgset);
|
||||
filedata.Dispose();
|
||||
}
|
||||
|
||||
// Add images from TEXTURES lump files
|
||||
AddImagesToList(images, imgset);
|
||||
|
||||
// Load TEXTURE1 lump file
|
||||
imgset.Clear();
|
||||
|
@ -220,7 +207,20 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// Add images from TEXTURE1 and TEXTURE2 lump files
|
||||
AddImagesToList(images, imgset);
|
||||
|
||||
return images;
|
||||
// Load TEXTURES lump file
|
||||
imgset.Clear();
|
||||
string texturesfile = FindFirstFile("TEXTURES", false);
|
||||
if((texturesfile != null) && FileExists(texturesfile))
|
||||
{
|
||||
MemoryStream filedata = LoadFile(texturesfile);
|
||||
WADReader.LoadHighresTextures(filedata, texturesfile, ref imgset, images, null);
|
||||
filedata.Dispose();
|
||||
}
|
||||
|
||||
// Add images from TEXTURES lump file
|
||||
AddImagesToList(images, imgset);
|
||||
|
||||
return new List<ImageData>(images.Values);
|
||||
}
|
||||
|
||||
// This returns the patch names from the PNAMES lump
|
||||
|
@ -260,7 +260,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// This loads the textures
|
||||
public override ICollection<ImageData> LoadFlats()
|
||||
{
|
||||
List<ImageData> images = new List<ImageData>();
|
||||
Dictionary<long, ImageData> images = new Dictionary<long, ImageData>();
|
||||
ICollection<ImageData> collection;
|
||||
|
||||
// Error when suspended
|
||||
|
@ -284,8 +284,8 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// Add images from flats directory
|
||||
collection = LoadDirectoryImages(FLATS_DIR, true, true);
|
||||
AddImagesToList(images, collection);
|
||||
|
||||
return images;
|
||||
|
||||
return new List<ImageData>(images.Values);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -346,24 +346,14 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
// This copies images from a collection unless they already exist in the list
|
||||
private void AddImagesToList(List<ImageData> targetlist, ICollection<ImageData> sourcelist)
|
||||
private void AddImagesToList(Dictionary<long, ImageData> targetlist, ICollection<ImageData> sourcelist)
|
||||
{
|
||||
// Go for all source images
|
||||
foreach(ImageData src in sourcelist)
|
||||
{
|
||||
// Check if exists in target list
|
||||
bool alreadyexists = false;
|
||||
foreach(ImageData tgt in targetlist)
|
||||
{
|
||||
if(tgt.LongName == src.LongName)
|
||||
{
|
||||
alreadyexists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add source image to target list
|
||||
if(!alreadyexists) targetlist.Add(src);
|
||||
if(!targetlist.ContainsKey(src.LongName))
|
||||
targetlist.Add(src.LongName, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,6 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// This loads the image
|
||||
protected override void LocalLoadImage()
|
||||
{
|
||||
uint datalength = (uint)(width * height * sizeof(PixelColor));
|
||||
IImageReader reader;
|
||||
BitmapData bitmapdata = null;
|
||||
MemoryStream mem;
|
||||
|
|
|
@ -25,24 +25,63 @@ using System.Drawing;
|
|||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.Data
|
||||
{
|
||||
internal enum TexturePathRenderStyle
|
||||
{
|
||||
Copy,
|
||||
Blend,
|
||||
Add,
|
||||
Subtract,
|
||||
ReverseSubtract,
|
||||
Modulate,
|
||||
CopyAlpha
|
||||
}
|
||||
|
||||
internal struct TexturePatch
|
||||
{
|
||||
public string lumpname;
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
// Constructor
|
||||
public bool flipx;
|
||||
public bool flipy;
|
||||
public int rotate;
|
||||
public PixelColor blend;
|
||||
public float alpha;
|
||||
public TexturePathRenderStyle style;
|
||||
|
||||
// Constructor for simple patches
|
||||
public TexturePatch(string lumpname, int x, int y)
|
||||
{
|
||||
// Initialize
|
||||
this.lumpname = lumpname;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.flipx = false;
|
||||
this.flipy = false;
|
||||
this.rotate = 0;
|
||||
this.blend = new PixelColor(0, 0, 0, 0);
|
||||
this.alpha = 1.0f;
|
||||
this.style = TexturePathRenderStyle.Copy;
|
||||
}
|
||||
|
||||
// Constructor for hires patches
|
||||
public TexturePatch(string lumpname, int x, int y, bool flipx, bool flipy, int rotate, PixelColor blend, float alpha, int style)
|
||||
{
|
||||
// Initialize
|
||||
this.lumpname = lumpname;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.flipx = flipx;
|
||||
this.flipy = flipy;
|
||||
this.rotate = rotate;
|
||||
this.blend = blend;
|
||||
this.alpha = alpha;
|
||||
this.style = (TexturePathRenderStyle)style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ using System.Drawing.Imaging;
|
|||
using System.IO;
|
||||
using CodeImp.DoomBuilder.IO;
|
||||
using CodeImp.DoomBuilder.ZDoom;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -213,6 +214,15 @@ namespace CodeImp.DoomBuilder.Data
|
|||
LoadTexturesRange(range.start, range.end, ref images, pnames);
|
||||
}
|
||||
|
||||
// Load TEXTURES lump file
|
||||
lump = file.FindLump("TEXTURES");
|
||||
if(lump != null)
|
||||
{
|
||||
MemoryStream filedata = new MemoryStream(lump.Stream.ReadAllBytes());
|
||||
WADReader.LoadHighresTextures(filedata, "TEXTURES", ref images, null, null);
|
||||
filedata.Dispose();
|
||||
}
|
||||
|
||||
// Return result
|
||||
return images;
|
||||
}
|
||||
|
@ -239,31 +249,18 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
// This loads the texture definitions from a TEXTURES lump
|
||||
public static void LoadHighresTextures(Stream stream, string filename, ref List<ImageData> images)
|
||||
public static void LoadHighresTextures(Stream stream, string filename, ref List<ImageData> images, Dictionary<long, ImageData> textures, Dictionary<long, ImageData> flats)
|
||||
{
|
||||
// Parse the data
|
||||
TexturesParser parser = new TexturesParser();
|
||||
parser.Parse(stream, filename);
|
||||
|
||||
// Determine default scale
|
||||
float defaultscale = General.Map.Config.DefaultTextureScale;
|
||||
|
||||
// Make the textures
|
||||
foreach(TextureStructure t in parser.Textures)
|
||||
{
|
||||
float scalex, scaley;
|
||||
if(t.XScale == 0.0f) scalex = defaultscale; else scalex = 1f / t.XScale;
|
||||
if(t.YScale == 0.0f) scaley = defaultscale; else scaley = 1f / t.YScale;
|
||||
TextureImage image = new TextureImage(t.Name.ToUpperInvariant(), t.Width, t.Height, scalex, scaley);
|
||||
|
||||
// Add patches
|
||||
foreach(PatchStructure p in t.Patches)
|
||||
{
|
||||
image.AddPatch(new TexturePatch(p.Name.ToUpperInvariant(), p.OffsetX, p.OffsetY));
|
||||
}
|
||||
|
||||
// Add the texture
|
||||
images.Add(image);
|
||||
ImageData img = t.MakeImage(textures, flats);
|
||||
images.Add(img);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const float BYTE_TO_FLOAT = 0.00392156862745098f;
|
||||
public const float BYTE_TO_FLOAT = 0.00392156862745098f;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
private int offsety;
|
||||
private bool flipx;
|
||||
private bool flipy;
|
||||
private float alpha;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -55,6 +56,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
public int OffsetY { get { return offsety; } }
|
||||
public bool FlipX { get { return flipx; } }
|
||||
public bool FlipY { get { return flipy; } }
|
||||
public float Alpha { get { return alpha; } }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -66,6 +68,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
string tokenstr;
|
||||
|
||||
// Initialize
|
||||
alpha = 1.0f;
|
||||
|
||||
// There should be 3 tokens separated by 2 commas now:
|
||||
// Name, Width, Height
|
||||
|
@ -137,6 +140,11 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
{
|
||||
flipy = true;
|
||||
}
|
||||
else if(token == "alpha")
|
||||
{
|
||||
if(!ReadTokenFloat(parser, token, out alpha)) return;
|
||||
alpha = General.Clamp(alpha, 0.0f, 1.0f);
|
||||
}
|
||||
else if(token == "}")
|
||||
{
|
||||
// Patch scope ends here,
|
||||
|
@ -147,5 +155,67 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This reads the next token and sets a floating point value, returns false when failed
|
||||
private bool ReadTokenFloat(TexturesParser parser, string propertyname, out float value)
|
||||
{
|
||||
// Next token is the property value to set
|
||||
parser.SkipWhitespace(true);
|
||||
string strvalue = parser.ReadToken();
|
||||
if(!string.IsNullOrEmpty(strvalue))
|
||||
{
|
||||
// Try parsing as value
|
||||
if(!float.TryParse(strvalue, out value))
|
||||
{
|
||||
parser.ReportError("Expected numeric value for property '" + propertyname + "'");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't find the property value!
|
||||
parser.ReportError("Expected a value for property '" + propertyname + "'");
|
||||
value = 0.0f;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This reads the next token and sets an integral value, returns false when failed
|
||||
private bool ReadTokenInt(TexturesParser parser, string propertyname, out int value)
|
||||
{
|
||||
// Next token is the property value to set
|
||||
parser.SkipWhitespace(true);
|
||||
string strvalue = parser.ReadToken();
|
||||
if(!string.IsNullOrEmpty(strvalue))
|
||||
{
|
||||
// Try parsing as value
|
||||
if(!int.TryParse(strvalue, out value))
|
||||
{
|
||||
parser.ReportError("Expected integral value for property '" + propertyname + "'");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't find the property value!
|
||||
parser.ReportError("Expected a value for property '" + propertyname + "'");
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ using CodeImp.DoomBuilder.Data;
|
|||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using CodeImp.DoomBuilder.Compilers;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -253,6 +254,30 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
}
|
||||
}
|
||||
|
||||
// This makes a HighResImage texture for this texture
|
||||
internal HighResImage MakeImage(Dictionary<long, ImageData> textures, Dictionary<long, ImageData> flats)
|
||||
{
|
||||
float scalex, scaley;
|
||||
|
||||
// Determine default scale
|
||||
float defaultscale = General.Map.Config.DefaultTextureScale;
|
||||
|
||||
// Determine scale for texture
|
||||
if(xscale == 0.0f) scalex = defaultscale; else scalex = 1f / xscale;
|
||||
if(yscale == 0.0f) scaley = defaultscale; else scaley = 1f / yscale;
|
||||
|
||||
// Make texture
|
||||
HighResImage tex = new HighResImage(name, width, height, scalex, scaley);
|
||||
|
||||
// Add patches
|
||||
foreach(PatchStructure p in patches)
|
||||
{
|
||||
tex.AddPatch(new TexturePatch(p.Name.ToUpperInvariant(), p.OffsetX, p.OffsetY, p.FlipX, p.FlipY, 0, new PixelColor(0, 0, 0, 0), p.Alpha, 0));
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue