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";
|
||||
sprite = "PINSA0";
|
||||
height = 45;
|
||||
class = "BlurSphere ";
|
||||
class = "BlurSphere";
|
||||
}
|
||||
2025
|
||||
{
|
||||
|
|
|
@ -713,10 +713,11 @@
|
|||
</Compile>
|
||||
<Compile Include="GZBuilder\Data\BoundingBox.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\GZDoom\ModeldefParser.cs" />
|
||||
<Compile Include="GZBuilder\GZDoom\ModeldefStructure.cs" />
|
||||
<Compile Include="GZBuilder\GZGeneral.cs" />
|
||||
<Compile Include="GZBuilder\IO\ModelDefParser.cs" />
|
||||
<Compile Include="GZBuilder\md3\GZModel.cs" />
|
||||
<Compile Include="GZBuilder\md3\ModelReader.cs" />
|
||||
<Compile Include="IO\DoomColormapReader.cs" />
|
||||
|
|
|
@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 10.00
|
|||
# Visual C# Express 2008
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPicker", "..\Plugins\ColorPicker\ColorPicker.csproj", "{A4761900-0EA3-4FE4-A919-847FD5080EFC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -33,6 +33,10 @@ using CodeImp.DoomBuilder.Map;
|
|||
using CodeImp.DoomBuilder.Windows;
|
||||
using CodeImp.DoomBuilder.ZDoom;
|
||||
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using CodeImp.DoomBuilder.GZBuilder.GZDoom;
|
||||
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.Data
|
||||
|
@ -65,7 +69,10 @@ namespace CodeImp.DoomBuilder.Data
|
|||
private AllTextureSet alltextures;
|
||||
|
||||
//mxd Folders
|
||||
private List<string> folders;
|
||||
//private List<string> folders;
|
||||
|
||||
//mxd modeldefs
|
||||
private Dictionary<int, ModeldefEntry> modeldefEntries;
|
||||
|
||||
// Background loading
|
||||
private Queue<ImageData> imageque;
|
||||
|
@ -107,7 +114,8 @@ namespace CodeImp.DoomBuilder.Data
|
|||
#region ================== Properties
|
||||
|
||||
//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 PreviewManager Previews { get { return previews; } }
|
||||
|
@ -247,9 +255,6 @@ namespace CodeImp.DoomBuilder.Data
|
|||
internalsprites = new Dictionary<string, ImageData>();
|
||||
thingcategories = General.Map.Config.GetThingCategories();
|
||||
thingtypes = General.Map.Config.GetThingTypes();
|
||||
|
||||
//mxd
|
||||
folders = new List<string>();
|
||||
|
||||
// Load texture sets
|
||||
foreach(DefinedTextureSet ts in General.Map.ConfigSettings.TextureSets)
|
||||
|
@ -285,10 +290,6 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// Directory container
|
||||
case DataLocation.RESOURCE_DIRECTORY:
|
||||
c = new DirectoryReader(dl);
|
||||
|
||||
//mxd
|
||||
folders.Add(dl.location);
|
||||
|
||||
break;
|
||||
|
||||
// PK3 file container
|
||||
|
@ -322,6 +323,9 @@ namespace CodeImp.DoomBuilder.Data
|
|||
thingcount = LoadDecorateThings();
|
||||
spritecount = LoadThingSprites();
|
||||
LoadInternalSprites();
|
||||
|
||||
//mxd
|
||||
loadModeldefs();
|
||||
|
||||
// Process colormaps (we just put them in as textures)
|
||||
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 sprites) i.Value.Dispose();
|
||||
palette = null;
|
||||
|
||||
//mxd
|
||||
if (modeldefEntries != null) {
|
||||
foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries) {
|
||||
group.Value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose containers
|
||||
foreach(DataReader c in containers) c.Dispose();
|
||||
|
@ -1342,10 +1353,110 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
#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
|
||||
internal bool FindFirstIWAD(out DataLocation result)
|
||||
{
|
||||
|
|
|
@ -156,6 +156,13 @@ namespace CodeImp.DoomBuilder.Data
|
|||
// When implemented, this returns the decorate lump
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
// This returns true if the specified file exists
|
||||
protected override bool FileExists(string filename)
|
||||
public override bool FileExists(string filename)
|
||||
{
|
||||
return files.FileExists(filename);
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
|
||||
// This loads an entire file in memory and returns 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)));
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
// This returns true if the specified file exists
|
||||
protected override bool FileExists(string filename)
|
||||
public override bool FileExists(string filename)
|
||||
{
|
||||
return files.FileExists(filename);
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ namespace CodeImp.DoomBuilder.Data
|
|||
|
||||
// This loads an entire file in memory and returns 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;
|
||||
byte[] copybuffer = new byte[4096];
|
||||
|
@ -359,7 +359,10 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
else
|
||||
{
|
||||
return filedata;
|
||||
//mxd. rewind before use
|
||||
filedata.Position = 0;
|
||||
|
||||
return filedata;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -417,10 +417,32 @@ namespace CodeImp.DoomBuilder.Data
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This loads the images in this directory
|
||||
|
||||
#region ================== Modeldef
|
||||
|
||||
//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)
|
||||
{
|
||||
List<ImageData> images = new List<ImageData>();
|
||||
|
@ -466,7 +488,8 @@ namespace CodeImp.DoomBuilder.Data
|
|||
protected abstract ImageData CreateImage(string name, string filename, int imagetype);
|
||||
|
||||
// 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
|
||||
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
|
||||
// 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
|
||||
// NOTE: Callers are responsible for removing the temp file when done!
|
||||
|
|
|
@ -816,7 +816,6 @@ namespace CodeImp.DoomBuilder.Data
|
|||
|
||||
return streams;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,27 +5,39 @@ using System.Text;
|
|||
using SlimDX;
|
||||
using SlimDX.Direct3D9;
|
||||
|
||||
using ColladaDotNet.Pipeline.MD3;
|
||||
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZBuilder.Data
|
||||
{
|
||||
public class ModelDefEntry
|
||||
public class ModeldefEntry
|
||||
{
|
||||
public string Name;
|
||||
public string Path;
|
||||
public string ClassName;
|
||||
public string Path; //this holds Path parameter of MODELDEF entry
|
||||
public List<string> ModelNames;
|
||||
public List<string> TextureNames;
|
||||
public string Location; //this holds location of resource, from which modeldef was loaded
|
||||
|
||||
public GZModel Model;
|
||||
|
||||
public Vector3 Scale;
|
||||
public float zOffset;
|
||||
|
||||
public ModelDefEntry() {
|
||||
Scale = new Vector3(1, 1, 1);
|
||||
zOffset = 0;
|
||||
public ModeldefEntry() {
|
||||
ModelNames = 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.Config;
|
||||
|
||||
using CodeImp.DoomBuilder.GZBuilder.IO;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Controls;
|
||||
|
||||
using ColladaDotNet.Pipeline.MD3;
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZBuilder
|
||||
{
|
||||
//mxd. should get rid of this class one day...
|
||||
public class GZGeneral
|
||||
{
|
||||
private static Dictionary<int, ModelDefEntry> modelDefEntries; //doomEdNum, entry
|
||||
public static Dictionary<int, ModelDefEntry> ModelDefEntries { get { return modelDefEntries; } }
|
||||
|
||||
//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};
|
||||
public static int[] GZ_LIGHTS { get { return gzLights; } }
|
||||
|
@ -34,6 +28,8 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
|||
|
||||
public static bool UDMF;
|
||||
|
||||
//public static float[] FogTable; // light to fog conversion table for black fog
|
||||
|
||||
//version
|
||||
public const float Version = 1.06f;
|
||||
|
||||
|
@ -48,6 +44,26 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
|||
General.Actions.BindMethods(typeof(GZGeneral));
|
||||
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
|
||||
#if DEBUG
|
||||
ConsoleDocker cd = new ConsoleDocker();
|
||||
|
@ -58,105 +74,25 @@ namespace CodeImp.DoomBuilder.GZBuilder
|
|||
}
|
||||
|
||||
public static void OnMapOpenEnd() {
|
||||
loadModelDefs();
|
||||
loadModels();
|
||||
UDMF = (General.Map.Config.FormatInterface == "UniversalMapSetIO");
|
||||
General.MainWindow.UpdateGZDoomPannel();
|
||||
}
|
||||
|
||||
public static void OnReloadResources() {
|
||||
loadModelDefs();
|
||||
loadModels();
|
||||
|
||||
#if DEBUG
|
||||
((ConsoleDocker)console.Control).Clear();
|
||||
#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
|
||||
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) {
|
||||
#if DEBUG
|
||||
((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;
|
||||
|
||||
|
||||
namespace ColladaDotNet.Pipeline.MD3
|
||||
namespace CodeImp.DoomBuilder.GZBuilder.MD3
|
||||
{
|
||||
public class GZModel {
|
||||
public List<Mesh> Meshes;
|
||||
|
|
|
@ -5,83 +5,90 @@ using System.Text;
|
|||
using System.Collections.Generic;
|
||||
|
||||
using CodeImp.DoomBuilder;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using CodeImp.DoomBuilder.GZBuilder.IO;
|
||||
using CodeImp.DoomBuilder.GZBuilder.GZDoom;
|
||||
|
||||
using SlimDX;
|
||||
using SlimDX.Direct3D9;
|
||||
|
||||
//mxd. Original version taken from here: http://colladadotnet.codeplex.com/SourceControl/changeset/view/40680
|
||||
namespace ColladaDotNet.Pipeline.MD3 {
|
||||
public class ModelReader {
|
||||
public static GZModel Parse(ModelDefEntry mde, Device D3DDevice) {
|
||||
string[] modelPaths = new string[mde.ModelNames.Count];
|
||||
string[] texturePaths = new string[mde.TextureNames.Count];
|
||||
namespace CodeImp.DoomBuilder.GZBuilder.MD3
|
||||
{
|
||||
internal class ModelReader
|
||||
{
|
||||
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.TextureNames.CopyTo(texturePaths);
|
||||
mde.ModelNames.CopyTo(modelNames);
|
||||
mde.TextureNames.CopyTo(textureNames);
|
||||
|
||||
if (modelPaths.Length != texturePaths.Length || texturePaths.Length == 0 || modelPaths.Length == 0) {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: wrong parse params! (modelPaths=" + modelPaths.ToString() + "; texturePaths=" + texturePaths.ToString() + ")");
|
||||
return null;
|
||||
}
|
||||
//should never happen
|
||||
/*if (modelNames.Length != textureNames.Length || textureNames.Length == 0 || modelNames.Length == 0) {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: wrong parse params! (modelPaths=" + modelNames.ToString() + "; texturePaths=" + textureNames.ToString() + ")");
|
||||
return;
|
||||
}*/
|
||||
|
||||
GZModel model = new GZModel();
|
||||
model.NUM_MESHES = (byte)modelPaths.Length;
|
||||
mde.Model = new GZModel();
|
||||
mde.Model.NUM_MESHES = (byte)modelNames.Length;
|
||||
|
||||
BoundingBoxSizes bbs = new BoundingBoxSizes();
|
||||
|
||||
for (int i = 0; i < modelPaths.Length; i++) {
|
||||
string modelPath = mde.Path + "\\" + modelPaths[i];
|
||||
if (File.Exists(modelPath)) {
|
||||
for (int i = 0; i < modelNames.Length; i++) {
|
||||
string modelPath = Path.Combine(mde.Path, modelNames[i]);
|
||||
|
||||
if (reader.FileExists(modelPath)) {
|
||||
MemoryStream stream = reader.LoadFile(modelPath);
|
||||
General.WriteLogLine("MD3Reader: loading '" + modelPath + "'");
|
||||
|
||||
//mesh
|
||||
string ext = modelPaths[i].Substring(modelPaths[i].Length - 4);
|
||||
bool loaded = false;
|
||||
if (ext == ".md3") {
|
||||
loaded = ReadMD3Model(ref bbs, mde, model, modelPath, D3DDevice);
|
||||
} else if (ext == ".md2") {
|
||||
loaded = ReadMD2Model(ref bbs, mde, model, modelPath, D3DDevice);
|
||||
}
|
||||
string ext = modelNames[i].Substring(modelNames[i].Length - 4);
|
||||
string error = "";
|
||||
if (ext == ".md3")
|
||||
error = ReadMD3Model(ref bbs, ref mde, stream, D3DDevice);
|
||||
else if (ext == ".md2")
|
||||
error = ReadMD2Model(ref bbs, ref mde, stream, D3DDevice);
|
||||
|
||||
//texture
|
||||
if (loaded) {
|
||||
string texturePath = mde.Path + "\\" + texturePaths[i];
|
||||
if (texturePaths[i] != ModelDefParser.INVALID_TEXTURE && File.Exists(texturePath)) {
|
||||
model.Textures.Add(Texture.FromFile(D3DDevice, texturePath));
|
||||
if (string.IsNullOrEmpty(error)) {
|
||||
string texturePath = Path.Combine(mde.Path, textureNames[i]);
|
||||
|
||||
if (textureNames[i] != ModeldefParser.INVALID_TEXTURE && reader.FileExists(texturePath)) {
|
||||
mde.Model.Textures.Add(Texture.FromStream(D3DDevice, reader.LoadFile(texturePath)));
|
||||
} else {
|
||||
model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
|
||||
if (texturePaths[i] != ModelDefParser.INVALID_TEXTURE)
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: unable to load texture '" + texturePath + "' - no such file");
|
||||
mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
|
||||
if (textureNames[i] != ModeldefParser.INVALID_TEXTURE)
|
||||
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: unable to load texture '" + texturePath + "' - no such file");
|
||||
}
|
||||
} else {
|
||||
model.NUM_MESHES--;
|
||||
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: error while loading " + modelPath + ": " + error);
|
||||
mde.Model.NUM_MESHES--;
|
||||
}
|
||||
stream.Dispose();
|
||||
|
||||
} else {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: unable to load model '" + mde.Path + "\\" + modelPaths[i] + "' - no such file");
|
||||
model.NUM_MESHES--;
|
||||
GZBuilder.GZGeneral.LogAndTraceWarning("MD3Reader: unable to load model '" + modelPath + "' - no such file");
|
||||
mde.Model.NUM_MESHES--;
|
||||
}
|
||||
}
|
||||
|
||||
if (model.NUM_MESHES <= 0)
|
||||
return null;
|
||||
if (mde.Model.NUM_MESHES <= 0) {
|
||||
mde.Model = null;
|
||||
return;
|
||||
}
|
||||
|
||||
model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
|
||||
|
||||
return model;
|
||||
mde.Model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
|
||||
}
|
||||
|
||||
private static bool ReadMD3Model(ref BoundingBoxSizes bbs, ModelDefEntry mde, GZModel model, string modelPath, Device D3DDevice) {
|
||||
FileStream s = new FileStream(modelPath, FileMode.Open);
|
||||
private static string ReadMD3Model(ref BoundingBoxSizes bbs, ref ModeldefEntry mde, MemoryStream s, Device D3DDevice) {
|
||||
long start = s.Position;
|
||||
|
||||
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
||||
string magic = ReadString(br, 4);
|
||||
if (magic != "IDP3") {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Magic should be 'IDP3', not '" + magic + "'");
|
||||
return false;
|
||||
}
|
||||
if (magic != "IDP3")
|
||||
return "magic should be 'IDP3', not '" + magic + "'";
|
||||
|
||||
s.Position += 80;
|
||||
int numSurfaces = br.ReadInt32();
|
||||
|
@ -94,8 +101,12 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
List<short> polyIndecesList = new List<short>();
|
||||
List<WorldVertex> vertList = new List<WorldVertex>();
|
||||
|
||||
for (int c = 0; c < numSurfaces; ++c)
|
||||
ReadSurface(ref bbs, br, polyIndecesList, vertList, mde);
|
||||
string error = "";
|
||||
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
|
||||
short[] indeces2d_arr = CreateLineListIndeces(polyIndecesList);
|
||||
|
@ -112,7 +123,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
mesh.IndexBuffer.Unlock();
|
||||
|
||||
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
||||
model.Meshes.Add(mesh);
|
||||
mde.Model.Meshes.Add(mesh);
|
||||
|
||||
//2d data
|
||||
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);
|
||||
indeces2d.Unlock();
|
||||
|
||||
model.Indeces2D.Add(indeces2d);
|
||||
model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
||||
mde.Model.Indeces2D.Add(indeces2d);
|
||||
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;
|
||||
string magic = ReadString(br, 4);
|
||||
if (magic != "IDP3") {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while reading surface: Magic should be 'IDP3', not '" + magic + "'");
|
||||
return;
|
||||
}
|
||||
if (magic != "IDP3")
|
||||
return "error while reading surface: Magic should be 'IDP3', not '" + magic + "'";
|
||||
|
||||
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.
|
||||
|
@ -170,9 +179,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
|
||||
for (int i = 0; i < numVerts; 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.x = (float)br.ReadInt16() / 64 * mde.Scale.Y;
|
||||
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)
|
||||
br.BaseStream.Position = start + ofsEnd;
|
||||
return "";
|
||||
}
|
||||
|
||||
private static bool ReadMD2Model(ref BoundingBoxSizes bbs, ModelDefEntry mde, GZModel model, string modelPath, Device D3DDevice) {
|
||||
FileStream s = new FileStream(modelPath, FileMode.Open);
|
||||
private static string ReadMD2Model(ref BoundingBoxSizes bbs, ref ModeldefEntry mde, MemoryStream s, Device D3DDevice) {
|
||||
long start = s.Position;
|
||||
|
||||
using (var br = new BinaryReader(s, Encoding.ASCII)) {
|
||||
string magic = ReadString(br, 4);
|
||||
if (magic != "IDP2") { //magic number: "IDP2"
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Magic should be 'IDP2', not '" + magic + "'");
|
||||
return false;
|
||||
}
|
||||
if (magic != "IDP2") //magic number: "IDP2"
|
||||
return "magic should be 'IDP2', not '" + magic + "'";
|
||||
|
||||
int modelVersion = br.ReadInt32();
|
||||
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 false;
|
||||
}
|
||||
if (modelVersion != 8) //MD2 version. Must be equal to 8
|
||||
return "MD2 version must be 8 but is " + modelVersion;
|
||||
|
||||
int texWidth = br.ReadInt32();
|
||||
int texHeight = br.ReadInt32();
|
||||
|
@ -219,10 +223,8 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
int num_tris = br.ReadInt32(); //Number of triangles
|
||||
s.Position += 4; //Number of OpenGL commands
|
||||
|
||||
if (br.ReadInt32() == 0) { //Total number of frames
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "MD3Reader: Error while loading '" + modelPath + "': Model has 0 frames");
|
||||
return false;
|
||||
}
|
||||
if (br.ReadInt32() == 0) //Total number of frames
|
||||
return "model has 0 frames";
|
||||
|
||||
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
|
||||
|
@ -284,7 +286,6 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
WorldVertex v = vertList[polyIndecesList[i]];
|
||||
|
||||
//bounding box
|
||||
//BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, v);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, new WorldVertex(v.y, v.x, v.z));
|
||||
|
||||
//uv
|
||||
|
@ -309,7 +310,7 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
mesh.IndexBuffer.Unlock();
|
||||
|
||||
mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);
|
||||
model.Meshes.Add(mesh);
|
||||
mde.Model.Meshes.Add(mesh);
|
||||
|
||||
//2d data
|
||||
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);
|
||||
indeces2d.Unlock();
|
||||
|
||||
model.Indeces2D.Add(indeces2d);
|
||||
model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
||||
model.Angle = -90.0f * (float)Math.PI / 180.0f;
|
||||
|
||||
return true;
|
||||
mde.Model.Indeces2D.Add(indeces2d);
|
||||
mde.Model.NumIndeces2D.Add((short)polyIndecesList.Count);
|
||||
mde.Model.Angle = -90.0f * (float)Math.PI / 180.0f;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//this creates list of vertex indeces for rendering using LineList method
|
||||
|
@ -344,41 +344,6 @@ namespace ColladaDotNet.Pipeline.MD3 {
|
|||
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) {
|
||||
var NAME = string.Empty;
|
||||
int i = 0;
|
||||
|
|
|
@ -286,6 +286,9 @@ namespace CodeImp.DoomBuilder
|
|||
map.UpdateConfiguration();
|
||||
map.Update();
|
||||
thingsfilter.Update();
|
||||
|
||||
//mxd. load models
|
||||
data.LoadModels();
|
||||
|
||||
// Bind any methods
|
||||
General.Actions.BindMethods(this);
|
||||
|
@ -409,6 +412,9 @@ namespace CodeImp.DoomBuilder
|
|||
map.SnapAllToAccuracy();
|
||||
map.Update();
|
||||
thingsfilter.Update();
|
||||
|
||||
//mxd. load models
|
||||
data.LoadModels();
|
||||
|
||||
// Bind any methods
|
||||
General.Actions.BindMethods(this);
|
||||
|
|
|
@ -365,7 +365,7 @@ namespace CodeImp.DoomBuilder.IO
|
|||
// This finds a lump by name, returns -1 when not found
|
||||
public int FindLumpIndex(string name, int start, int end)
|
||||
{
|
||||
byte[] fixedname;
|
||||
//byte[] fixedname;
|
||||
long longname = Lump.MakeLongName(name);
|
||||
|
||||
// Fix end when it exceeds length
|
||||
|
@ -375,7 +375,7 @@ namespace CodeImp.DoomBuilder.IO
|
|||
name = name.ToUpperInvariant();
|
||||
|
||||
// Make fixed name
|
||||
fixedname = Lump.MakeFixedName(name, ENCODING);
|
||||
//fixedname = Lump.MakeFixedName(name, ENCODING);
|
||||
|
||||
// Loop through the lumps
|
||||
for(int i = start; i <= end; i++)
|
||||
|
|
|
@ -37,7 +37,7 @@ using CodeImp.DoomBuilder.Editing;
|
|||
|
||||
//mxd
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using ColladaDotNet.Pipeline.MD3;
|
||||
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -943,7 +943,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
{
|
||||
//mxd. Collect things with models for rendering
|
||||
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)) {
|
||||
thingsWithModel[screenpos] = t;
|
||||
}
|
||||
|
@ -1119,12 +1119,12 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
|
||||
graphics.Shaders.Things2D.BeginPass(1);
|
||||
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)
|
||||
RenderModel(mde.Model, group.Key, group.Value.Angle + mde.Model.Angle, group.Value.Selected);
|
||||
else
|
||||
group.Value.IsModel = GZBuilder.GZGeneral.LoadModelForThing(group.Value);
|
||||
group.Value.IsModel = General.Map.Data.LoadModelForThing(group.Value);
|
||||
}
|
||||
graphics.Shaders.Things2D.EndPass();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ using CodeImp.DoomBuilder.VisualModes;
|
|||
using CodeImp.DoomBuilder.Map;
|
||||
|
||||
//mxd
|
||||
using ColladaDotNet.Pipeline.MD3;
|
||||
using CodeImp.DoomBuilder.GZBuilder.MD3;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
@ -81,7 +81,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
private List<VisualThing> thingsWithLight;
|
||||
private int[] lightOffsets;
|
||||
private Dictionary<Texture, List<VisualGeometry>> litGeometry;
|
||||
private Dictionary<ModelDefEntry, List<VisualThing>> thingsWithModel;
|
||||
private Dictionary<ModeldefEntry, List<VisualThing>> thingsWithModel;
|
||||
//dbg
|
||||
//int geoSkipped = 0;
|
||||
//int totalGeo = 0;
|
||||
|
@ -499,7 +499,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
things = new Dictionary<ImageData, List<VisualThing>>[RENDER_PASSES];
|
||||
thingsbydistance = new BinaryHeap<VisualThing>();
|
||||
//mxd
|
||||
thingsWithModel = new Dictionary<ModelDefEntry, List<VisualThing>>();
|
||||
thingsWithModel = new Dictionary<ModeldefEntry, List<VisualThing>>();
|
||||
litGeometry = new Dictionary<Texture, List<VisualGeometry>>();
|
||||
|
||||
for(int i = 0; i < RENDER_PASSES; i++)
|
||||
|
@ -1003,15 +1003,14 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
|
||||
//mxd. render models
|
||||
private void RenderModels() {
|
||||
int shaderpass = 4;
|
||||
if (fullbrightness) shaderpass++;
|
||||
int shaderpass = fullbrightness ? 1 : 4;
|
||||
int currentshaderpass = shaderpass;
|
||||
int highshaderpass = shaderpass + 2;
|
||||
|
||||
// Begin rendering with this shader
|
||||
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) {
|
||||
Color4 vertexColor = new Color4(t.VertexColor);
|
||||
vertexColor.Alpha = 1.0f;
|
||||
|
@ -1177,7 +1176,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
}
|
||||
//mxd. gather models
|
||||
} 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))
|
||||
return;
|
||||
|
|
|
@ -792,7 +792,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
if (refreshSelection || selectedVisualThings == null) {
|
||||
selectedVisualThings = new List<VisualThing>();
|
||||
foreach (KeyValuePair<Thing, VisualThing> group in allthings) {
|
||||
if (group.Value.Selected)
|
||||
if (group.Value != null && group.Value.Selected)
|
||||
selectedVisualThings.Add(group.Value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,9 +93,6 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
private Vector3 position_v3;
|
||||
private float lightDelta; //used in light animation
|
||||
private Vector3[] boundingBox;
|
||||
|
||||
//mxd. model
|
||||
private bool checkedIfModel;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -202,7 +199,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
|
||||
// This sets the distance from the camera
|
||||
internal void CalculateCameraDistance(Vector2D campos)
|
||||
{
|
||||
|
@ -222,7 +219,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
if(geobuffer != null) geobuffer.Dispose();
|
||||
geobuffer = null;
|
||||
updategeo = true;
|
||||
checkedIfModel = false;
|
||||
//checkedIfModel = false;
|
||||
}
|
||||
|
||||
// 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?
|
||||
if (updategeo)
|
||||
{
|
||||
//mxd
|
||||
if (!checkedIfModel) {
|
||||
//check if thing is model
|
||||
if (GZBuilder.GZGeneral.ModelDefEntries.ContainsKey(thing.Type)) {
|
||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[thing.Type];
|
||||
if (mde.Model == null)
|
||||
thing.IsModel = GZBuilder.GZGeneral.LoadModelForThing(thing);
|
||||
else
|
||||
thing.IsModel = true;
|
||||
}
|
||||
if (thing.IsModel)
|
||||
updateBoundingBoxForModel();
|
||||
checkedIfModel = true;
|
||||
//mxd. check if thing is model
|
||||
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;
|
||||
}
|
||||
|
||||
// Trash geometry buffer
|
||||
|
@ -474,7 +467,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
|
||||
//mxd. update bounding box from model bounding box
|
||||
private void updateBoundingBoxForModel() {
|
||||
ModelDefEntry mde = GZBuilder.GZGeneral.ModelDefEntries[thing.Type];
|
||||
ModeldefEntry mde = General.Map.Data.ModeldefEntries[thing.Type];
|
||||
int len = mde.Model.BoundingBox.Length;
|
||||
boundingBox = new Vector3[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
public DecorateParser()
|
||||
{
|
||||
// Syntax
|
||||
whitespace = "\n \t\r";
|
||||
whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
|
||||
specialtokens = ":{}+-\n;,";
|
||||
|
||||
// Initialize
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
public TexturesParser()
|
||||
{
|
||||
// Syntax
|
||||
whitespace = "\n \t\r";
|
||||
whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
|
||||
specialtokens = ",{}\n";
|
||||
|
||||
// Initialize
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
#region ================== Variables
|
||||
|
||||
// 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;";
|
||||
|
||||
// Input data stream
|
||||
|
@ -297,7 +297,7 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
// This reports an error
|
||||
protected internal void ReportError(string message)
|
||||
{
|
||||
long position = datastream.Position;
|
||||
/*long position = datastream.Position;
|
||||
long readpos = 0;
|
||||
int linenumber = 1;
|
||||
|
||||
|
@ -313,13 +313,35 @@ namespace CodeImp.DoomBuilder.ZDoom
|
|||
}
|
||||
|
||||
// Return to original position
|
||||
datastream.Seek(position, SeekOrigin.Begin);
|
||||
datastream.Seek(position, SeekOrigin.Begin);*/
|
||||
|
||||
// Set error information
|
||||
errordesc = message;
|
||||
errorline = linenumber;
|
||||
errorline = GetCurrentLineNumber();
|
||||
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
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ using CodeImp.DoomBuilder.VisualModes;
|
|||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
|
@ -200,6 +202,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
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
|
||||
SetPosition(pos);
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
<ProjectReference Include="..\..\Core\Builder.csproj">
|
||||
<Project>{818B3D10-F791-4C3F-9AF5-BB2D0079B63C}</Project>
|
||||
<Name>Builder</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -34,6 +34,8 @@ using CodeImp.DoomBuilder.VisualModes;
|
|||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZDoomEditing
|
||||
|
@ -236,6 +238,18 @@ namespace CodeImp.DoomBuilder.GZDoomEditing
|
|||
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
|
||||
SetPosition(pos);
|
||||
|
|
Loading…
Reference in a new issue