Added support for SurfaceSkin MODELDEF property.

Changed, Visual mode: increased maximum rendreable dynamic lights count to 64.
This commit is contained in:
MaxED 2016-07-18 12:05:19 +00:00
parent 68c5ed1747
commit 3f93525ebc
7 changed files with 143 additions and 39 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(texturenames[i]) && string.IsNullOrEmpty(modelnames[i]))
if(!string.IsNullOrEmpty(skinnames[i]) && string.IsNullOrEmpty(modelnames[i]))
{
parser.ReportError("No model is defined for skin " + i + ":\"" + texturenames[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(surfaceskinenames[i].Count > 0 && string.IsNullOrEmpty(modelnames[i]))
{
parser.ReportError("No model is defined for surface skin " + i);
return false;
}
}