From 3f93525ebcf57ef0de7e10d342e6f99131921cea Mon Sep 17 00:00:00 2001 From: MaxED <j.maxed@gmail.com> Date: Mon, 18 Jul 2016 12:05:19 +0000 Subject: [PATCH] Added support for SurfaceSkin MODELDEF property. Changed, Visual mode: increased maximum rendreable dynamic lights count to 64. --- Source/Core/Data/DataManager.cs | 2 +- Source/Core/GZBuilder/Data/ModelData.cs | 6 +- Source/Core/GZBuilder/md3/ModelReader.cs | 48 +++++++--- .../Core/Windows/PreferencesForm.Designer.cs | 19 ++-- Source/Core/Windows/PreferencesForm.cs | 6 +- Source/Core/ZDoom/ModeldefParser.cs | 5 +- Source/Core/ZDoom/ModeldefStructure.cs | 96 +++++++++++++++++-- 7 files changed, 143 insertions(+), 39 deletions(-) diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 3255a2612..1e5ca5356 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -3210,7 +3210,7 @@ namespace CodeImp.DoomBuilder.Data // Load the skysphere model... BoundingBoxSizes bbs = new BoundingBoxSizes(); Stream modeldata = General.ThisAssembly.GetManifestResourceStream("CodeImp.DoomBuilder.Resources.SkySphere.md3"); - ModelReader.MD3LoadResult meshes = ModelReader.ReadMD3Model(ref bbs, true, modeldata, device, 0); + ModelReader.MD3LoadResult meshes = ModelReader.ReadMD3Model(ref bbs, new Dictionary<int, string>(), modeldata, device, 0); if(meshes.Meshes.Count != 3) throw new Exception("Skybox creation failed: " + (string.IsNullOrEmpty(meshes.Errors) ? "skybox model must contain 3 surfaces" : meshes.Errors)); diff --git a/Source/Core/GZBuilder/Data/ModelData.cs b/Source/Core/GZBuilder/Data/ModelData.cs index 0c5dcc39a..b139f10e0 100644 --- a/Source/Core/GZBuilder/Data/ModelData.cs +++ b/Source/Core/GZBuilder/Data/ModelData.cs @@ -30,7 +30,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data #region ================== Properties internal List<string> ModelNames; - internal List<string> TextureNames; + internal List<string> SkinNames; + internal List<Dictionary<int, string>> SurfaceSkinNames; internal List<string> FrameNames; internal List<int> FrameIndices; @@ -62,7 +63,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data internal ModelData() { ModelNames = new List<string>(); - TextureNames = new List<string>(); + SkinNames = new List<string>(); + SurfaceSkinNames = new List<Dictionary<int, string>>(); FrameNames = new List<string>(); FrameIndices = new List<int>(); transform = Matrix.Identity; diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index 5d1799c86..fb2c77148 100644 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -77,7 +77,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } //clear unneeded data - mde.TextureNames = null; + mde.SkinNames = null; mde.ModelNames = null; if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) @@ -95,10 +95,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //load models and textures for(int i = 0; i < mde.ModelNames.Count; i++) { - //need to use model skins? - bool useSkins = string.IsNullOrEmpty(mde.TextureNames[i]); + // Use model skins? + // INFO: Skin MODELDEF property overrides both embedded surface names and ones set using SurfaceSkin MODELDEF property + Dictionary<int, string> skins = null; + if(string.IsNullOrEmpty(mde.SkinNames[i])) + { + skins = (mde.SurfaceSkinNames[i].Count > 0 ? mde.SurfaceSkinNames[i] : new Dictionary<int, string>()); + } - //load mesh + // Load mesh MemoryStream ms = LoadFile(containers, mde.ModelNames[i], true); if(ms == null) { @@ -115,7 +120,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": frame names are not supported for MD3 models!"); continue; } - result = ReadMD3Model(ref bbs, useSkins, ms, device, mde.FrameIndices[i]); + result = ReadMD3Model(ref bbs, skins, ms, device, mde.FrameIndices[i]); break; case ".md2": result = ReadMD2Model(ref bbs, ms, device, mde.FrameIndices[i], mde.FrameNames[i]); @@ -145,7 +150,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 List<string> errors = new List<string>(); // Texture not defined in MODELDEF? - if(useSkins) + if(skins != null) { //try to use model's own skins for(int m = 0; m < result.Meshes.Count; m++) @@ -169,7 +174,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //relative path? if(path.IndexOf(Path.DirectorySeparatorChar) == -1) - path = Path.Combine(Path.GetDirectoryName(mde.ModelNames[useSkins ? i : m]), path); + path = Path.Combine(Path.GetDirectoryName(mde.ModelNames[i]), path); Texture t = LoadTexture(containers, path, device); @@ -186,11 +191,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //Try to use texture loaded from MODELDEFS else { - Texture t = LoadTexture(containers, mde.TextureNames[i], device); + Texture t = LoadTexture(containers, mde.SkinNames[i], device); if(t == null) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); - errors.Add("unable to load texture \"" + mde.TextureNames[i] + "\""); + errors.Add("unable to load texture \"" + mde.SkinNames[i] + "\""); } else { @@ -208,7 +213,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } //clear unneeded data - mde.TextureNames = null; + mde.SkinNames = null; mde.ModelNames = null; if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) @@ -231,7 +236,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== MD3 - internal static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, bool useSkins, Stream s, Device device, int frame) + internal static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, Dictionary<int, string> skins, Stream s, Device device, int frame) { long start = s.Position; MD3LoadResult result = new MD3LoadResult(); @@ -265,6 +270,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 Dictionary<string, List<List<int>>> polyIndecesListsPerTexture = new Dictionary<string, List<List<int>>>(StringComparer.Ordinal); Dictionary<string, List<WorldVertex>> vertListsPerTexture = new Dictionary<string, List<WorldVertex>>(StringComparer.Ordinal); Dictionary<string, List<int>> vertexOffsets = new Dictionary<string, List<int>>(StringComparer.Ordinal); + bool useskins = false; for(int c = 0; c < numSurfaces; c++) { @@ -277,8 +283,22 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 return result; } - if(useSkins) + // Pick a skin to use + if(skins == null) + { + // skins is null when Skin MODELDEF property is set + skin = string.Empty; + } + else if(skins.ContainsKey(c)) + { + // Overrtide surface skin with SurfaceSkin MODELDEF property + skin = skins[c]; + } + + if(!string.IsNullOrEmpty(skin)) { + useskins = true; + if(polyIndecesListsPerTexture.ContainsKey(skin)) { polyIndecesListsPerTexture[skin].Add(polyIndecesList); @@ -298,8 +318,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } } - if(!useSkins) - { + if(!useskins) + { //create mesh CreateMesh(device, ref result, vertList, polyIndecesList); result.Skins.Add(""); diff --git a/Source/Core/Windows/PreferencesForm.Designer.cs b/Source/Core/Windows/PreferencesForm.Designer.cs index 99dd8480e..5b528ceef 100644 --- a/Source/Core/Windows/PreferencesForm.Designer.cs +++ b/Source/Core/Windows/PreferencesForm.Designer.cs @@ -602,7 +602,7 @@ namespace CodeImp.DoomBuilder.Windows // label1 // label1.AutoSize = true; - label1.Location = new System.Drawing.Point(41, 171); + label1.Location = new System.Drawing.Point(43, 171); label1.Name = "label1"; label1.Size = new System.Drawing.Size(145, 13); label1.TabIndex = 20; @@ -612,11 +612,11 @@ namespace CodeImp.DoomBuilder.Windows // label18 // label18.AutoSize = true; - label18.Location = new System.Drawing.Point(41, 208); + label18.Location = new System.Drawing.Point(80, 208); label18.Name = "label18"; - label18.Size = new System.Drawing.Size(147, 13); + label18.Size = new System.Drawing.Size(108, 13); label18.TabIndex = 25; - label18.Text = "Max. dynamic lights to render:"; + label18.Text = "Dynamic lights count:"; label18.TextAlign = System.Drawing.ContentAlignment.TopRight; this.toolTip1.SetToolTip(label18, "Controls how many dynamic lights could be \r\nrendered simultaneously in Visual mod" + "e "); @@ -654,7 +654,7 @@ namespace CodeImp.DoomBuilder.Windows // label29 // label29.AutoSize = true; - label29.Location = new System.Drawing.Point(90, 356); + label29.Location = new System.Drawing.Point(96, 356); label29.Name = "label29"; label29.Size = new System.Drawing.Size(93, 13); label29.TabIndex = 38; @@ -1704,7 +1704,7 @@ namespace CodeImp.DoomBuilder.Windows // label32 // this.label32.AutoSize = true; - this.label32.Location = new System.Drawing.Point(44, 134); + this.label32.Location = new System.Drawing.Point(49, 134); this.label32.Name = "label32"; this.label32.Size = new System.Drawing.Size(139, 13); this.label32.TabIndex = 44; @@ -1724,7 +1724,7 @@ namespace CodeImp.DoomBuilder.Windows // label30 // this.label30.AutoSize = true; - this.label30.Location = new System.Drawing.Point(16, 97); + this.label30.Location = new System.Drawing.Point(15, 97); this.label30.Name = "label30"; this.label30.Size = new System.Drawing.Size(173, 13); this.label30.TabIndex = 41; @@ -1845,14 +1845,13 @@ namespace CodeImp.DoomBuilder.Windows // tbDynLightCount // this.tbDynLightCount.BackColor = System.Drawing.SystemColors.Window; - this.tbDynLightCount.LargeChange = 3; + this.tbDynLightCount.LargeChange = 1; this.tbDynLightCount.Location = new System.Drawing.Point(199, 197); - this.tbDynLightCount.Maximum = 32; + this.tbDynLightCount.Maximum = 8; this.tbDynLightCount.Minimum = 1; this.tbDynLightCount.Name = "tbDynLightCount"; this.tbDynLightCount.Size = new System.Drawing.Size(154, 45); this.tbDynLightCount.TabIndex = 5; - this.tbDynLightCount.TickFrequency = 4; this.tbDynLightCount.TickStyle = System.Windows.Forms.TickStyle.TopLeft; this.tbDynLightCount.Value = 1; this.tbDynLightCount.ValueChanged += new System.EventHandler(this.tbDynLightCount_ValueChanged); diff --git a/Source/Core/Windows/PreferencesForm.cs b/Source/Core/Windows/PreferencesForm.cs index 08a79a0cc..c67bd62b3 100644 --- a/Source/Core/Windows/PreferencesForm.cs +++ b/Source/Core/Windows/PreferencesForm.cs @@ -97,7 +97,7 @@ namespace CodeImp.DoomBuilder.Windows checkforupdates.Checked = General.Settings.CheckForUpdates; toolbar_gzdoom.Checked = General.Settings.GZToolbarGZDoom; cbSynchCameras.Checked = General.Settings.GZSynchCameras; - tbDynLightCount.Value = General.Clamp(General.Settings.GZMaxDynamicLights, tbDynLightCount.Minimum, tbDynLightCount.Maximum); + tbDynLightCount.Value = General.Clamp(General.Settings.GZMaxDynamicLights / 8, tbDynLightCount.Minimum, tbDynLightCount.Maximum); labelDynLightCount.Text = General.Settings.GZMaxDynamicLights.ToString(); tbDynLightSize.Value = General.Clamp((int)(General.Settings.GZDynamicLightRadius * 10), tbDynLightSize.Minimum, tbDynLightSize.Maximum); labelDynLightSize.Text = General.Settings.GZDynamicLightRadius.ToString(); @@ -409,7 +409,7 @@ namespace CodeImp.DoomBuilder.Windows //mxd General.Settings.GZSynchCameras = cbSynchCameras.Checked; - General.Settings.GZMaxDynamicLights = tbDynLightCount.Value; + General.Settings.GZMaxDynamicLights = tbDynLightCount.Value * 8; General.Settings.GZDynamicLightRadius = (tbDynLightSize.Value / 10.0f); General.Settings.GZDynamicLightIntensity = (tbDynLightIntensity.Value / 10.0f); General.Settings.FilterAnisotropy = D3DDevice.AF_STEPS[anisotropicfiltering.Value]; @@ -1006,7 +1006,7 @@ namespace CodeImp.DoomBuilder.Windows //mxd private void tbDynLightCount_ValueChanged(object sender, EventArgs e) { - labelDynLightCount.Text = tbDynLightCount.Value.ToString(); + labelDynLightCount.Text = (tbDynLightCount.Value * 8).ToString(); } //mxd diff --git a/Source/Core/ZDoom/ModeldefParser.cs b/Source/Core/ZDoom/ModeldefParser.cs index 62654eaa0..47cb8174f 100644 --- a/Source/Core/ZDoom/ModeldefParser.cs +++ b/Source/Core/ZDoom/ModeldefParser.cs @@ -118,9 +118,10 @@ namespace CodeImp.DoomBuilder.ZDoom } // Texture name will be empty when skin path is embedded in the model - string texturename = (!string.IsNullOrEmpty(mds.TextureNames[fs.ModelIndex]) ? mds.TextureNames[fs.ModelIndex].ToLowerInvariant() : string.Empty); + string skinname = (!string.IsNullOrEmpty(mds.SkinNames[fs.ModelIndex]) ? mds.SkinNames[fs.ModelIndex].ToLowerInvariant() : string.Empty); - md.TextureNames.Add(texturename); + md.SkinNames.Add(skinname); + md.SurfaceSkinNames.Add(mds.SurfaceSkinNames[fs.ModelIndex]); md.ModelNames.Add(mds.ModelNames[fs.ModelIndex].ToLowerInvariant()); md.FrameNames.Add(fs.FrameName); md.FrameIndices.Add(fs.FrameIndex); diff --git a/Source/Core/ZDoom/ModeldefStructure.cs b/Source/Core/ZDoom/ModeldefStructure.cs index b4b0dcbb0..bad406029 100644 --- a/Source/Core/ZDoom/ModeldefStructure.cs +++ b/Source/Core/ZDoom/ModeldefStructure.cs @@ -33,7 +33,8 @@ namespace CodeImp.DoomBuilder.ZDoom #region ================== Variables - private string[] texturenames; + private string[] skinnames; + private Dictionary<int, string>[] surfaceskinenames; private string[] modelnames; private string path; private Vector3 scale; @@ -51,7 +52,8 @@ namespace CodeImp.DoomBuilder.ZDoom #region ================== Properties - public string[] TextureNames { get { return texturenames; } } + public string[] SkinNames { get { return skinnames; } } + public Dictionary<int, string>[] SurfaceSkinNames { get { return surfaceskinenames; } } public string[] ModelNames { get { return modelnames; } } public Vector3 Scale { get { return scale; } } public Vector3 Offset { get { return offset; } } @@ -70,10 +72,15 @@ namespace CodeImp.DoomBuilder.ZDoom internal ModeldefStructure() { - texturenames = new string[MAX_MODELS]; + skinnames = new string[MAX_MODELS]; modelnames = new string[MAX_MODELS]; frames = new Dictionary<string, HashSet<FrameStructure>>(StringComparer.OrdinalIgnoreCase); scale = new Vector3(1.0f, 1.0f, 1.0f); + surfaceskinenames = new Dictionary<int, string>[MAX_MODELS]; + for(int i = 0; i < MAX_MODELS; i++) + { + surfaceskinenames[i] = new Dictionary<int, string>(); + } } #endregion @@ -194,7 +201,72 @@ namespace CodeImp.DoomBuilder.ZDoom } // GZDoom allows skins with identical index, it uses the last one encountered - texturenames[skinindex] = Path.Combine(path, token); + skinnames[skinindex] = Path.Combine(path, token); + break; + + // SurfaceSkin <int modelindex> <int surfaceindex> <string skinfile> + case "surfaceskin": + parser.SkipWhitespace(true); + + // Model index + int modelindex = 0; + token = parser.ReadToken(); + if(!parser.ReadSignedInt(token, ref modelindex)) + { + // Not numeric! + parser.ReportError("Expected model index, but got \"" + token + "\""); + return false; + } + + if(modelindex < 0 || modelindex >= MAX_MODELS) + { + // Out of bounds + parser.ReportError("Model index must be in [0.." + (MAX_MODELS - 1) + "] range"); + return false; + } + + parser.SkipWhitespace(true); + + // Surfaceindex index + int surfaceindex = 0; + token = parser.ReadToken(); + if(!parser.ReadSignedInt(token, ref surfaceindex)) + { + // Not numeric! + parser.ReportError("Expected surface index, but got \"" + token + "\""); + return false; + } + + if(surfaceindex < 0) + { + // Out of bounds + parser.ReportError("Surface index must be positive integer"); + return false; + } + + parser.SkipWhitespace(true); + + // Skin path + token = parser.StripTokenQuotes(parser.ReadToken(false)).ToLowerInvariant(); // Don't skip newline + if(string.IsNullOrEmpty(token)) + { + parser.ReportError("Expected skin path"); + return false; + } + + // Check invalid path chars + if(!parser.CheckInvalidPathChars(token)) return false; + + // Check extension + string skinext = Path.GetExtension(token); + if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, skinext) == -1) + { + parser.ReportError("Image format \"" + skinext + "\" is not supported"); + return false; + } + + // Store + surfaceskinenames[modelindex][surfaceindex] = Path.Combine(path, token); break; case "scale": @@ -511,11 +583,21 @@ namespace CodeImp.DoomBuilder.ZDoom } // Check skin-model associations - for(int i = 0; i < texturenames.Length; i++) + for(int i = 0; i < skinnames.Length; i++) + { + if(!string.IsNullOrEmpty(skinnames[i]) && string.IsNullOrEmpty(modelnames[i])) + { + parser.ReportError("No model is defined for skin " + i + ":\"" + skinnames[i] + "\""); + return false; + } + } + + // Check surfaceskin-model associations + for(int i = 0; i < surfaceskinenames.Length; i++) { - if(!string.IsNullOrEmpty(texturenames[i]) && string.IsNullOrEmpty(modelnames[i])) + if(surfaceskinenames[i].Count > 0 && string.IsNullOrEmpty(modelnames[i])) { - parser.ReportError("No model is defined for skin " + i + ":\"" + texturenames[i] + "\""); + parser.ReportError("No model is defined for surface skin " + i); return false; } } -- GitLab