Skip to content
This repository has been archived by the owner on Sep 16, 2019. It is now read-only.

Better WAD2 implementation #224

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Sledge.DataStructures/GameData/Palette.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Sledge.DataStructures.GameData
{
public class Palette
{
public byte[] ByteArray { get; private set; }

public Palette(byte[] pal)
{
ByteArray = pal;
}
}
}
1 change: 1 addition & 0 deletions Sledge.DataStructures/Sledge.DataStructures.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<ItemGroup>
<Compile Include="GameData\AutoVisgroup.cs" />
<Compile Include="GameData\AutoVisgroupSection.cs" />
<Compile Include="GameData\Palette.cs" />
<Compile Include="Geometric\Box.cs" />
<Compile Include="Geometric\Cloud.cs" />
<Compile Include="Geometric\CoordinateF.cs" />
Expand Down
21 changes: 20 additions & 1 deletion Sledge.Editor/Documents/Document.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class Document
public Game Game { get; set; }
public GameEnvironment Environment { get; private set; }
public GameData GameData { get; set; }
public Palette Palette { get; set; }

public Pointfile Pointfile { get; set; }

Expand Down Expand Up @@ -107,7 +108,25 @@ public Document(string mapFile, Map map, Game game)
GameData.MapSizeHigh = game.OverrideMapSizeHigh;
}

TextureCollection = TextureProvider.CreateCollection(Environment.GetGameDirectories(), Game.AdditionalPackages, Game.GetTextureBlacklist(), Game.GetTextureWhitelist());
// Set up Quake 1/Hexen 2 palette
var palpath = Environment.Root.TraversePath("gfx/palette.lmp");
var paldata = new byte[768];
if (palpath != null)
{
try
{
using (var br = new BinaryReader(palpath.Open()))
{
paldata = br.ReadBytes(768);
}
}
catch (Exception)
{
}
}
Palette = new Palette(paldata);

TextureCollection = TextureProvider.CreateCollection(Environment.GetGameDirectories(), Game.AdditionalPackages, Game.GetTextureBlacklist(), Game.GetTextureWhitelist(), Palette);
/* .Union(GameData.MaterialExclusions) */ // todo material exclusions

