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:
MaxED 2012-05-21 23:51:32 +00:00
parent 9a72148ad1
commit 3a0426cd7f
28 changed files with 707 additions and 491 deletions

View file

@ -367,7 +367,7 @@ powerups
title = "Invisibility"; title = "Invisibility";
sprite = "PINSA0"; sprite = "PINSA0";
height = 45; height = 45;
class = "BlurSphere "; class = "BlurSphere";
} }
2025 2025
{ {

View file

@ -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" />

View file

@ -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

View file

@ -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)
{ {

View file

@ -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
} }
} }

View file

@ -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)));
} }

View file

@ -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;
} }
} }

View file

@ -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!

View file

@ -816,7 +816,6 @@ namespace CodeImp.DoomBuilder.Data
return streams; return streams;
} }
#endregion #endregion
} }
} }

View file

@ -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();
}
}
} }
} }

View 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;
}
}
}

View 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;
}
}
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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++)

View file

@ -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();
} }

View file

@ -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;

View file

@ -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);
} }
} }

View file

@ -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++) {

View file

@ -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

View file

@ -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

View file

@ -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
} }

View file

@ -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);

View file

@ -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>

View file

@ -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);