mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-31 04:40:55 +00:00
GZDoomBuilder 1.06a:
MODELDEFs and models can now be loaded from PK3 resources (does anybody know if models or MODELDEFs can be stored in WADs?). Negative scale and zOffset are now correctly parsed from MODELDEFs (model surfaces may be inverted though). Fixed a crash while reading MODELDEFs when Operation System's decimal separator was set to comma. Fixed a crash when user changed Thing type in Visual mode to a new one with model override, which wasn't previously used in a map. Fixed a bug introduced in 1.06 when models weren't rendered in Visual mode when Fullbright mode was on. Non-breaking space is now correctly handled by all Doom Builder's data parsers. ColorPicker plugin: Fixed a crash when user attempted to open ColorPicker window to edit sector properties in Visual mode, using hilighted surface as selection source, without selecting anything before doing so.
This commit is contained in:
parent
9a72148ad1
commit
3a0426cd7f
28 changed files with 707 additions and 491 deletions
|
@ -367,7 +367,7 @@ powerups
|
||||||
title = "Invisibility";
|
title = "Invisibility";
|
||||||
sprite = "PINSA0";
|
sprite = "PINSA0";
|
||||||
height = 45;
|
height = 45;
|
||||||
class = "BlurSphere ";
|
class = "BlurSphere";
|
||||||
}
|
}
|
||||||
2025
|
2025
|
||||||
{
|
{
|
||||||
|
|
|
@ -713,10 +713,11 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="GZBuilder\Data\BoundingBox.cs" />
|
<Compile Include="GZBuilder\Data\BoundingBox.cs" />
|
||||||
<Compile Include="GZBuilder\Data\GZDoomLight.cs" />
|
<Compile Include="GZBuilder\Data\GZDoomLight.cs" />
|
||||||
<Compile Include="GZBuilder\Data\ModelDefEntry.cs" />
|
<Compile Include="GZBuilder\Data\ModeldefEntry.cs" />
|
||||||
<Compile Include="GZBuilder\Data\ThingBoundingBox.cs" />
|
<Compile Include="GZBuilder\Data\ThingBoundingBox.cs" />
|
||||||
|
<Compile Include="GZBuilder\GZDoom\ModeldefParser.cs" />
|
||||||
|
<Compile Include="GZBuilder\GZDoom\ModeldefStructure.cs" />
|
||||||
<Compile Include="GZBuilder\GZGeneral.cs" />
|
<Compile Include="GZBuilder\GZGeneral.cs" />
|
||||||
<Compile Include="GZBuilder\IO\ModelDefParser.cs" />
|
|
||||||
<Compile Include="GZBuilder\md3\GZModel.cs" />
|
<Compile Include="GZBuilder\md3\GZModel.cs" />
|
||||||
<Compile Include="GZBuilder\md3\ModelReader.cs" />
|
<Compile Include="GZBuilder\md3\ModelReader.cs" />
|
||||||
<Compile Include="IO\DoomColormapReader.cs" />
|
<Compile Include="IO\DoomColormapReader.cs" />
|
||||||
|
|
|
@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 10.00
|
||||||
# Visual C# Express 2008
|
# Visual C# Express 2008
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPicker", "..\Plugins\ColorPicker\ColorPicker.csproj", "{A4761900-0EA3-4FE4-A919-847FD5080EFC}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -25,16 +23,6 @@ Global
|
||||||
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|Mixed Platforms.Build.0 = Release|x86
|
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.ActiveCfg = Release|x86
|
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.ActiveCfg = Release|x86
|
||||||
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.Build.0 = Release|x86
|
{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}.Release|x86.Build.0 = Release|x86
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Any CPU.ActiveCfg = Debug|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Any CPU.ActiveCfg = Release|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Mixed Platforms.Build.0 = Release|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.Build.0 = Release|x86
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -33,6 +33,10 @@ using CodeImp.DoomBuilder.Map;
|
||||||
using CodeImp.DoomBuilder.Windows;
|
using CodeImp.DoomBuilder.Windows;
|
||||||
using CodeImp.DoomBuilder.ZDoom;
|
using CodeImp.DoomBuilder.ZDoom;
|
||||||
|
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.GZDoom;
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.Data
|
namespace CodeImp.DoomBuilder.Data
|
||||||
|
@ -65,7 +69,10 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
private AllTextureSet alltextures;
|
private AllTextureSet alltextures;
|
||||||
|
|
||||||
//mxd Folders
|
//mxd Folders
|
||||||
private List<string> folders;
|
//private List<string> folders;
|
||||||
|
|
||||||
|
//mxd modeldefs
|
||||||
|
private Dictionary<int, ModeldefEntry> modeldefEntries;
|
||||||
|
|
||||||
// Background loading
|
// Background loading
|
||||||
private Queue<ImageData> imageque;
|
private Queue<ImageData> imageque;
|
||||||
|
@ -107,7 +114,8 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
#region ================== Properties
|
#region ================== Properties
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
public List<string> Folders { get { return folders; } }
|
//public List<string> Folders { get { return folders; } }
|
||||||
|
public Dictionary<int, ModeldefEntry> ModeldefEntries { get { return modeldefEntries; } }
|
||||||
|
|
||||||
public Playpal Palette { get { return palette; } }
|
public Playpal Palette { get { return palette; } }
|
||||||
public PreviewManager Previews { get { return previews; } }
|
public PreviewManager Previews { get { return previews; } }
|
||||||
|
@ -247,9 +255,6 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
internalsprites = new Dictionary<string, ImageData>();
|
internalsprites = new Dictionary<string, ImageData>();
|
||||||
thingcategories = General.Map.Config.GetThingCategories();
|
thingcategories = General.Map.Config.GetThingCategories();
|
||||||
thingtypes = General.Map.Config.GetThingTypes();
|
thingtypes = General.Map.Config.GetThingTypes();
|
||||||
|
|
||||||
//mxd
|
|
||||||
folders = new List<string>();
|
|
||||||
|
|
||||||
// Load texture sets
|
// Load texture sets
|
||||||
foreach(DefinedTextureSet ts in General.Map.ConfigSettings.TextureSets)
|
foreach(DefinedTextureSet ts in General.Map.ConfigSettings.TextureSets)
|
||||||
|
@ -285,10 +290,6 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
// Directory container
|
// Directory container
|
||||||
case DataLocation.RESOURCE_DIRECTORY:
|
case DataLocation.RESOURCE_DIRECTORY:
|
||||||
c = new DirectoryReader(dl);
|
c = new DirectoryReader(dl);
|
||||||
|
|
||||||
//mxd
|
|
||||||
folders.Add(dl.location);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// PK3 file container
|
// PK3 file container
|
||||||
|
@ -322,6 +323,9 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
thingcount = LoadDecorateThings();
|
thingcount = LoadDecorateThings();
|
||||||
spritecount = LoadThingSprites();
|
spritecount = LoadThingSprites();
|
||||||
LoadInternalSprites();
|
LoadInternalSprites();
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
loadModeldefs();
|
||||||
|
|
||||||
// Process colormaps (we just put them in as textures)
|
// Process colormaps (we just put them in as textures)
|
||||||
foreach(KeyValuePair<long, ImageData> t in colormapsonly)
|
foreach(KeyValuePair<long, ImageData> t in colormapsonly)
|
||||||
|
@ -434,6 +438,13 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
foreach(KeyValuePair<long, ImageData> i in flats) i.Value.Dispose();
|
foreach(KeyValuePair<long, ImageData> i in flats) i.Value.Dispose();
|
||||||
foreach(KeyValuePair<long, ImageData> i in sprites) i.Value.Dispose();
|
foreach(KeyValuePair<long, ImageData> i in sprites) i.Value.Dispose();
|
||||||
palette = null;
|
palette = null;
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
if (modeldefEntries != null) {
|
||||||
|
foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries) {
|
||||||
|
group.Value.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dispose containers
|
// Dispose containers
|
||||||
foreach(DataReader c in containers) c.Dispose();
|
foreach(DataReader c in containers) c.Dispose();
|
||||||
|
@ -1342,10 +1353,110 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ================== Tools
|
|
||||||
|
|
||||||
// This finds the first IWAD resource
|
#region ================== Modeldef and models
|
||||||
|
|
||||||
|
public void LoadModels() {
|
||||||
|
General.MainWindow.DisplayStatus(StatusType.Busy, "Loading models...");
|
||||||
|
|
||||||
|
foreach (Thing t in General.Map.Map.Things)
|
||||||
|
LoadModelForThing(t);
|
||||||
|
|
||||||
|
General.MainWindow.RedrawDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LoadModelForThing(Thing t) {
|
||||||
|
if (modeldefEntries.ContainsKey(t.Type)) {
|
||||||
|
if (modeldefEntries[t.Type].Model == null) {
|
||||||
|
//load model and texture
|
||||||
|
ModeldefEntry mde = modeldefEntries[t.Type];
|
||||||
|
|
||||||
|
foreach (DataReader dr in containers) {
|
||||||
|
currentreader = dr;
|
||||||
|
if (currentreader.Location.location == mde.Location) {
|
||||||
|
ModelReader.Parse(ref mde, (PK3StructuredReader)currentreader, General.Map.Graphics.Device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentreader = null;
|
||||||
|
|
||||||
|
if (mde.Model != null) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Loaded model for Thing ¹" + t.Type);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
modeldefEntries.Remove(t.Type);
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Failed to load model(s) for Thing ¹" + t.Type + ", model(s) location is "+mde.Location+ "\\" + mde.Path +". MODELDEF node removed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mxd. This parses modeldefs
|
||||||
|
private void loadModeldefs() {
|
||||||
|
General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing model definitions...");
|
||||||
|
|
||||||
|
Dictionary<string, int> Actors = new Dictionary<string, int>();
|
||||||
|
Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
|
||||||
|
|
||||||
|
//read our new shiny ClassNames for default game things
|
||||||
|
foreach (KeyValuePair<int, ThingTypeInfo> ti in things) {
|
||||||
|
if (ti.Value.ClassName != null)
|
||||||
|
Actors.Add(ti.Value.ClassName, ti.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//and for actors defined in DECORATE
|
||||||
|
ICollection<ActorStructure> ac = decorate.Actors; //General.Map.Data.Decorate.Actors;
|
||||||
|
foreach (ActorStructure actor in ac) {
|
||||||
|
string className = actor.ClassName.ToLower();
|
||||||
|
if (actor.DoomEdNum != -1 && !Actors.ContainsKey(className)) //we don't need actors without DoomEdNum
|
||||||
|
Actors.Add(className, actor.DoomEdNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, ModeldefEntry> modelDefEntriesByName = new Dictionary<string, ModeldefEntry>();
|
||||||
|
ModeldefParser mdeParser = new ModeldefParser();
|
||||||
|
|
||||||
|
foreach (DataReader dr in containers) {
|
||||||
|
currentreader = dr;
|
||||||
|
|
||||||
|
Dictionary<string, Stream> streams = dr.GetModeldefData();
|
||||||
|
foreach (KeyValuePair<string, Stream> group in streams) {
|
||||||
|
//dbg
|
||||||
|
GZBuilder.GZGeneral.Trace("Adding mdes from " + currentreader.Location.location);
|
||||||
|
|
||||||
|
// Parse the data
|
||||||
|
group.Value.Seek(0, SeekOrigin.Begin);
|
||||||
|
mdeParser.Parse(group.Value, currentreader.Location.location + "\\" + group.Key);
|
||||||
|
Dictionary<string, ModeldefEntry> mdes = mdeParser.ModelDefEntries;
|
||||||
|
|
||||||
|
if (mdes != null) {
|
||||||
|
foreach (KeyValuePair<string, ModeldefEntry> g in mdes) {
|
||||||
|
g.Value.Location = currentreader.Location.location;
|
||||||
|
modelDefEntriesByName.Add(g.Key, g.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentreader = null;
|
||||||
|
modeldefEntries = new Dictionary<int, ModeldefEntry>();
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, ModeldefEntry> e in modelDefEntriesByName) {
|
||||||
|
if (Actors.ContainsKey(e.Key)) {
|
||||||
|
modeldefEntries[Actors[e.Key]] = modelDefEntriesByName[e.Key];
|
||||||
|
} else {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Got MODELDEF override for class '" + e.Key + "', but haven't found such class in Decorate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Tools
|
||||||
|
|
||||||
|
// This finds the first IWAD resource
|
||||||
// Returns false when not found
|
// Returns false when not found
|
||||||
internal bool FindFirstIWAD(out DataLocation result)
|
internal bool FindFirstIWAD(out DataLocation result)
|
||||||
{
|
{
|
||||||
|
|
|
@ -156,6 +156,13 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
// When implemented, this returns the decorate lump
|
// When implemented, this returns the decorate lump
|
||||||
public virtual List<Stream> GetDecorateData(string pname) { return new List<Stream>(); }
|
public virtual List<Stream> GetDecorateData(string pname) { return new List<Stream>(); }
|
||||||
|
|
||||||
|
//mxd. When implemented, this returns the modeldef lump
|
||||||
|
public virtual Dictionary<string, Stream> GetModeldefData() { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
//public Stream GetModel(string path) { return null; }
|
||||||
|
//protected abstract MemoryStream LoadFile(string filename);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
// This returns true if the specified file exists
|
// This returns true if the specified file exists
|
||||||
protected override bool FileExists(string filename)
|
public override bool FileExists(string filename)
|
||||||
{
|
{
|
||||||
return files.FileExists(filename);
|
return files.FileExists(filename);
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
|
|
||||||
// This loads an entire file in memory and returns the stream
|
// This loads an entire file in memory and returns the stream
|
||||||
// NOTE: Callers are responsible for disposing the stream!
|
// NOTE: Callers are responsible for disposing the stream!
|
||||||
protected override MemoryStream LoadFile(string filename)
|
public override MemoryStream LoadFile(string filename)
|
||||||
{
|
{
|
||||||
return new MemoryStream(File.ReadAllBytes(Path.Combine(location.location, filename)));
|
return new MemoryStream(File.ReadAllBytes(Path.Combine(location.location, filename)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,7 +267,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
// This returns true if the specified file exists
|
// This returns true if the specified file exists
|
||||||
protected override bool FileExists(string filename)
|
public override bool FileExists(string filename)
|
||||||
{
|
{
|
||||||
return files.FileExists(filename);
|
return files.FileExists(filename);
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
|
|
||||||
// This loads an entire file in memory and returns the stream
|
// This loads an entire file in memory and returns the stream
|
||||||
// NOTE: Callers are responsible for disposing the stream!
|
// NOTE: Callers are responsible for disposing the stream!
|
||||||
protected override MemoryStream LoadFile(string filename)
|
public override MemoryStream LoadFile(string filename)
|
||||||
{
|
{
|
||||||
MemoryStream filedata = null;
|
MemoryStream filedata = null;
|
||||||
byte[] copybuffer = new byte[4096];
|
byte[] copybuffer = new byte[4096];
|
||||||
|
@ -359,7 +359,10 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return filedata;
|
//mxd. rewind before use
|
||||||
|
filedata.Position = 0;
|
||||||
|
|
||||||
|
return filedata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -417,10 +417,32 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ================== Methods
|
#region ================== Modeldef
|
||||||
|
|
||||||
// This loads the images in this directory
|
//mxd
|
||||||
|
public override Dictionary<string, Stream> GetModeldefData() {
|
||||||
|
Dictionary<string, Stream> streams = new Dictionary<string, Stream>();
|
||||||
|
// Error when suspended
|
||||||
|
if (issuspended) throw new Exception("Data reader is suspended");
|
||||||
|
|
||||||
|
//modedef should be in root folder
|
||||||
|
string[] allFiles = GetAllFiles("", false);
|
||||||
|
|
||||||
|
foreach (string s in allFiles) {
|
||||||
|
if (s.ToLowerInvariant().IndexOf("modeldef") != -1) {
|
||||||
|
streams.Add(s, LoadFile(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
// This loads the images in this directory
|
||||||
private ICollection<ImageData> LoadDirectoryImages(string path, int imagetype, bool includesubdirs)
|
private ICollection<ImageData> LoadDirectoryImages(string path, int imagetype, bool includesubdirs)
|
||||||
{
|
{
|
||||||
List<ImageData> images = new List<ImageData>();
|
List<ImageData> images = new List<ImageData>();
|
||||||
|
@ -466,7 +488,8 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
protected abstract ImageData CreateImage(string name, string filename, int imagetype);
|
protected abstract ImageData CreateImage(string name, string filename, int imagetype);
|
||||||
|
|
||||||
// This must return true if the specified file exists
|
// This must return true if the specified file exists
|
||||||
protected abstract bool FileExists(string filename);
|
//mxd
|
||||||
|
public abstract bool FileExists(string filename);
|
||||||
|
|
||||||
// This must return all files in a given directory
|
// This must return all files in a given directory
|
||||||
protected abstract string[] GetAllFiles(string path, bool subfolders);
|
protected abstract string[] GetAllFiles(string path, bool subfolders);
|
||||||
|
@ -488,7 +511,8 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
|
|
||||||
// This must load an entire file in memory and returns the stream
|
// This must load an entire file in memory and returns the stream
|
||||||
// NOTE: Callers are responsible for disposing the stream!
|
// NOTE: Callers are responsible for disposing the stream!
|
||||||
protected abstract MemoryStream LoadFile(string filename);
|
//mxd
|
||||||
|
public abstract MemoryStream LoadFile(string filename);
|
||||||
|
|
||||||
// This must create a temp file for the speciied file and return the absolute path to the temp file
|
// This must create a temp file for the speciied file and return the absolute path to the temp file
|
||||||
// NOTE: Callers are responsible for removing the temp file when done!
|
// NOTE: Callers are responsible for removing the temp file when done!
|
||||||
|
|
|
@ -816,7 +816,6 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
|
|
||||||
return streams;
|
return streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,39 @@ using System.Text;
|
||||||
using SlimDX;
|
using SlimDX;
|
||||||
using SlimDX.Direct3D9;
|
using SlimDX.Direct3D9;
|
||||||
|
|
||||||
using ColladaDotNet.Pipeline.MD3;
|
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.GZBuilder.Data
|
namespace CodeImp.DoomBuilder.GZBuilder.Data
|
||||||
{
|
{
|
||||||
public class ModelDefEntry
|
public class ModeldefEntry
|
||||||
{
|
{
|
||||||
public string Name;
|
public string ClassName;
|
||||||
public string Path;
|
public string Path; //this holds Path parameter of MODELDEF entry
|
||||||
public List<string> ModelNames;
|
public List<string> ModelNames;
|
||||||
public List<string> TextureNames;
|
public List<string> TextureNames;
|
||||||
|
public string Location; //this holds location of resource, from which modeldef was loaded
|
||||||
|
|
||||||
public GZModel Model;
|
public GZModel Model;
|
||||||
|
|
||||||
public Vector3 Scale;
|
public Vector3 Scale;
|
||||||
public float zOffset;
|
public float zOffset;
|
||||||
|
|
||||||
public ModelDefEntry() {
|
public ModeldefEntry() {
|
||||||
Scale = new Vector3(1, 1, 1);
|
|
||||||
zOffset = 0;
|
|
||||||
ModelNames = new List<string>();
|
ModelNames = new List<string>();
|
||||||
TextureNames = new List<string>();
|
TextureNames = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (Model != null) {
|
||||||
|
foreach (IndexBuffer ib in Model.Indeces2D)
|
||||||
|
ib.Dispose();
|
||||||
|
|
||||||
|
foreach (Mesh mesh in Model.Meshes)
|
||||||
|
mesh.Dispose();
|
||||||
|
|
||||||
|
foreach (Texture t in Model.Textures)
|
||||||
|
t.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
88
Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
Normal file
88
Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using CodeImp.DoomBuilder.ZDoom;
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.GZDoom;
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
|
||||||
|
|
||||||
|
public class ModeldefParser : ZDTextParser {
|
||||||
|
public static string INVALID_TEXTURE = "**INVALID_TEXTURE**";
|
||||||
|
|
||||||
|
private Dictionary<string, ModeldefEntry> modelDefEntries; //classname, entry
|
||||||
|
public Dictionary<string, ModeldefEntry> ModelDefEntries { get { return modelDefEntries; } }
|
||||||
|
|
||||||
|
public string Source { get { return sourcename; } }
|
||||||
|
|
||||||
|
//should be called after all decorate actors are parsed
|
||||||
|
public override bool Parse(Stream stream, string sourcefilename) {
|
||||||
|
base.Parse(stream, sourcefilename);
|
||||||
|
modelDefEntries = new Dictionary<string, ModeldefEntry>();
|
||||||
|
|
||||||
|
// Continue until at the end of the stream
|
||||||
|
while (SkipWhitespace(true)) {
|
||||||
|
string token = ReadToken();
|
||||||
|
if (token != null) {
|
||||||
|
token = token.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (token == "model") { //model structure start
|
||||||
|
//find classname
|
||||||
|
SkipWhitespace(true);
|
||||||
|
string className = StripTokenQuotes(ReadToken()).ToLowerInvariant();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(className)) {
|
||||||
|
if (modelDefEntries.ContainsKey(className))
|
||||||
|
continue; //already got this class; continue to next one
|
||||||
|
|
||||||
|
//now find opening brace
|
||||||
|
SkipWhitespace(true);
|
||||||
|
token = ReadToken();
|
||||||
|
if (token != "{") {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Unexpected token found in "+sourcefilename+" at line "+GetCurrentLineNumber()+": expected '{', but got " + token);
|
||||||
|
continue; //something wrong with modeldef declaration, continue to next one
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeldefStructure mds = new ModeldefStructure();
|
||||||
|
ModeldefEntry mde = mds.Parse(this);
|
||||||
|
if (mde != null) {
|
||||||
|
GZBuilder.GZGeneral.Trace("Got mds for class " + className);
|
||||||
|
mde.ClassName = className;
|
||||||
|
modelDefEntries.Add(className, mde);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue; //no class name found. continue to next structure
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Unknown structure!
|
||||||
|
string token2;
|
||||||
|
do {
|
||||||
|
if (!SkipWhitespace(true)) break;
|
||||||
|
token2 = ReadToken();
|
||||||
|
if (token2 == null) break;
|
||||||
|
}
|
||||||
|
while (token2 != "{");
|
||||||
|
int scopelevel = 1;
|
||||||
|
do {
|
||||||
|
if (!SkipWhitespace(true)) break;
|
||||||
|
token2 = ReadToken();
|
||||||
|
if (token2 == null) break;
|
||||||
|
if (token2 == "{") scopelevel++;
|
||||||
|
if (token2 == "}") scopelevel--;
|
||||||
|
}
|
||||||
|
while (scopelevel > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelDefEntries.Count > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
230
Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
Normal file
230
Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using SlimDX;
|
||||||
|
using SlimDX.Direct3D9;
|
||||||
|
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
|
||||||
|
public sealed class ModeldefStructure {
|
||||||
|
private string[] supportedTextureExtensions = { ".jpg", ".tga", ".png", ".dds" };
|
||||||
|
|
||||||
|
public ModeldefEntry Parse(ModeldefParser parser) {
|
||||||
|
string[] textureNames = new string[16];
|
||||||
|
string[] modelNames = new string[16];
|
||||||
|
string path = "";
|
||||||
|
Vector3 scale = new Vector3(1, 1, 1);
|
||||||
|
float zOffset = 0;
|
||||||
|
string token;
|
||||||
|
bool gotErrors = false;
|
||||||
|
|
||||||
|
//read modeldef structure contents
|
||||||
|
while (parser.SkipWhitespace(true)) {
|
||||||
|
token = parser.ReadToken();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(token)) {
|
||||||
|
token = token.ToLowerInvariant();
|
||||||
|
|
||||||
|
char a = token[0];
|
||||||
|
char c = " "[0];
|
||||||
|
bool b1 = Char.IsWhiteSpace(a);
|
||||||
|
bool b2 = Char.IsWhiteSpace(c);
|
||||||
|
bool f;
|
||||||
|
|
||||||
|
//path
|
||||||
|
if (token == "path") {
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
path = parser.StripTokenQuotes(parser.ReadToken()).Replace("/", "\\");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(path)) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected path to model, but got '" + token + "' in " + parser.Source + " at line "+parser.GetCurrentLineNumber());
|
||||||
|
//GZBuilder.GZGeneral.LogAndTraceWarning("Expected path to model, but got '" + token + "'");
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//model
|
||||||
|
} else if (token == "model") {
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
//model index
|
||||||
|
int modelIndex;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelIndex)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected model index, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//model path
|
||||||
|
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
|
||||||
|
if (string.IsNullOrEmpty(token)) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected model name, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
//check extension
|
||||||
|
int dotPos = token.LastIndexOf(".");
|
||||||
|
string fileExt = token.Substring(token.LastIndexOf("."), token.Length - dotPos);
|
||||||
|
if (fileExt != ".md3" && fileExt != ".md2") {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Model '" + token + "' not parsed in " + parser.Source + " at line " + parser.GetCurrentLineNumber() +". Only MD3 and MD2 models are supported.");
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelNames[modelIndex] != null) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Error: already got model for index " + modelIndex + " in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
modelNames[modelIndex] = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//skin
|
||||||
|
} else if (token == "skin") {
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
//skin index
|
||||||
|
int skinIndex;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out skinIndex)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected skin index, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//skin path
|
||||||
|
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
|
||||||
|
if (string.IsNullOrEmpty(token)) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected skin name, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
//check extension
|
||||||
|
int dotPos = token.LastIndexOf(".");
|
||||||
|
string fileExt = token.Substring(token.LastIndexOf("."), token.Length - dotPos);
|
||||||
|
if(Array.IndexOf(supportedTextureExtensions, fileExt) == -1)
|
||||||
|
token = ModeldefParser.INVALID_TEXTURE;
|
||||||
|
|
||||||
|
if (textureNames[skinIndex] != null) {
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Already got model for index " + skinIndex + " in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
textureNames[skinIndex] = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//scale
|
||||||
|
} else if (token == "scale") {
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
token = parser.ReadToken();
|
||||||
|
|
||||||
|
int sign = 1;
|
||||||
|
if (token == "-") {
|
||||||
|
sign = -1;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.X)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected scale X value, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scale.X *= sign;
|
||||||
|
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
token = parser.ReadToken();
|
||||||
|
|
||||||
|
sign = 1;
|
||||||
|
if (token == "-") {
|
||||||
|
sign = -1;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.Y)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected scale Y value, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scale.Y *= sign;
|
||||||
|
|
||||||
|
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
token = parser.ReadToken();
|
||||||
|
|
||||||
|
sign = 1;
|
||||||
|
if (token == "-") {
|
||||||
|
sign = -1;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale.Z)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected scale Z value, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scale.Z *= sign;
|
||||||
|
//zoffset
|
||||||
|
} else if (token == "zoffset") {
|
||||||
|
parser.SkipWhitespace(true);
|
||||||
|
|
||||||
|
token = parser.ReadToken();
|
||||||
|
|
||||||
|
int sign = 1;
|
||||||
|
if (token == "-") {
|
||||||
|
sign = -1;
|
||||||
|
token = parser.ReadToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out zOffset)) {
|
||||||
|
// Not numeric!
|
||||||
|
GZBuilder.GZGeneral.LogAndTraceWarning("Expected ZOffset value, but got '" + token + "' in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
|
||||||
|
gotErrors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
zOffset *= sign;
|
||||||
|
//frameindex
|
||||||
|
} else if (token == "frameindex") {
|
||||||
|
//parsed all required fields
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//find closing brace, then quit;
|
||||||
|
while (parser.SkipWhitespace(true)) {
|
||||||
|
token = parser.ReadToken();
|
||||||
|
if (token == "}")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gotErrors)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
//classname is set in ModeldefParser
|
||||||
|
ModeldefEntry mde = new ModeldefEntry();
|
||||||
|
mde.Path = path;
|
||||||
|
mde.Scale = scale;
|
||||||
|
mde.zOffset = zOffset;
|
||||||
|
|
||||||
|
for (int i = 0; i < textureNames.Length; i++ ) {
|
||||||
|
if (textureNames[i] != null && modelNames[i] != null) {
|
||||||
|
mde.TextureNames.Add(textureNames[i]);
|
||||||
|
mde.ModelNames.Add(modelNames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mde;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,20 +10,14 @@ using CodeImp.DoomBuilder.Actions;
|
||||||
using CodeImp.DoomBuilder.Windows;
|
using CodeImp.DoomBuilder.Windows;
|
||||||
using CodeImp.DoomBuilder.Config;
|
using CodeImp.DoomBuilder.Config;
|
||||||
|
|
||||||
using CodeImp.DoomBuilder.GZBuilder.IO;
|
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Controls;
|
using CodeImp.DoomBuilder.GZBuilder.Controls;
|
||||||
|
|
||||||
using ColladaDotNet.Pipeline.MD3;
|
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.GZBuilder
|
namespace CodeImp.DoomBuilder.GZBuilder
|
||||||
{
|
{
|
||||||
//mxd. should get rid of this class one day...
|
//mxd. should get rid of this class one day...
|
||||||
public class GZGeneral
|
public class GZGeneral
|
||||||
{
|
{
|
||||||
private static Dictionary<int, ModelDefEntry> modelDefEntries; //doomEdNum, entry
|
|
||||||
public static Dictionary<int, ModelDefEntry> ModelDefEntries { get { return modelDefEntries; } }
|
|
||||||
|
|
||||||
//gzdoom light types
|
//gzdoom light types
|
||||||
private static int[] gzLights = { /* normal lights */ 9800, 9801, 9802, 9803, 9804, /* additive lights */ 9810, 9811, 9812, 9813, 9814, /* negative lights */ 9820, 9821, 9822, 9823, 9824, /* vavoom lights */ 1502, 1503};
|
private static int[] gzLights = { /* normal lights */ 9800, 9801, 9802, 9803, 9804, /* additive lights */ 9810, 9811, 9812, 9813, 9814, /* negative lights */ 9820, 9821, 9822, 9823, 9824, /* vavoom lights */ 1502, 1503};
|
||||||
public static int[] GZ_LIGHTS { get { return gzLights; } }
|
public static int[] GZ_LIGHTS { get { return gzLights; } }
|
||||||
|
@ -34,6 +28,8 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
||||||
|
|
||||||
public static bool UDMF;
|
public static bool UDMF;
|
||||||
|
|
||||||
|
//public static float[] FogTable; // light to fog conversion table for black fog
|
||||||
|
|
||||||
//version
|
//version
|
||||||
public const float Version = 1.06f;
|
public const float Version = 1.06f;
|
||||||
|
|
||||||
|
@ -48,6 +44,26 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
||||||
General.Actions.BindMethods(typeof(GZGeneral));
|
General.Actions.BindMethods(typeof(GZGeneral));
|
||||||
General.MainWindow.UpdateGZDoomPannel();
|
General.MainWindow.UpdateGZDoomPannel();
|
||||||
|
|
||||||
|
//create fog table
|
||||||
|
/*FogTable = new float[256];
|
||||||
|
byte gl_distfog = 255;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
if (i < 164) {
|
||||||
|
FogTable[i] = (gl_distfog >> 1) + (gl_distfog) * (164 - i) / 164;
|
||||||
|
} else if (i < 230) {
|
||||||
|
FogTable[i] = (gl_distfog >> 1) - (gl_distfog >> 1) * (i - 164) / (230 - 164);
|
||||||
|
} else FogTable[i] = 0;
|
||||||
|
|
||||||
|
//if (i < 128) {
|
||||||
|
//distfogtable[1][i] = 6.f + (gl_distfog >> 1) + (gl_distfog) * (128 - i) / 48;
|
||||||
|
//} else if (i < 216) {
|
||||||
|
//distfogtable[1][i] = (216.f - i) / ((216.f - 128.f)) * gl_distfog / 10;
|
||||||
|
//} else distfogtable[1][i] = 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//float[] ft = FogTable;
|
||||||
|
|
||||||
//create console
|
//create console
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ConsoleDocker cd = new ConsoleDocker();
|
ConsoleDocker cd = new ConsoleDocker();
|
||||||
|
@ -58,105 +74,25 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnMapOpenEnd() {
|
public static void OnMapOpenEnd() {
|
||||||
loadModelDefs();
|
|
||||||
loadModels();
|
|
||||||
UDMF = (General.Map.Config.FormatInterface == "UniversalMapSetIO");
|
UDMF = (General.Map.Config.FormatInterface == "UniversalMapSetIO");
|
||||||
General.MainWindow.UpdateGZDoomPannel();
|
General.MainWindow.UpdateGZDoomPannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnReloadResources() {
|
public static void OnReloadResources() {
|
||||||
loadModelDefs();
|
|
||||||
loadModels();
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
((ConsoleDocker)console.Control).Clear();
|
((ConsoleDocker)console.Control).Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool LoadModelForThing(Thing t) {
|
|
||||||
if (modelDefEntries.ContainsKey(t.Type)) {
|
|
||||||
string msg = "GZBuilder: got model override for Thing №" + t.Type;
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, msg);
|
|
||||||
General.WriteLogLine(msg);
|
|
||||||
|
|
||||||
if (modelDefEntries[t.Type].Model == null) {
|
|
||||||
//load model and texture
|
|
||||||
ModelDefEntry mde = modelDefEntries[t.Type];
|
|
||||||
mde.Model = ModelReader.Parse(mde, General.Map.Graphics.Device);
|
|
||||||
|
|
||||||
if (mde.Model != null) {
|
|
||||||
//General.Map.IsChanged = true;
|
|
||||||
//General.MainWindow.RedrawDisplay(); //update display
|
|
||||||
msg = "GZBuilder: loaded model for Thing №" + t.Type;
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, msg);
|
|
||||||
General.WriteLogLine(msg);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
modelDefEntries.Remove(t.Type);
|
|
||||||
msg = "GZBuilder: failed to load model(s) for Thing №" + t.Type + ". ModelDef node removed.";
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, msg);
|
|
||||||
General.WriteLogLine(msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//functions
|
|
||||||
private static void loadModelDefs() {
|
|
||||||
General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing model definitions...");
|
|
||||||
|
|
||||||
Dictionary<string, int> Actors = new Dictionary<string,int>();
|
|
||||||
Dictionary<int, ThingTypeInfo> things = General.Map.Config.GetThingTypes();
|
|
||||||
|
|
||||||
//read our new shiny ClassNames for default game things
|
|
||||||
foreach (KeyValuePair<int, ThingTypeInfo> ti in things) {
|
|
||||||
if (ti.Value.ClassName != null)
|
|
||||||
Actors.Add(ti.Value.ClassName, ti.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
//and for actors defined in DECORATE
|
|
||||||
ICollection<ActorStructure> ac = General.Map.Data.Decorate.Actors;
|
|
||||||
foreach (ActorStructure actor in ac) {
|
|
||||||
string className = actor.ClassName.ToLower();
|
|
||||||
if (actor.DoomEdNum != -1 && !Actors.ContainsKey(className)) //we don't need actors without DoomEdNum
|
|
||||||
Actors.Add(className, actor.DoomEdNum);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<string, ModelDefEntry> modelDefEntriesByName = new Dictionary<string, ModelDefEntry>();
|
|
||||||
|
|
||||||
foreach (string folder in General.Map.Data.Folders)
|
|
||||||
ModelDefParser.ParseFolder(modelDefEntriesByName, folder);
|
|
||||||
|
|
||||||
modelDefEntries = new Dictionary<int, ModelDefEntry>();
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, ModelDefEntry> e in modelDefEntriesByName) {
|
|
||||||
if (Actors.ContainsKey(e.Value.Name)) {
|
|
||||||
modelDefEntries[Actors[e.Value.Name]] = modelDefEntriesByName[e.Value.Name];
|
|
||||||
} else {
|
|
||||||
string msg = "GZBuilder: ModelDefEntry wasn't found in Decorate: '" + e.Value.Name + "'";
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, msg);
|
|
||||||
General.WriteLogLine(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//load models for things which are already in the map
|
|
||||||
private static void loadModels() {
|
|
||||||
General.MainWindow.DisplayStatus(StatusType.Busy, "Loading models...");
|
|
||||||
string msg = "GZBuilder: loading models...";
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, msg);
|
|
||||||
General.WriteLogLine(msg);
|
|
||||||
|
|
||||||
foreach(Thing t in General.Map.Map.Things)
|
|
||||||
LoadModelForThing(t);
|
|
||||||
|
|
||||||
General.MainWindow.RedrawDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
//debug
|
||||||
|
public static void LogAndTraceWarning(string message) {
|
||||||
|
General.ErrorLogger.Add(ErrorType.Warning, message);
|
||||||
|
General.WriteLogLine(message);
|
||||||
|
#if DEBUG
|
||||||
|
Trace(message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
public static void Trace(string message) {
|
public static void Trace(string message) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
((ConsoleDocker)console.Control).Trace(message);
|
((ConsoleDocker)console.Control).Trace(message);
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Globalization;
|
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.GZBuilder.IO
|
|
||||||
{
|
|
||||||
class ModelDefParser
|
|
||||||
{
|
|
||||||
public static string INVALID_TEXTURE = "**INVALID_TEXTURE**";
|
|
||||||
private static string[] SUPPORTED_TEXTURE_EXTENSIONS = { ".jpg", ".tga", ".png", ".dds", ".bmp" };
|
|
||||||
|
|
||||||
public static void ParseFolder(Dictionary<string, ModelDefEntry> modelDefEntriesByName, string path) {
|
|
||||||
string[] files = Directory.GetFiles(path);
|
|
||||||
|
|
||||||
foreach (string fileName in files) {
|
|
||||||
if (fileName.ToLower().IndexOf("modeldef") != -1)
|
|
||||||
Parse(modelDefEntriesByName, path, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
logAndTrace("ModelDefParser: parsed " + modelDefEntriesByName.Count + " definitions;");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Parse(Dictionary<string, ModelDefEntry> modelDefEntriesByName, string path, string fileName) {
|
|
||||||
logAndTrace("ModelDefParser: Parsing '" + fileName + "'");
|
|
||||||
|
|
||||||
if (File.Exists(fileName)) {
|
|
||||||
StreamReader s = File.OpenText(fileName);
|
|
||||||
string contents = s.ReadToEnd();
|
|
||||||
s.Close();
|
|
||||||
|
|
||||||
contents = StripComments(contents).ToLower();
|
|
||||||
|
|
||||||
int startIndex = 0;
|
|
||||||
int mdlIndex = 0;
|
|
||||||
|
|
||||||
while ((mdlIndex = contents.IndexOf("model", startIndex)) != -1) {
|
|
||||||
startIndex = contents.IndexOf("}", mdlIndex);
|
|
||||||
parseModelDef(modelDefEntriesByName, path, contents.Substring(mdlIndex, startIndex - mdlIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
logAndTrace("ModelDefParser: File '" + fileName + "' doesn't exist!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void parseModelDef(Dictionary<string, ModelDefEntry> modelDefEntriesByName, string path, string modelDef) {
|
|
||||||
string[] modelNames = new string[16];
|
|
||||||
string[] textureNames = new string[16];
|
|
||||||
|
|
||||||
string[] lines = modelDef.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
char[] space = new char[] { ' ' };
|
|
||||||
string[] parts = lines[0].Split(space, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
string name = parts[1].Trim().Replace("{", "");
|
|
||||||
|
|
||||||
if (modelDefEntriesByName.ContainsKey(name)) {
|
|
||||||
General.WriteLogLine("Already have ModelDef for '" + name + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char[] splitter = new char[] { ' ', '"' };
|
|
||||||
ModelDefEntry mde = new ModelDefEntry();
|
|
||||||
mde.Name = name;
|
|
||||||
|
|
||||||
for (int i = 1; i < lines.Length; i++) {
|
|
||||||
parts = lines[i].Split(space, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
if (parts.Length > 0) {
|
|
||||||
string s = parts[0].Trim();
|
|
||||||
|
|
||||||
//LOTS of boilerplate! Yay!!!
|
|
||||||
if (s.IndexOf("frameindex") != -1) {
|
|
||||||
if (mde.Name != String.Empty && mde.Path != String.Empty) {
|
|
||||||
for (int c = 0; c < modelNames.Length; c++) {
|
|
||||||
if (modelNames[c] != null && textureNames[c] != null) {
|
|
||||||
mde.ModelNames.Add(modelNames[c]);
|
|
||||||
mde.TextureNames.Add(textureNames[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mde.ModelNames.Count > 0 && mde.TextureNames.Count > 0)
|
|
||||||
modelDefEntriesByName[mde.Name] = mde;
|
|
||||||
else
|
|
||||||
logAndTrace("Error while parsing ModelDef. Not all required fileds are present." + Environment.NewLine + "Parsed data: [" + Environment.NewLine + ModelDefEntry_ToString(mde) + "]" + Environment.NewLine);
|
|
||||||
return; //we don't want to parse all frames
|
|
||||||
|
|
||||||
}
|
|
||||||
logAndTrace("Error while parsing ModelDef. Not all required fileds are present." + Environment.NewLine + "Parsed data: [" + Environment.NewLine + ModelDefEntry_ToString(mde) + "]" + Environment.NewLine);
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else if (s.IndexOf("model") != -1) {
|
|
||||||
if (parts.Length != 3) {
|
|
||||||
logAndTrace("Incorrect syntax in 'model' token for class '" + name + "': expected 3 entries, but got " + parts.Length + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fileIndex = int.Parse(parts[1].Trim(splitter), NumberStyles.Integer);
|
|
||||||
string fileName = parts[2].Trim(splitter);
|
|
||||||
string fileExt = Path.GetExtension(fileName);
|
|
||||||
|
|
||||||
if (fileExt == ".md3" || fileExt == ".md2") {
|
|
||||||
if (modelNames[fileIndex] != null) {
|
|
||||||
logAndTrace("Incorrect syntax in 'model' token for class '" + name + "': already got model with index " + fileIndex + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
modelNames[fileIndex] = fileName;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
logAndTrace("Model '" + fileName + "' not parsed. Only MD3 and MD2 models are supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (s.IndexOf("path") != -1) {
|
|
||||||
if (parts.Length != 2) {
|
|
||||||
logAndTrace("Incorrect syntax in 'path' token for class '" + name + "': expected 2 entries, but got " + parts.Length + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mde.Path = path + "\\" + parts[1].Trim(splitter).Replace("/", "\\");
|
|
||||||
|
|
||||||
} else if (s.IndexOf("skin") != -1) {
|
|
||||||
if (parts.Length != 3) {
|
|
||||||
logAndTrace("Incorrect syntax in 'skin' token for class '" + name + "': expected 3 entries, but got " + parts.Length + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = int.Parse(parts[1].Trim(splitter), NumberStyles.Integer);
|
|
||||||
if (textureNames[index] != null) {
|
|
||||||
logAndTrace("Incorrect syntax in 'skin' token for class '" + name + "': already got skin with index " + index + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string textureName = parts[2].Trim(splitter);
|
|
||||||
string fileExt = Path.GetExtension(textureName);
|
|
||||||
textureNames[index] = Array.IndexOf(SUPPORTED_TEXTURE_EXTENSIONS, fileExt) == -1 ? INVALID_TEXTURE : textureName;
|
|
||||||
|
|
||||||
} else if (s.IndexOf("scale") != -1) {
|
|
||||||
if (parts.Length != 4) {
|
|
||||||
logAndTrace("Incorrect syntax in 'scale' token for class '" + name + "': expected 4 entries, but got " + parts.Length + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mde.Scale.X = float.Parse(parts[1], NumberStyles.Float);
|
|
||||||
mde.Scale.Y = float.Parse(parts[2], NumberStyles.Float);
|
|
||||||
mde.Scale.Z = float.Parse(parts[3], NumberStyles.Float);
|
|
||||||
|
|
||||||
} else if (s.IndexOf("zoffset") != -1) {
|
|
||||||
if (parts.Length != 2) {
|
|
||||||
logAndTrace("Incorrect syntax in 'zoffset' token for class '" + name + "': expected 2 entries, but got " + parts.Length + "!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mde.zOffset = float.Parse(parts[1], NumberStyles.Float);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ModelDefEntry_ToString(ModelDefEntry mde) {
|
|
||||||
string[] models = new string[mde.ModelNames.Count];
|
|
||||||
mde.ModelNames.CopyTo(models);
|
|
||||||
|
|
||||||
string[] textures = new string[mde.TextureNames.Count];
|
|
||||||
mde.TextureNames.CopyTo(textures);
|
|
||||||
|
|
||||||
return "Name: " + mde.Name + Environment.NewLine
|
|
||||||
+ "Path: " + mde.Path + Environment.NewLine
|
|
||||||
+ "Models: " + String.Join(", ", models) + Environment.NewLine
|
|
||||||
+ "Skins: " + String.Join(", ", textures) + Environment.NewLine
|
|
||||||
+ "Scale: " + mde.Scale + Environment.NewLine
|
|
||||||
+ "zOffset: " + mde.zOffset + Environment.NewLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string StripComments(string contents) {
|
|
||||||
int start, end;
|
|
||||||
|
|
||||||
//comments
|
|
||||||
while ((start = contents.IndexOf("//")) != -1) {
|
|
||||||
end = contents.IndexOf(Environment.NewLine, start);
|
|
||||||
contents = contents.Remove(start, end - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
//block comments
|
|
||||||
while ((start = contents.IndexOf("/*")) != -1) {
|
|
||||||
end = contents.IndexOf("*/");
|
|
||||||
contents = contents.Remove(start, end - start + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logAndTrace(string message) {
|
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, message);
|
|
||||||
General.WriteLogLine(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ using SlimDX.Direct3D9;
|
||||||
using CodeImp.DoomBuilder.Geometry;
|
using CodeImp.DoomBuilder.Geometry;
|
||||||
|
|
||||||
|
|
||||||
namespace ColladaDotNet.Pipeline.MD3
|
namespace CodeImp.DoomBuilder.GZBuilder.MD3
|
||||||
{
|
{
|
||||||
public class GZModel {
|
public class GZModel {
|
||||||
public List<Mesh> Meshes;
|
public List<Mesh> Meshes;
|
||||||
|
|
|
@ -5,83 +5,90 @@ using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using CodeImp.DoomBuilder;
|
using CodeImp.DoomBuilder;
|
||||||
|
using CodeImp.DoomBuilder.Data;
|
||||||
using CodeImp.DoomBuilder.Rendering;
|
using CodeImp.DoomBuilder.Rendering;
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
using CodeImp.DoomBuilder.GZBuilder.IO;
|
using CodeImp.DoomBuilder.GZBuilder.GZDoom;
|
||||||
|
|
||||||
using SlimDX;
|
using SlimDX;
|
||||||
using SlimDX.Direct3D9;
|
using SlimDX.Direct3D9;
|
||||||
|
|
||||||
//mxd. Original version taken from here: http://colladadotnet.codeplex.com/SourceControl/changeset/view/40680
|
//mxd. Original version taken from here: http://colladadotnet.codeplex.com/SourceControl/changeset/view/40680
|
||||||
namespace ColladaDotNet.Pipeline.MD3 {
|
namespace CodeImp.DoomBuilder.GZBuilder.MD3
|
||||||
public class ModelReader {
|
{
|
||||||
public static GZModel Parse(ModelDefEntry mde, Device D3DDevice) {
|
internal class ModelReader
|
||||||
string[] modelPaths = new string[mde.ModelNames.Count];
|
{
|
||||||
string[] texturePaths = new string[mde.TextureNames.Count];
|
public static void Parse(ref ModeldefEntry mde, PK3StructuredReader reader, Device D3DDevice) {
|
||||||
|
string[] modelNames = new string[mde.ModelNames.Count];
|
||||||
|
string[] textureNames = new string[mde.TextureNames.Count];
|
||||||
|
|
||||||
mde.ModelNames.CopyTo(modelPaths);
|
mde.ModelNames.CopyTo(modelNames);
|
||||||
mde.TextureNames.CopyTo(texturePaths);
|
mde.TextureNames.CopyTo(textureNames);
|
||||||
|
|
||||||
if (modelPaths.Length != texturePaths.Length || texturePaths.Length == 0 || modelPaths.Length == 0) {
|
//should never happen
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: wrong parse params! (modelPaths=" + modelPaths.ToString() + "; texturePaths=" + texturePaths.ToString() + ")");
|
/*if (modelNames.Length != textureNames.Length || textureNames.Length == 0 || modelNames.Length == 0) {
|
||||||
return null;
|
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: wrong parse params! (modelPaths=" + modelNames.ToString() + "; texturePaths=" + textureNames.ToString() + ")");
|
||||||
}
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
GZModel model = new GZModel();
|
mde.Model = new GZModel();
|
||||||
model.NUM_MESHES = (byte)modelPaths.Length;
|
mde.Model.NUM_MESHES = (byte)modelNames.Length;
|
||||||
|
|
||||||
BoundingBoxSizes bbs = new BoundingBoxSizes();
|
BoundingBoxSizes bbs = new BoundingBoxSizes();
|
||||||
|
|
||||||
for (int i = 0; i < modelPaths.Length; i++) {
|
for (int i = 0; i < modelNames.Length; i++) {
|
||||||
string modelPath = mde.Path + "\\" + modelPaths[i];
|
string modelPath = Path.Combine(mde.Path, modelNames[i]);
|
||||||
if (File.Exists(modelPath)) {
|
|
||||||
|
if (reader.FileExists(modelPath)) {
|
||||||
|
MemoryStream stream = reader.LoadFile(modelPath);
|
||||||
General.WriteLogLine("MD3Reader: loading '" + modelPath + "'");
|
General.WriteLogLine("MD3Reader: loading '" + modelPath + "'");
|
||||||
|
|
||||||
//mesh
|
//mesh
|
||||||
string ext = modelPaths[i].Substring(modelPaths[i].Length - 4);
|
string ext = modelNames[i].Substring(modelNames[i].Length - 4);
|
||||||
bool loaded = false;
|
string error = "";
|
||||||
if (ext == ".md3") {
|
if (ext == ".md3")
|
||||||
loaded = ReadMD3Model(ref bbs, mde, model, modelPath, D3DDevice);
|
error = ReadMD3Model(ref bbs, ref mde, stream, D3DDevice);
|
||||||
} else if (ext == ".md2") {
|
else if (ext == ".md2")
|
||||||
loaded = ReadMD2Model(ref bbs, mde, model, modelPath, D3DDevice);
|
error = ReadMD2Model(ref bbs, ref mde, stream, D3DDevice);
|
||||||
}
|
|
||||||
|
|
||||||
//texture
|
//texture
|
||||||
if (loaded) {
|
if (string.IsNullOrEmpty(error)) {
|
||||||
string texturePath = mde.Path + "\\" + texturePaths[i];
|
string texturePath = Path.Combine(mde.Path, textureNames[i]);
|
||||||
if (texturePaths[i] != ModelDefParser.INVALID_TEXTURE && File.Exists(texturePath)) {
|
|
||||||
model.Textures.Add(Texture.FromFile(D3DDevice, texturePath));
|
if (textureNames[i] != ModeldefParser.INVALID_TEXTURE && reader.FileExists(texturePath)) {
|
||||||
|
mde.Model.Textures.Add(Texture.FromStream(D3DDevice, reader.LoadFile(texturePath)));
|
||||||
} else {
|
} else {
|
||||||
model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
|
mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
|
||||||
if (texturePaths[i] != ModelDefParser.INVALID_TEXTURE)
|
if (textureNames[i] != ModeldefParser.INVALID_TEXTURE)
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: unable to load texture '" + texturePath + "' - no such file");
|
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: unable to load texture '" + texturePath + "' - no such file");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
model.NUM_MESHES--;
|
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: error while loading " + modelPath + ": " + error);
|
||||||
|
mde.Model.NUM_MESHES--;
|
||||||
}
|
}
|
||||||
|
stream.Dispose();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: unable to load model '" + mde.Path + "\\" + modelPaths[i] + "' - no such file");
|
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: unable to load model '" + modelPath + "' - no such file");
|
||||||
model.NUM_MESHES--;
|
mde.Model.NUM_MESHES--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.NUM_MESHES <= 0)
|
if (mde.Model.NUM_MESHES <= 0) {
|
||||||
return null;
|
mde.Model = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
|
mde.Model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ReadMD3Model(ref BoundingBoxSizes bbs, ModelDefEntry mde, GZModel model, string modelPath, Device D3DDevice) {
|
private static string ReadMD3Model(ref BoundingBoxSizes bbs, ref ModeldefEntry mde, MemoryStream s, Device D3DDevice) {
|
||||||
FileStream s = new FileStream(modelPath, FileMode.Open);
|
|
||||||
long start = s.Position;
|
long start = s.Position;
|
||||||
|
|
||||||
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
||||||
string magic = ReadString(br, 4);
|
string magic = ReadString(br, 4);
|
||||||
if (magic != "IDP3") {
|
if (magic != "IDP3")
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Magic should be 'IDP3', not '" + magic + "'");
|
return "magic should be 'IDP3', not '" + magic + "'";
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Position += 80;
|
s.Position += 80;
|
||||||
int numSurfaces = br.ReadInt32();
|
int numSurfaces = br.ReadInt32();
|
||||||
|
@ -94,8 +101,12 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
List<short> polyIndecesList = new List<short>();
|
List<short> polyIndecesList = new List<short>();
|
||||||
List<WorldVertex> vertList = new List<WorldVertex>();
|
List<WorldVertex> vertList = new List<WorldVertex>();
|
||||||
|
|
||||||
for (int c = 0; c < numSurfaces; ++c)
|
string error = "";
|
||||||
ReadSurface(ref bbs, br, polyIndecesList, vertList, mde);
|
for (int c = 0; c < numSurfaces; ++c) {
|
||||||
|
error = ReadSurface(ref bbs, br, polyIndecesList, vertList, mde);
|
||||||
|
if (!string.IsNullOrEmpty(error))
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
//indeces for rendering current mesh in 2d
|
//indeces for rendering current mesh in 2d
|
||||||
short[] indeces2d_arr = CreateLineListIndeces(polyIndecesList);
|
short[] indeces2d_arr = CreateLineListIndeces(polyIndecesList);
|
||||||
|
@ -112,7 +123,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
mesh.IndexBuffer.Unlock();
|
mesh.IndexBuffer.Unlock();
|
||||||
|
|
||||||
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
||||||
model.Meshes.Add(mesh);
|
mde.Model.Meshes.Add(mesh);
|
||||||
|
|
||||||
//2d data
|
//2d data
|
||||||
IndexBuffer indeces2d = new IndexBuffer(D3DDevice, 2 * indeces2d_arr.Length, Usage.WriteOnly, Pool.Managed, true);
|
IndexBuffer indeces2d = new IndexBuffer(D3DDevice, 2 * indeces2d_arr.Length, Usage.WriteOnly, Pool.Managed, true);
|
||||||
|
@ -120,19 +131,17 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
stream.WriteRange(indeces2d_arr);
|
stream.WriteRange(indeces2d_arr);
|
||||||
indeces2d.Unlock();
|
indeces2d.Unlock();
|
||||||
|
|
||||||
model.Indeces2D.Add(indeces2d);
|
mde.Model.Indeces2D.Add(indeces2d);
|
||||||
model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
mde.Model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
||||||
}
|
}
|
||||||
return true;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadSurface(ref BoundingBoxSizes bbs, BinaryReader br, List<short> polyIndecesList, List<WorldVertex> vertList, ModelDefEntry mde) {
|
private static string ReadSurface(ref BoundingBoxSizes bbs, BinaryReader br, List<short> polyIndecesList, List<WorldVertex> vertList, ModeldefEntry mde) {
|
||||||
var start = br.BaseStream.Position;
|
var start = br.BaseStream.Position;
|
||||||
string magic = ReadString(br, 4);
|
string magic = ReadString(br, 4);
|
||||||
if (magic != "IDP3") {
|
if (magic != "IDP3")
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while reading surface: Magic should be 'IDP3', not '" + magic + "'");
|
return "error while reading surface: Magic should be 'IDP3', not '" + magic + "'";
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
br.BaseStream.Position += 76;
|
br.BaseStream.Position += 76;
|
||||||
int numVerts = br.ReadInt32(); //Number of Vertex objects defined in this Surface, up to MD3_MAX_VERTS. Current value of MD3_MAX_VERTS is 4096.
|
int numVerts = br.ReadInt32(); //Number of Vertex objects defined in this Surface, up to MD3_MAX_VERTS. Current value of MD3_MAX_VERTS is 4096.
|
||||||
|
@ -170,9 +179,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
|
|
||||||
for (int i = 0; i < numVerts; i++) {
|
for (int i = 0; i < numVerts; i++) {
|
||||||
WorldVertex v = vertList[i];
|
WorldVertex v = vertList[i];
|
||||||
//short[] coords = new short[] { br.ReadInt16(), br.ReadInt16(), br.ReadInt16() };
|
|
||||||
|
|
||||||
//v.Position = new Vector3((float)coords[1] / 64, -(float)coords[0] / 64, (float)coords[2] / 64);
|
|
||||||
v.y = -(float)br.ReadInt16() / 64 * mde.Scale.X;
|
v.y = -(float)br.ReadInt16() / 64 * mde.Scale.X;
|
||||||
v.x = (float)br.ReadInt16() / 64 * mde.Scale.Y;
|
v.x = (float)br.ReadInt16() / 64 * mde.Scale.Y;
|
||||||
v.z = (float)br.ReadInt16() / 64 * mde.Scale.Z + mde.zOffset;
|
v.z = (float)br.ReadInt16() / 64 * mde.Scale.Z + mde.zOffset;
|
||||||
|
@ -192,23 +199,20 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
|
|
||||||
if (start + ofsEnd != br.BaseStream.Position)
|
if (start + ofsEnd != br.BaseStream.Position)
|
||||||
br.BaseStream.Position = start + ofsEnd;
|
br.BaseStream.Position = start + ofsEnd;
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ReadMD2Model(ref BoundingBoxSizes bbs, ModelDefEntry mde, GZModel model, string modelPath, Device D3DDevice) {
|
private static string ReadMD2Model(ref BoundingBoxSizes bbs, ref ModeldefEntry mde, MemoryStream s, Device D3DDevice) {
|
||||||
FileStream s = new FileStream(modelPath, FileMode.Open);
|
|
||||||
long start = s.Position;
|
long start = s.Position;
|
||||||
|
|
||||||
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
||||||
string magic = ReadString(br, 4);
|
string magic = ReadString(br, 4);
|
||||||
if (magic != "IDP2") { //magic number: "IDP2"
|
if (magic != "IDP2") //magic number: "IDP2"
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Magic should be 'IDP2', not '" + magic + "'");
|
return "magic should be 'IDP2', not '" + magic + "'";
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int modelVersion = br.ReadInt32();
|
int modelVersion = br.ReadInt32();
|
||||||
if (modelVersion != 8) { //MD2 version. Must be equal to 8
|
if (modelVersion != 8) //MD2 version. Must be equal to 8
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': MD2 version must be 8 but is " + modelVersion);
|
return "MD2 version must be 8 but is " + modelVersion;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int texWidth = br.ReadInt32();
|
int texWidth = br.ReadInt32();
|
||||||
int texHeight = br.ReadInt32();
|
int texHeight = br.ReadInt32();
|
||||||
|
@ -219,10 +223,8 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
int num_tris = br.ReadInt32(); //Number of triangles
|
int num_tris = br.ReadInt32(); //Number of triangles
|
||||||
s.Position += 4; //Number of OpenGL commands
|
s.Position += 4; //Number of OpenGL commands
|
||||||
|
|
||||||
if (br.ReadInt32() == 0) { //Total number of frames
|
if (br.ReadInt32() == 0) //Total number of frames
|
||||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Model has 0 frames");
|
return "model has 0 frames";
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Position += 4; //Offset to skin names (each skin name is an unsigned char[64] and are null terminated)
|
s.Position += 4; //Offset to skin names (each skin name is an unsigned char[64] and are null terminated)
|
||||||
int ofs_uv = br.ReadInt32();//Offset to s-t texture coordinates
|
int ofs_uv = br.ReadInt32();//Offset to s-t texture coordinates
|
||||||
|
@ -284,7 +286,6 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
WorldVertex v = vertList[polyIndecesList[i]];
|
WorldVertex v = vertList[polyIndecesList[i]];
|
||||||
|
|
||||||
//bounding box
|
//bounding box
|
||||||
//BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, v);
|
|
||||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, new WorldVertex(v.y, v.x, v.z));
|
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, new WorldVertex(v.y, v.x, v.z));
|
||||||
|
|
||||||
//uv
|
//uv
|
||||||
|
@ -309,7 +310,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
mesh.IndexBuffer.Unlock();
|
mesh.IndexBuffer.Unlock();
|
||||||
|
|
||||||
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
||||||
model.Meshes.Add(mesh);
|
mde.Model.Meshes.Add(mesh);
|
||||||
|
|
||||||
//2d data
|
//2d data
|
||||||
IndexBuffer indeces2d = new IndexBuffer(D3DDevice, 2 * indeces2d_arr.Length, Usage.WriteOnly, Pool.Managed, true);
|
IndexBuffer indeces2d = new IndexBuffer(D3DDevice, 2 * indeces2d_arr.Length, Usage.WriteOnly, Pool.Managed, true);
|
||||||
|
@ -317,12 +318,11 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
stream.WriteRange(indeces2d_arr);
|
stream.WriteRange(indeces2d_arr);
|
||||||
indeces2d.Unlock();
|
indeces2d.Unlock();
|
||||||
|
|
||||||
model.Indeces2D.Add(indeces2d);
|
mde.Model.Indeces2D.Add(indeces2d);
|
||||||
model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
mde.Model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
||||||
model.Angle = -90.0f * (float)Math.PI / 180.0f;
|
mde.Model.Angle = -90.0f * (float)Math.PI / 180.0f;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
//this creates list of vertex indeces for rendering using LineList method
|
//this creates list of vertex indeces for rendering using LineList method
|
||||||
|
@ -344,41 +344,6 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
||||||
return indeces2d_arr;
|
return indeces2d_arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this creates array of vectors resembling bounding box
|
|
||||||
/*private static Vector3[] CalculateBoundingBox(BoundingBoxSizes bbs) {
|
|
||||||
//center
|
|
||||||
Vector3 v0 = new Vector3(bbs.MinX + (bbs.MaxX - bbs.MinX) / 2, bbs.MinY + (bbs.MaxY - bbs.MinY) / 2, bbs.MinZ + (bbs.MaxZ - bbs.MinZ) / 2);
|
|
||||||
|
|
||||||
//corners
|
|
||||||
Vector3 v1 = new Vector3(bbs.MinX, bbs.MinY, bbs.MinZ);
|
|
||||||
Vector3 v2 = new Vector3(bbs.MaxX, bbs.MinY, bbs.MinZ);
|
|
||||||
Vector3 v3 = new Vector3(bbs.MinX, bbs.MaxY, bbs.MinZ);
|
|
||||||
Vector3 v4 = new Vector3(bbs.MaxX, bbs.MaxY, bbs.MinZ);
|
|
||||||
Vector3 v5 = new Vector3(bbs.MinX, bbs.MinY, bbs.MaxZ);
|
|
||||||
Vector3 v6 = new Vector3(bbs.MaxX, bbs.MinY, bbs.MaxZ);
|
|
||||||
Vector3 v7 = new Vector3(bbs.MinX, bbs.MaxY, bbs.MaxZ);
|
|
||||||
Vector3 v8 = new Vector3(bbs.MaxX, bbs.MaxY, bbs.MaxZ);
|
|
||||||
|
|
||||||
return new Vector3[] { v0, v1, v2, v3, v4, v5, v6, v7, v8 };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateBoundingBoxSizes(ref BoundingBoxSizes bbs, WorldVertex v) {
|
|
||||||
if (v.x < bbs.MinX)
|
|
||||||
bbs.MinX = (short)v.x;
|
|
||||||
else if (v.x > bbs.MaxX)
|
|
||||||
bbs.MaxX = (short)v.x;
|
|
||||||
|
|
||||||
if (v.z < bbs.MinZ)
|
|
||||||
bbs.MinZ = (short)v.z;
|
|
||||||
else if (v.z > bbs.MaxZ)
|
|
||||||
bbs.MaxZ = (short)v.z;
|
|
||||||
|
|
||||||
if (v.y < bbs.MinY)
|
|
||||||
bbs.MinY = (short)v.y;
|
|
||||||
else if (v.y > bbs.MaxY)
|
|
||||||
bbs.MaxY = (short)v.y;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private static string ReadString(BinaryReader br, int len) {
|
private static string ReadString(BinaryReader br, int len) {
|
||||||
var NAME = string.Empty;
|
var NAME = string.Empty;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
|
@ -286,6 +286,9 @@ namespace CodeImp.DoomBuilder
|
||||||
map.UpdateConfiguration();
|
map.UpdateConfiguration();
|
||||||
map.Update();
|
map.Update();
|
||||||
thingsfilter.Update();
|
thingsfilter.Update();
|
||||||
|
|
||||||
|
//mxd. load models
|
||||||
|
data.LoadModels();
|
||||||
|
|
||||||
// Bind any methods
|
// Bind any methods
|
||||||
General.Actions.BindMethods(this);
|
General.Actions.BindMethods(this);
|
||||||
|
@ -409,6 +412,9 @@ namespace CodeImp.DoomBuilder
|
||||||
map.SnapAllToAccuracy();
|
map.SnapAllToAccuracy();
|
||||||
map.Update();
|
map.Update();
|
||||||
thingsfilter.Update();
|
thingsfilter.Update();
|
||||||
|
|
||||||
|
//mxd. load models
|
||||||
|
data.LoadModels();
|
||||||
|
|
||||||
// Bind any methods
|
// Bind any methods
|
||||||
General.Actions.BindMethods(this);
|
General.Actions.BindMethods(this);
|
||||||
|
|
|
@ -365,7 +365,7 @@ namespace CodeImp.DoomBuilder.IO
|
||||||
// This finds a lump by name, returns -1 when not found
|
// This finds a lump by name, returns -1 when not found
|
||||||
public int FindLumpIndex(string name, int start, int end)
|
public int FindLumpIndex(string name, int start, int end)
|
||||||
{
|
{
|
||||||
byte[] fixedname;
|
//byte[] fixedname;
|
||||||
long longname = Lump.MakeLongName(name);
|
long longname = Lump.MakeLongName(name);
|
||||||
|
|
||||||
// Fix end when it exceeds length
|
// Fix end when it exceeds length
|
||||||
|
@ -375,7 +375,7 @@ namespace CodeImp.DoomBuilder.IO
|
||||||
name = name.ToUpperInvariant();
|
name = name.ToUpperInvariant();
|
||||||
|
|
||||||
// Make fixed name
|
// Make fixed name
|
||||||
fixedname = Lump.MakeFixedName(name, ENCODING);
|
//fixedname = Lump.MakeFixedName(name, ENCODING);
|
||||||
|
|
||||||
// Loop through the lumps
|
// Loop through the lumps
|
||||||
for(int i = start; i <= end; i++)
|
for(int i = start; i <= end; i++)
|
||||||
|
|
|
@ -37,7 +37,7 @@ using CodeImp.DoomBuilder.Editing;
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
using ColladaDotNet.Pipeline.MD3;
|
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -943,7 +943,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
{
|
{
|
||||||
//mxd. Collect things with models for rendering
|
//mxd. Collect things with models for rendering
|
||||||
if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected)) {
|
if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected)) {
|
||||||
Dictionary<int, ModelDefEntry> mde = GZBuilder.GZGeneral.ModelDefEntries;
|
Dictionary<int, ModeldefEntry> mde = General.Map.Data.ModeldefEntries;
|
||||||
if (mde != null && mde.ContainsKey(t.Type)) {
|
if (mde != null && mde.ContainsKey(t.Type)) {
|
||||||
thingsWithModel[screenpos] = t;
|
thingsWithModel[screenpos] = t;
|
||||||
}
|
}
|
||||||
|
@ -1119,12 +1119,12 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
|
|
||||||
graphics.Shaders.Things2D.BeginPass(1);
|
graphics.Shaders.Things2D.BeginPass(1);
|
||||||
foreach(KeyValuePair<Vector2D, Thing> group in thingsWithModel){
|
foreach(KeyValuePair<Vector2D, Thing> group in thingsWithModel){
|
||||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[group.Value.Type];
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[group.Value.Type];
|
||||||
|
|
||||||
if (mde.Model != null)
|
if (mde.Model != null)
|
||||||
RenderModel(mde.Model, group.Key, group.Value.Angle + mde.Model.Angle, group.Value.Selected);
|
RenderModel(mde.Model, group.Key, group.Value.Angle + mde.Model.Angle, group.Value.Selected);
|
||||||
else
|
else
|
||||||
group.Value.IsModel = GZBuilder.GZGeneral.LoadModelForThing(group.Value);
|
group.Value.IsModel = General.Map.Data.LoadModelForThing(group.Value);
|
||||||
}
|
}
|
||||||
graphics.Shaders.Things2D.EndPass();
|
graphics.Shaders.Things2D.EndPass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ using CodeImp.DoomBuilder.VisualModes;
|
||||||
using CodeImp.DoomBuilder.Map;
|
using CodeImp.DoomBuilder.Map;
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
using ColladaDotNet.Pipeline.MD3;
|
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -81,7 +81,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
private List<VisualThing> thingsWithLight;
|
private List<VisualThing> thingsWithLight;
|
||||||
private int[] lightOffsets;
|
private int[] lightOffsets;
|
||||||
private Dictionary<Texture, List<VisualGeometry>> litGeometry;
|
private Dictionary<Texture, List<VisualGeometry>> litGeometry;
|
||||||
private Dictionary<ModelDefEntry, List<VisualThing>> thingsWithModel;
|
private Dictionary<ModeldefEntry, List<VisualThing>> thingsWithModel;
|
||||||
//dbg
|
//dbg
|
||||||
//int geoSkipped = 0;
|
//int geoSkipped = 0;
|
||||||
//int totalGeo = 0;
|
//int totalGeo = 0;
|
||||||
|
@ -499,7 +499,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
things = new Dictionary<ImageData, List<VisualThing>>[RENDER_PASSES];
|
things = new Dictionary<ImageData, List<VisualThing>>[RENDER_PASSES];
|
||||||
thingsbydistance = new BinaryHeap<VisualThing>();
|
thingsbydistance = new BinaryHeap<VisualThing>();
|
||||||
//mxd
|
//mxd
|
||||||
thingsWithModel = new Dictionary<ModelDefEntry, List<VisualThing>>();
|
thingsWithModel = new Dictionary<ModeldefEntry, List<VisualThing>>();
|
||||||
litGeometry = new Dictionary<Texture, List<VisualGeometry>>();
|
litGeometry = new Dictionary<Texture, List<VisualGeometry>>();
|
||||||
|
|
||||||
for(int i = 0; i < RENDER_PASSES; i++)
|
for(int i = 0; i < RENDER_PASSES; i++)
|
||||||
|
@ -1003,15 +1003,14 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
|
|
||||||
//mxd. render models
|
//mxd. render models
|
||||||
private void RenderModels() {
|
private void RenderModels() {
|
||||||
int shaderpass = 4;
|
int shaderpass = fullbrightness ? 1 : 4;
|
||||||
if (fullbrightness) shaderpass++;
|
|
||||||
int currentshaderpass = shaderpass;
|
int currentshaderpass = shaderpass;
|
||||||
int highshaderpass = shaderpass + 2;
|
int highshaderpass = shaderpass + 2;
|
||||||
|
|
||||||
// Begin rendering with this shader
|
// Begin rendering with this shader
|
||||||
graphics.Shaders.World3D.BeginPass(currentshaderpass);
|
graphics.Shaders.World3D.BeginPass(currentshaderpass);
|
||||||
|
|
||||||
foreach (KeyValuePair<ModelDefEntry, List<VisualThing>> group in thingsWithModel) {
|
foreach (KeyValuePair<ModeldefEntry, List<VisualThing>> group in thingsWithModel) {
|
||||||
foreach (VisualThing t in group.Value) {
|
foreach (VisualThing t in group.Value) {
|
||||||
Color4 vertexColor = new Color4(t.VertexColor);
|
Color4 vertexColor = new Color4(t.VertexColor);
|
||||||
vertexColor.Alpha = 1.0f;
|
vertexColor.Alpha = 1.0f;
|
||||||
|
@ -1177,7 +1176,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
}
|
}
|
||||||
//mxd. gather models
|
//mxd. gather models
|
||||||
} else if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected) && t.Thing.IsModel) {
|
} else if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected) && t.Thing.IsModel) {
|
||||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[t.Thing.Type];
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[t.Thing.Type];
|
||||||
|
|
||||||
if (!isThingOnScreen(t.BoundingBox))
|
if (!isThingOnScreen(t.BoundingBox))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -792,7 +792,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
if (refreshSelection || selectedVisualThings == null) {
|
if (refreshSelection || selectedVisualThings == null) {
|
||||||
selectedVisualThings = new List<VisualThing>();
|
selectedVisualThings = new List<VisualThing>();
|
||||||
foreach (KeyValuePair<Thing, VisualThing> group in allthings) {
|
foreach (KeyValuePair<Thing, VisualThing> group in allthings) {
|
||||||
if (group.Value.Selected)
|
if (group.Value != null && group.Value.Selected)
|
||||||
selectedVisualThings.Add(group.Value);
|
selectedVisualThings.Add(group.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,9 +93,6 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
private Vector3 position_v3;
|
private Vector3 position_v3;
|
||||||
private float lightDelta; //used in light animation
|
private float lightDelta; //used in light animation
|
||||||
private Vector3[] boundingBox;
|
private Vector3[] boundingBox;
|
||||||
|
|
||||||
//mxd. model
|
|
||||||
private bool checkedIfModel;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -202,7 +199,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ================== Methods
|
#region ================== Methods
|
||||||
|
|
||||||
// This sets the distance from the camera
|
// This sets the distance from the camera
|
||||||
internal void CalculateCameraDistance(Vector2D campos)
|
internal void CalculateCameraDistance(Vector2D campos)
|
||||||
{
|
{
|
||||||
|
@ -222,7 +219,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
if(geobuffer != null) geobuffer.Dispose();
|
if(geobuffer != null) geobuffer.Dispose();
|
||||||
geobuffer = null;
|
geobuffer = null;
|
||||||
updategeo = true;
|
updategeo = true;
|
||||||
checkedIfModel = false;
|
//checkedIfModel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called resets when the device is reset
|
// This is called resets when the device is reset
|
||||||
|
@ -295,19 +292,15 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
// Do we need to update the geometry buffer?
|
// Do we need to update the geometry buffer?
|
||||||
if (updategeo)
|
if (updategeo)
|
||||||
{
|
{
|
||||||
//mxd
|
//mxd. check if thing is model
|
||||||
if (!checkedIfModel) {
|
if (General.Map.Data.ModeldefEntries.ContainsKey(thing.Type)) {
|
||||||
//check if thing is model
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[thing.Type];
|
||||||
if (GZBuilder.GZGeneral.ModelDefEntries.ContainsKey(thing.Type)) {
|
if (mde.Model == null)
|
||||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[thing.Type];
|
thing.IsModel = General.Map.Data.LoadModelForThing(thing);
|
||||||
if (mde.Model == null)
|
else
|
||||||
thing.IsModel = GZBuilder.GZGeneral.LoadModelForThing(thing);
|
thing.IsModel = true;
|
||||||
else
|
} else {
|
||||||
thing.IsModel = true;
|
thing.IsModel = false;
|
||||||
}
|
|
||||||
if (thing.IsModel)
|
|
||||||
updateBoundingBoxForModel();
|
|
||||||
checkedIfModel = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trash geometry buffer
|
// Trash geometry buffer
|
||||||
|
@ -474,7 +467,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
|
|
||||||
//mxd. update bounding box from model bounding box
|
//mxd. update bounding box from model bounding box
|
||||||
private void updateBoundingBoxForModel() {
|
private void updateBoundingBoxForModel() {
|
||||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[thing.Type];
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[thing.Type];
|
||||||
int len = mde.Model.BoundingBox.Length;
|
int len = mde.Model.BoundingBox.Length;
|
||||||
boundingBox = new Vector3[len];
|
boundingBox = new Vector3[len];
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
||||||
public DecorateParser()
|
public DecorateParser()
|
||||||
{
|
{
|
||||||
// Syntax
|
// Syntax
|
||||||
whitespace = "\n \t\r";
|
whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
|
||||||
specialtokens = ":{}+-\n;,";
|
specialtokens = ":{}+-\n;,";
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
||||||
public TexturesParser()
|
public TexturesParser()
|
||||||
{
|
{
|
||||||
// Syntax
|
// Syntax
|
||||||
whitespace = "\n \t\r";
|
whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
|
||||||
specialtokens = ",{}\n";
|
specialtokens = ",{}\n";
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
||||||
#region ================== Variables
|
#region ================== Variables
|
||||||
|
|
||||||
// Parsing
|
// Parsing
|
||||||
protected string whitespace = "\n \t\r";
|
protected string whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
|
||||||
protected string specialtokens = ":{}+-\n;";
|
protected string specialtokens = ":{}+-\n;";
|
||||||
|
|
||||||
// Input data stream
|
// Input data stream
|
||||||
|
@ -297,7 +297,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
||||||
// This reports an error
|
// This reports an error
|
||||||
protected internal void ReportError(string message)
|
protected internal void ReportError(string message)
|
||||||
{
|
{
|
||||||
long position = datastream.Position;
|
/*long position = datastream.Position;
|
||||||
long readpos = 0;
|
long readpos = 0;
|
||||||
int linenumber = 1;
|
int linenumber = 1;
|
||||||
|
|
||||||
|
@ -313,13 +313,35 @@ namespace CodeImp.DoomBuilder.ZDoom
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return to original position
|
// Return to original position
|
||||||
datastream.Seek(position, SeekOrigin.Begin);
|
datastream.Seek(position, SeekOrigin.Begin);*/
|
||||||
|
|
||||||
// Set error information
|
// Set error information
|
||||||
errordesc = message;
|
errordesc = message;
|
||||||
errorline = linenumber;
|
errorline = GetCurrentLineNumber();
|
||||||
errorsource = sourcename;
|
errorsource = sourcename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
protected internal int GetCurrentLineNumber() {
|
||||||
|
long position = datastream.Position;
|
||||||
|
long readpos = 0;
|
||||||
|
int linenumber = 1;
|
||||||
|
|
||||||
|
// Find the line on which we found this error
|
||||||
|
datastream.Seek(0, SeekOrigin.Begin);
|
||||||
|
StreamReader textreader = new StreamReader(datastream, Encoding.ASCII);
|
||||||
|
while (readpos < position) {
|
||||||
|
string line = textreader.ReadLine();
|
||||||
|
if (line == null) break;
|
||||||
|
readpos += line.Length + 2;
|
||||||
|
linenumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to original position
|
||||||
|
datastream.Seek(position, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return linenumber;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ using CodeImp.DoomBuilder.VisualModes;
|
||||||
using CodeImp.DoomBuilder.Config;
|
using CodeImp.DoomBuilder.Config;
|
||||||
using CodeImp.DoomBuilder.Data;
|
using CodeImp.DoomBuilder.Data;
|
||||||
|
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.BuilderModes
|
namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
|
@ -200,6 +202,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
pos.z = Thing.Sector.CeilHeight - info.Height;
|
pos.z = Thing.Sector.CeilHeight - info.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd. check model state
|
||||||
|
if (General.Map.Data.ModeldefEntries.ContainsKey(Thing.Type)) {
|
||||||
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[Thing.Type];
|
||||||
|
if (mde.Model == null) {
|
||||||
|
Thing.IsModel = General.Map.Data.LoadModelForThing(Thing);
|
||||||
|
} else {
|
||||||
|
Thing.IsModel = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Thing.IsModel = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply settings
|
// Apply settings
|
||||||
SetPosition(pos);
|
SetPosition(pos);
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
<ProjectReference Include="..\..\Core\Builder.csproj">
|
<ProjectReference Include="..\..\Core\Builder.csproj">
|
||||||
<Project>{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}</Project>
|
<Project>{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}</Project>
|
||||||
<Name>Builder</Name>
|
<Name>Builder</Name>
|
||||||
|
<Private>False</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -34,6 +34,8 @@ using CodeImp.DoomBuilder.VisualModes;
|
||||||
using CodeImp.DoomBuilder.Config;
|
using CodeImp.DoomBuilder.Config;
|
||||||
using CodeImp.DoomBuilder.Data;
|
using CodeImp.DoomBuilder.Data;
|
||||||
|
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||||
|
@ -236,6 +238,18 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||||
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mxd. check model state
|
||||||
|
if (General.Map.Data.ModeldefEntries.ContainsKey(Thing.Type)) {
|
||||||
|
ModeldefEntry mde = General.Map.Data.ModeldefEntries[Thing.Type];
|
||||||
|
if (mde.Model == null) {
|
||||||
|
Thing.IsModel = General.Map.Data.LoadModelForThing(Thing);
|
||||||
|
} else {
|
||||||
|
Thing.IsModel = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Thing.IsModel = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply settings
|
// Apply settings
|
||||||
SetPosition(pos);
|
SetPosition(pos);
|
||||||
|
|
Loading…
Reference in a new issue