var texList = Map.GetAllTextures();
Expand Down
2 changes: 1 addition & 1 deletion Sledge.Editor/Extensions/ModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private static bool UpdateModels(Document document, MapObject mo, Dictionary<str

try
{
var mr = ModelProvider.CreateModelReference(file);
var mr = ModelProvider.CreateModelReference(file, document.Palette);
SetModel(e, mr);
cache.Add(model, mr);
return true;
Expand Down
7 changes: 6 additions & 1 deletion Sledge.Packages/Sledge.Packages.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@
<Compile Include="Wad\WadPackage.cs" />
<Compile Include="Wad\WadPackageStreamSource.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\Sledge.DataStructures\Sledge.DataStructures.csproj">
<Project>{26a974c9-e495-4fa3-8e87-1e00019d04f5}</Project>
<Name>Sledge.DataStructures</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
2 changes: 1 addition & 1 deletion Sledge.Packages/Wad/WadEntryType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public enum WadEntryType : byte
// ColorMap = 0x41,
Image = 0x42, // Simple image with any size
Texture = 0x43, // Power-of-16-sized world textures with 4 mipmaps
// Raw = 0x44,
QuakeTexture = 0x44, // Same as Texture but without the palette following the mipmaps
// ColorMap2 = 0x45,
// Font = 0x46, // Fixed-height font. Contains an image and font data (row, X offset and width of a character) for 256 ASCII characters.
}
Expand Down
13 changes: 11 additions & 2 deletions Sledge.Packages/Wad/WadImageStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,17 @@ private void PrepareData(BinaryReader br)
bw.Write(_entry.PaletteSize); // Colours used
bw.Write(_entry.PaletteSize); // "Important" colours used

br.BaseStream.Position = startIndex + (_entry.PaletteDataOffset - _entry.Offset);
var paletteData = br.ReadBytes((int)(_entry.PaletteSize * 3));
byte[] paletteData;
if (_entry.Type == WadEntryType.QuakeTexture)
{
paletteData = _entry.Package.Palette.ByteArray;
}
else
{
br.BaseStream.Position = startIndex + (_entry.PaletteDataOffset - _entry.Offset);
paletteData = br.ReadBytes((int)(_entry.PaletteSize * 3));
}

for (var i = 0; i < _entry.PaletteSize; i++)
{
// Wad palettes are RGB, bitmap is BGRX
Expand Down
25 changes: 19 additions & 6 deletions Sledge.Packages/Wad/WadPackage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Sledge.DataStructures.GameData;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -11,23 +12,26 @@ namespace Sledge.Packages.Wad
// https://developer.valvesoftware.com/wiki/WAD
public class WadPackage : IPackage
{
private const string Signature = "WAD3";
private const string WAD2Signature = "WAD2";
private const string WAD3Signature = "WAD3";

public FileInfo PackageFile { get; private set; }
internal uint NumTextures { get; private set; }
internal uint LumpOffset { get; private set; }
internal List<WadEntry> Entries { get; private set; }
public Palette Palette { get; private set; }

public WadPackage(FileInfo packageFile)
public WadPackage(FileInfo packageFile, Palette pal)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the palette being passed into all the package loaders when only the WAD provider needs it. I think it'd probably be better to cache the palette data inside the package by searching from the root like this:

if (sig == WAD2Signature) {
    var palette = packageFile.TraversePath("/gfx/palette.lmp");
    // Load palette byte data
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that passing the Palette everywhere is messy. The problem with just using packageFile is, AFAIK, it's not necessarily inside the game directory - you could add a WAD file from a random location on your hard drive, but the palette always resides in the game directory. To work around that, I think the IFile for the game root directory would also need to be passed to the WadPackage constructor like:

public WadPackage(FileInfo packageFile, IFile gameRoot)

then I could do this:

if (sig == WAD2Signature) {
    var palette = gameRoot.TraversePath("/gfx/palette.lmp");
    // Load palette byte data
}

However, the problem with that is I can't use IFile or TraversePath inside the WadPackage implementation because it creates a circular dependency between Sledge.Filesystem and Sledge.Packages.
Maybe that could be worked around by merging the FileSystem and Packages assemblies, but that seems like a heavy handed workaround.

{
PackageFile = packageFile;
Entries = new List<WadEntry>();
Palette = pal;

// Read the data from the wad
using (var br = new BinaryReader(OpenFile(packageFile)))
{
var sig = br.ReadFixedLengthString(Encoding.ASCII, 4);
if (sig != Signature) throw new PackageException("Unknown package signature: Expected '" + Signature + "', got '" + sig + "'.");
if (sig != WAD2Signature && sig != WAD3Signature) throw new PackageException("Unknown package signature: Expected [WAD2,WAD3], got '" + sig + "'.");

NumTextures = br.ReadUInt32();
LumpOffset = br.ReadUInt32();
Expand Down Expand Up @@ -129,15 +133,24 @@ private void SetEntryData(WadEntry e, BinaryReader br)
paletteDataOffset = br.BaseStream.Position;
break;
case WadEntryType.Texture:
case WadEntryType.QuakeTexture:
br.BaseStream.Position += 16; // Skip name
width = br.ReadUInt32();
height = br.ReadUInt32();
textureDataOffset = br.BaseStream.Position + 16;
var num = (int)(width * height);
var skipMapData = (num / 4) + (num / 16) + (num / 64);
br.BaseStream.Position += 16 + num + skipMapData; // Skip mipmap offsets, texture data, mipmap texture data
paletteSize = br.ReadUInt16();
paletteDataOffset = br.BaseStream.Position;
if (e.Type == WadEntryType.QuakeTexture)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd probably be cleaner to branch in the switch instead of here, maybe something like this?

case WadEntryType.Texture:
    textureDataOffset = MoveToTextureData(br, out width, out height);
    paletteSize = br.ReadUInt16();
    paletteDataOffset = br.BaseStream.Position;
    break;
case WadEntryType.QuakeTexture:
    textureDataOffset = MoveToTextureData(br, out width, out height);
    paletteSize = 256;
    paletteDataOffset = 0;
    break;

...

private long MoveToTextureData(BinaryReader br, out uint width, out uint height)
{
    br.BaseStream.Position += 16; // Skip name
    width = br.ReadUInt32();
    height = br.ReadUInt32();
    var textureDataOffset = br.BaseStream.Position + 16;
    var num = (int)(width * height);
    var skipMapData = (num / 4) + (num / 16) + (num / 64);
    br.BaseStream.Position += 16 + num + skipMapData; // Skip mipmap offsets, texture data, mipmap texture data
    return textureDataOffset;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I refactored it like that.

{
paletteSize = 256;
paletteDataOffset = 0;
}
else
{
paletteSize = br.ReadUInt16();
paletteDataOffset = br.BaseStream.Position;
}
break;
/*
case WadEntryType.Font:
Expand Down
10 changes: 5 additions & 5 deletions Sledge.Providers/Model/MdlProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ protected override bool IsValidForFile(IFile file)
return file.Extension.ToLowerInvariant() == "mdl";
}

protected override DataStructures.Models.Model LoadFromFile(IFile file)
protected override DataStructures.Models.Model LoadFromFile(IFile file, DataStructures.GameData.Palette pal)
{
return LoadMDL(file, ModelLoadItems.AllStatic | ModelLoadItems.Animations);
return LoadMDL(file, ModelLoadItems.AllStatic | ModelLoadItems.Animations, pal);
}

// Model loader for MDL files. Reference Valve's studiohdr_t struct definition for the most part.
public DataStructures.Models.Model LoadMDL(IFile file, ModelLoadItems loadItems)
public DataStructures.Models.Model LoadMDL(IFile file, ModelLoadItems loadItems, DataStructures.GameData.Palette pal)
{
using (var fs = new MemoryStream(file.ReadAll()))
{
using(var br = new BinaryReader(fs))
{
return ReadModel(br, file, loadItems);
return ReadModel(br, file, loadItems, pal);
}
}
}
Expand All @@ -73,7 +73,7 @@ public DataStructures.Models.Model LoadMDL(IFile file, ModelLoadItems loadItems)
private const byte VTXStripGroupTriListFlag = 0x01;
private const byte VTXStripGroupTriStripFlag = 0x02;

private static DataStructures.Models.Model ReadModel(BinaryReader br, IFile file, ModelLoadItems loadItems)
private static DataStructures.Models.Model ReadModel(BinaryReader br, IFile file, ModelLoadItems loadItems, DataStructures.GameData.Palette pal)
{
// int id - Not really an int. This is a magic string, either "IDST" or "IDSQ".
var magicString = br.ReadFixedLengthString(Encoding.UTF8, 4);
Expand Down
10 changes: 5 additions & 5 deletions Sledge.Providers/Model/ModelProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ public static void DeregisterAll()
RegisteredProviders.Clear();
}

public static ModelReference CreateModelReference(IFile file)
public static ModelReference CreateModelReference(IFile file, DataStructures.GameData.Palette pal)
{
var model = LoadModel(file);
var model = LoadModel(file, pal);
var reference = new ModelReference(file.FullPathName, model);
References.Add(reference);
return reference;
Expand All @@ -59,7 +59,7 @@ public static bool CanLoad(IFile file)
return RegisteredProviders.Any(p => p.IsValidForFile(file));
}

private static DataStructures.Models.Model LoadModel(IFile file)
private static DataStructures.Models.Model LoadModel(IFile file, DataStructures.GameData.Palette pal)
{
var path = file.FullPathName;
if (Models.ContainsKey(path)) return Models[path];
Expand All @@ -68,7 +68,7 @@ private static DataStructures.Models.Model LoadModel(IFile file)
var provider = RegisteredProviders.FirstOrDefault(p => p.IsValidForFile(file));
if (provider != null)
{
var model = provider.LoadFromFile(file);
var model = provider.LoadFromFile(file, pal);
model.PreprocessModel();
for (var i = 0; i < model.Textures.Count; i++)
{
Expand All @@ -88,6 +88,6 @@ private static void UnloadModel(DataStructures.Models.Model model)
}

protected abstract bool IsValidForFile(IFile file);
protected abstract DataStructures.Models.Model LoadFromFile(IFile file);
protected abstract DataStructures.Models.Model LoadFromFile(IFile file, DataStructures.GameData.Palette pal);
}
}
5 changes: 3 additions & 2 deletions Sledge.Providers/Texture/SprProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Sledge.Common;
using Sledge.FileSystem;
using Sledge.Graphics.Helpers;
using Sledge.DataStructures.GameData;

namespace Sledge.Providers.Texture
{
Expand Down Expand Up @@ -137,11 +138,11 @@ public override void LoadTextures(IEnumerable<TextureItem> items)
}
}

public override IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist)
public override IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist, Palette pal)
{
// Sprite provider ignores the black/whitelists
var dirs = sourceRoots.Union(additionalPackages).Where(Directory.Exists).Select(Path.GetFullPath).Select(x => x.ToLowerInvariant()).Distinct().ToList();
var tp = new TexturePackage(String.Join(";", dirs), "sprites", this) {IsBrowsable = false};
var tp = new TexturePackage(String.Join(";", dirs), "sprites", this, pal) {IsBrowsable = false};
foreach (var dir in dirs)
{
var sprs = Directory.GetFiles(dir, "*.spr", SearchOption.AllDirectories);
Expand Down
5 changes: 4 additions & 1 deletion Sledge.Providers/Texture/TexturePackage.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Sledge.Graphics.Helpers;
using Sledge.DataStructures.GameData;

namespace Sledge.Providers.Texture
{
Expand All @@ -12,15 +13,17 @@ public class TexturePackage : IDisposable
public Dictionary<string, TextureItem> Items { get; private set; }
private readonly Dictionary<string, TextureItem> _loadedItems;
public bool IsBrowsable { get; set; }
public Palette Palette { get; private set; }

public TexturePackage(string packageRoot, string packageRelativePath, TextureProvider provider)
public TexturePackage(string packageRoot, string packageRelativePath, TextureProvider provider, Palette pal)
{
Provider = provider;
PackageRoot = packageRoot;
PackageRelativePath = packageRelativePath;
Items = new Dictionary<string, TextureItem>();
_loadedItems = new Dictionary<string, TextureItem>();
IsBrowsable = true;
Palette = pal;
}

public void AddTexture(TextureItem item)
Expand Down
7 changes: 4 additions & 3 deletions Sledge.Providers/Texture/TextureProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Sledge.Graphics.Helpers;
using Sledge.DataStructures.GameData;

namespace Sledge.Providers.Texture
{
Expand Down Expand Up @@ -41,12 +42,12 @@ public static void Deregister(TextureProvider provider)
#endregion

protected string CachePath { get; private set; }
public abstract IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist);
public abstract IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist, Palette pal);
public abstract void DeletePackages(IEnumerable<TexturePackage> packages);
public abstract void LoadTextures(IEnumerable<TextureItem> items);
public abstract ITextureStreamSource GetStreamSource(int maxWidth, int maxHeight, IEnumerable<TexturePackage> packages);

public static TextureCollection CreateCollection(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist)
public static TextureCollection CreateCollection(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist, Palette pal)
{
var list = sourceRoots.ToList();
var additional = additionalPackages == null ? new List<string>() : additionalPackages.ToList();
Expand All @@ -55,7 +56,7 @@ public static TextureCollection CreateCollection(IEnumerable<string> sourceRoots
var pkgs = new List<TexturePackage>();
foreach (var provider in RegisteredProviders)
{
pkgs.AddRange(provider.CreatePackages(list, additional, bl, wl));
pkgs.AddRange(provider.CreatePackages(list, additional, bl, wl, pal));
}
var tc = new TextureCollection(pkgs);
Packages.AddRange(pkgs);
Expand Down
5 changes: 3 additions & 2 deletions Sledge.Providers/Texture/VmtProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
using Sledge.Graphics.Helpers;
using Sledge.Packages;
using Sledge.Packages.Vpk;
using Sledge.DataStructures.GameData;

namespace Sledge.Providers.Texture
{
public class VmtProvider : TextureProvider
{
private readonly Dictionary<TexturePackage, QuickRoot> _roots = new Dictionary<TexturePackage, QuickRoot>();

public override IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist)
public override IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> sourceRoots, IEnumerable<string> additionalPackages, IEnumerable<string> blacklist, IEnumerable<string> whitelist, Palette pal)
{
var blist = blacklist.Select(x => x.TrimEnd('/', '\\')).Where(x => !String.IsNullOrWhiteSpace(x)).ToList();
var wlist = whitelist.Select(x => x.TrimEnd('/', '\\')).Where(x => !String.IsNullOrWhiteSpace(x)).ToList();
Expand Down Expand Up @@ -59,7 +60,7 @@ public override IEnumerable<TexturePackage> CreatePackages(IEnumerable<string> s
continue;
}

if (!packages.ContainsKey(dir)) packages.Add(dir, new TexturePackage(packageRoot, dir, this));
if (!packages.ContainsKey(dir)) packages.Add(dir, new TexturePackage(packageRoot, dir, this, pal));
if (packages[dir].HasTexture(vmt)) continue;

var gs = GenericStructure.Parse(new StreamReader(vmtRoot.OpenFile(vmt))).FirstOrDefault();
Expand Down
Loading