mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 14:31:50 +00:00
Classic modes: further text label rendering optimization.
MODELDEF parser: rewrote most of the parser logic. Now it picks actor model(s) based on Frame / FrameName properties.
This commit is contained in:
parent
ee12da96a1
commit
580f7d4461
10 changed files with 605 additions and 572 deletions
|
@ -1,34 +1,50 @@
|
|||
using System;
|
||||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CodeImp.DoomBuilder.Config;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.ZDoom;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using SlimDX;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
|
||||
{
|
||||
internal class ModeldefParser : ZDTextParser
|
||||
{
|
||||
internal override ScriptType ScriptType { get { return ScriptType.MODELDEF; } }
|
||||
#region ================== Variables
|
||||
|
||||
private readonly Dictionary<string, int> actorsbyclass;
|
||||
internal Dictionary<string, int> ActorsByClass { get { return actorsbyclass; } }
|
||||
|
||||
private Dictionary<string, ModelData> entries; //classname, entry
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
internal override ScriptType ScriptType { get { return ScriptType.MODELDEF; } }
|
||||
internal Dictionary<string, ModelData> Entries { get { return entries; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor
|
||||
|
||||
internal ModeldefParser(Dictionary<string, int> actorsbyclass)
|
||||
{
|
||||
this.actorsbyclass = actorsbyclass;
|
||||
this.entries = new Dictionary<string, ModelData>(StringComparer.Ordinal);
|
||||
this.entries = new Dictionary<string, ModelData>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
//should be called after all decorate actors are parsed
|
||||
#endregion
|
||||
|
||||
#region ================== Parsing
|
||||
|
||||
// Should be called after all decorate actors are parsed
|
||||
public override bool Parse(TextResourceData data, bool clearerrors)
|
||||
{
|
||||
entries = new Dictionary<string, ModelData>(StringComparer.Ordinal);
|
||||
|
||||
//mxd. Already parsed?
|
||||
// Already parsed?
|
||||
if(!base.AddTextResource(data))
|
||||
{
|
||||
if(clearerrors) ClearError();
|
||||
|
@ -42,72 +58,75 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
|
|||
while(SkipWhitespace(true))
|
||||
{
|
||||
string token = ReadToken();
|
||||
if(!string.IsNullOrEmpty(token))
|
||||
if(string.IsNullOrEmpty(token)) continue;
|
||||
|
||||
token = StripTokenQuotes(token).ToLowerInvariant();
|
||||
if(token != "model") continue;
|
||||
|
||||
// Find classname
|
||||
SkipWhitespace(true);
|
||||
string classname = ReadToken(ActorStructure.ACTOR_CLASS_SPECIAL_TOKENS);
|
||||
if(string.IsNullOrEmpty(classname))
|
||||
{
|
||||
token = StripTokenQuotes(token).ToLowerInvariant();
|
||||
if(token == "model") //model structure start
|
||||
{
|
||||
// Find classname
|
||||
SkipWhitespace(true);
|
||||
string displayclassname = StripTokenQuotes(ReadToken(ActorStructure.ACTOR_CLASS_SPECIAL_TOKENS));
|
||||
string classname = displayclassname.ToLowerInvariant();
|
||||
ReportError("Expected actor class");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now find opening brace
|
||||
if(!NextTokenIs("{")) return false;
|
||||
|
||||
if(!string.IsNullOrEmpty(classname) && !entries.ContainsKey(classname))
|
||||
{
|
||||
// Now find opening brace
|
||||
if(!NextTokenIs("{")) return false;
|
||||
|
||||
ModeldefStructure mds = new ModeldefStructure();
|
||||
if(mds.Parse(this, displayclassname) && mds.ModelData != null)
|
||||
{
|
||||
entries.Add(classname, mds.ModelData);
|
||||
}
|
||||
|
||||
if(HasError)
|
||||
{
|
||||
LogError();
|
||||
ClearError();
|
||||
}
|
||||
|
||||
// Skip untill current structure end
|
||||
if(!mds.ParsingFinished) SkipStructure(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
// Parse the structure
|
||||
ModeldefStructure mds = new ModeldefStructure();
|
||||
if(mds.Parse(this))
|
||||
{
|
||||
// Fetch Actor info
|
||||
if(actorsbyclass.ContainsKey(classname))
|
||||
{
|
||||
// Unknown structure!
|
||||
if(token != "{")
|
||||
{
|
||||
string token2;
|
||||
do
|
||||
{
|
||||
if(!SkipWhitespace(true)) break;
|
||||
token2 = ReadToken();
|
||||
if(string.IsNullOrEmpty(token2)) break;
|
||||
}
|
||||
while(token2 != "{");
|
||||
}
|
||||
ThingTypeInfo info = General.Map.Data.GetThingInfoEx(actorsbyclass[classname]);
|
||||
|
||||
SkipStructure(1);
|
||||
// Actor has a valid sprite?
|
||||
if(info != null && !string.IsNullOrEmpty(info.Sprite) && !info.Sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX))
|
||||
{
|
||||
string targetsprite = info.Sprite.Substring(0, 5);
|
||||
if(mds.Frames.ContainsKey(targetsprite))
|
||||
{
|
||||
// Create model data
|
||||
ModelData md = new ModelData { InheritActorPitch = mds.InheritActorPitch, InheritActorRoll = mds.InheritActorRoll };
|
||||
|
||||
// Things are complicated in GZDoom...
|
||||
Matrix moffset = Matrix.Translation(mds.Offset.Y, -mds.Offset.X, mds.Offset.Z);
|
||||
Matrix mrotation = Matrix.RotationY(-Angle2D.DegToRad(mds.RollOffset)) * Matrix.RotationX(-Angle2D.DegToRad(mds.PitchOffset)) * Matrix.RotationZ(Angle2D.DegToRad(mds.AngleOffset));
|
||||
md.SetTransform(mrotation, moffset, mds.Scale);
|
||||
|
||||
// Add models
|
||||
foreach(var fs in mds.Frames[targetsprite])
|
||||
{
|
||||
// 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);
|
||||
|
||||
md.TextureNames.Add(texturename);
|
||||
md.ModelNames.Add(mds.ModelNames[fs.ModelIndex].ToLowerInvariant());
|
||||
md.FrameNames.Add(fs.FrameName);
|
||||
md.FrameIndices.Add(fs.FrameIndex);
|
||||
}
|
||||
|
||||
// Add to collection
|
||||
entries[classname] = md;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(HasError)
|
||||
{
|
||||
LogError();
|
||||
ClearError();
|
||||
}
|
||||
}
|
||||
|
||||
return entries.Count > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skips untill current structure end
|
||||
private void SkipStructure(int scopelevel)
|
||||
{
|
||||
do
|
||||
{
|
||||
if(!SkipWhitespace(true)) break;
|
||||
string token = ReadToken();
|
||||
if(string.IsNullOrEmpty(token)) break;
|
||||
if(token == "{") scopelevel++;
|
||||
if(token == "}") scopelevel--;
|
||||
}
|
||||
while(scopelevel > 0);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,490 +1,494 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using SlimDX;
|
||||
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
|
||||
{
|
||||
internal sealed class ModeldefStructure
|
||||
internal sealed class ModeldefStructure
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const int MAX_MODELS = 4; //maximum models per modeldef entry, zero-based
|
||||
private bool parsingfinished;
|
||||
|
||||
internal ModelData ModelData;
|
||||
internal bool ParsingFinished { get { return parsingfinished; } }
|
||||
#endregion
|
||||
|
||||
#region ================== Structs
|
||||
|
||||
internal bool Parse(ModeldefParser parser, string classname)
|
||||
internal struct FrameStructure
|
||||
{
|
||||
public string SpriteName; // Stays here for HashSet duplicate checks
|
||||
public int ModelIndex;
|
||||
public int FrameIndex;
|
||||
public string FrameName;
|
||||
}
|
||||
|
||||
#region ================== Vars
|
||||
#endregion
|
||||
|
||||
string[] textureNames = new string[MAX_MODELS];
|
||||
string[] modelNames = new string[MAX_MODELS];
|
||||
string[] frameNames = new string[MAX_MODELS];
|
||||
int[] frameIndices = new int[MAX_MODELS];
|
||||
bool[] modelsUsed = new bool[MAX_MODELS];
|
||||
string path = "";
|
||||
Vector3 scale = new Vector3(1, 1, 1);
|
||||
Vector3 offset = new Vector3();
|
||||
float angleOffset = 0;
|
||||
float pitchOffset = 0;
|
||||
float rollOffset = 0;
|
||||
bool inheritactorpitch = false;
|
||||
bool inheritactorroll = false;
|
||||
#region ================== Variables
|
||||
|
||||
string token;
|
||||
private string[] texturenames;
|
||||
private string[] modelnames;
|
||||
private string path;
|
||||
private Vector3 scale;
|
||||
private Vector3 offset;
|
||||
private float angleoffset;
|
||||
private float pitchoffset;
|
||||
private float rolloffset;
|
||||
private bool inheritactorpitch;
|
||||
private bool inheritactorroll;
|
||||
|
||||
#endregion
|
||||
private Dictionary<string, HashSet<FrameStructure>> frames;
|
||||
|
||||
//read modeldef structure contents
|
||||
parsingfinished = false;
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public string[] TextureNames { get { return texturenames; } }
|
||||
public string[] ModelNames { get { return modelnames; } }
|
||||
public Vector3 Scale { get { return scale; } }
|
||||
public Vector3 Offset { get { return offset; } }
|
||||
public float AngleOffset { get { return angleoffset; } }
|
||||
public float PitchOffset { get { return pitchoffset; } }
|
||||
public float RollOffset { get { return rolloffset; } }
|
||||
public bool InheritActorPitch { get { return inheritactorpitch; } }
|
||||
public bool InheritActorRoll { get { return inheritactorroll; } }
|
||||
|
||||
public Dictionary<string, HashSet<FrameStructure>> Frames { get { return frames; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor
|
||||
|
||||
internal ModeldefStructure()
|
||||
{
|
||||
texturenames = 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);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Parsing
|
||||
|
||||
internal bool Parse(ModeldefParser parser)
|
||||
{
|
||||
// Read modeldef structure contents
|
||||
bool parsingfinished = false;
|
||||
while(!parsingfinished && parser.SkipWhitespace(true))
|
||||
{
|
||||
token = parser.ReadToken();
|
||||
if(!string.IsNullOrEmpty(token))
|
||||
string token = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(token)) continue;
|
||||
|
||||
switch(token.ToLowerInvariant())
|
||||
{
|
||||
token = parser.StripTokenQuotes(token).ToLowerInvariant(); //ANYTHING can be quoted...
|
||||
switch(token)
|
||||
{
|
||||
|
||||
#region ================== Path
|
||||
|
||||
case "path":
|
||||
parser.SkipWhitespace(true);
|
||||
path = parser.StripTokenQuotes(parser.ReadToken(false)).Replace("/", "\\"); // Don't skip newline
|
||||
if(string.IsNullOrEmpty(path))
|
||||
{
|
||||
parser.ReportError("Expected model path");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Model
|
||||
|
||||
case "model":
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//model index
|
||||
int index;
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out index))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(index >= MAX_MODELS)
|
||||
{
|
||||
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//model path
|
||||
token = parser.StripTokenQuotes(parser.ReadToken(false)).ToLowerInvariant(); // Don't skip newline
|
||||
if(string.IsNullOrEmpty(token))
|
||||
{
|
||||
parser.ReportError("Expected model name");
|
||||
return false;
|
||||
}
|
||||
|
||||
//check invalid path chars
|
||||
if(!parser.CheckInvalidPathChars(token)) return false;
|
||||
|
||||
//check extension
|
||||
string modelext = Path.GetExtension(token);
|
||||
if(string.IsNullOrEmpty(modelext))
|
||||
{
|
||||
parser.ReportError("Model \"" + token + "\" won't be loaded. Models without extension are not supported by GZDoom");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(modelext != ".md3" && modelext != ".md2")
|
||||
{
|
||||
parser.ReportError("Model \"" + token + "\" won't be loaded. Only MD2 and MD3 models are supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
//GZDoom allows models with identical modelIndex, it uses the last one encountered
|
||||
modelNames[index] = Path.Combine(path, token);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Skin
|
||||
|
||||
case "skin":
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//skin index
|
||||
int skinIndex;
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out skinIndex))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected skin index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(skinIndex >= MAX_MODELS)
|
||||
{
|
||||
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " skins per MODELDEF entry");
|
||||
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 texext = Path.GetExtension(token);
|
||||
if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, texext) == -1)
|
||||
{
|
||||
parser.ReportError("Image format \"" + texext + "\" is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
//GZDoom allows skins with identical modelIndex, it uses the last one encountered
|
||||
textureNames[skinIndex] = Path.Combine(path, token);
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Scale
|
||||
|
||||
case "scale":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref scale.Y))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale X value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref scale.X))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale Y value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref scale.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale Z value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Offset
|
||||
|
||||
case "offset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref offset.X))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset X value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Y))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset Y value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset Z value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== ZOffset
|
||||
|
||||
case "zoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected ZOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== AngleOffset
|
||||
|
||||
case "angleoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref angleOffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected AngleOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== PitchOffset
|
||||
|
||||
case "pitchoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref pitchOffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected PitchOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== RollOffset
|
||||
|
||||
case "rolloffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(!parser.ReadSignedFloat(token, ref rollOffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected RollOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== InheritActorPitch
|
||||
|
||||
case "inheritactorpitch":
|
||||
inheritactorpitch = true;
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== InheritActorRoll
|
||||
|
||||
case "inheritactorroll":
|
||||
inheritactorroll = true;
|
||||
break;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Frame / FrameIndex
|
||||
|
||||
case "frameindex":
|
||||
case "frame":
|
||||
//parsed all required fields. if got more than one model - find which one(s) should be displayed
|
||||
if(modelNames.GetLength(0) > 1)
|
||||
{
|
||||
string spriteLump = null;
|
||||
string spriteFrame = null;
|
||||
|
||||
//step back
|
||||
parser.DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
|
||||
|
||||
//here we check which models are used in first encountered lump and frame
|
||||
while(parser.SkipWhitespace(true))
|
||||
{
|
||||
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
|
||||
if(token == "frameindex" || token == "frame")
|
||||
{
|
||||
bool frameIndex = (token == "frameindex");
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//should be sprite lump
|
||||
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
|
||||
if(string.IsNullOrEmpty(spriteLump))
|
||||
{
|
||||
spriteLump = token;
|
||||
}
|
||||
else if(spriteLump != token) //got another lump
|
||||
{
|
||||
for(int i = 0; i < modelsUsed.Length; i++)
|
||||
{
|
||||
if(!modelsUsed[i])
|
||||
{
|
||||
modelNames[i] = null;
|
||||
textureNames[i] = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//should be sprite frame
|
||||
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
|
||||
if(string.IsNullOrEmpty(spriteFrame))
|
||||
{
|
||||
spriteFrame = token;
|
||||
}
|
||||
else if(spriteFrame != token) //got another frame
|
||||
{
|
||||
for(int i = 0; i < modelsUsed.Length; i++)
|
||||
{
|
||||
if(!modelsUsed[i])
|
||||
{
|
||||
modelNames[i] = null;
|
||||
textureNames[i] = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
//should be model index
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
|
||||
int modelIndex;
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelIndex))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(modelIndex >= MAX_MODELS)
|
||||
{
|
||||
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(modelNames[modelIndex] == null)
|
||||
{
|
||||
parser.ReportError("Model index doesn't correspond to any defined model");
|
||||
return false;
|
||||
}
|
||||
|
||||
modelsUsed[modelIndex] = true;
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
// Should be frame name or index
|
||||
token = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(frameIndex)
|
||||
{
|
||||
int frame = 0;
|
||||
if(!parser.ReadSignedInt(token, ref frame))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model frame index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the model if frame index is -1
|
||||
if(frame == -1) modelsUsed[modelIndex] = false;
|
||||
else frameIndices[modelIndex] = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(string.IsNullOrEmpty(token))
|
||||
{
|
||||
// Missing!
|
||||
parser.ReportError("Expected model frame name");
|
||||
return false;
|
||||
}
|
||||
|
||||
frameNames[modelIndex] = token.ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//must be "}", step back
|
||||
parser.DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parsingfinished = true;
|
||||
break;
|
||||
|
||||
#endregion
|
||||
}
|
||||
case "path":
|
||||
parser.SkipWhitespace(true);
|
||||
path = parser.StripTokenQuotes(parser.ReadToken(false)).Replace("/", "\\"); // Don't skip newline
|
||||
if(string.IsNullOrEmpty(path))
|
||||
{
|
||||
parser.ReportError("Expected model path");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "model":
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
// Model index
|
||||
int index;
|
||||
token = parser.ReadToken();
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out index) || index < 0)
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(index >= MAX_MODELS)
|
||||
{
|
||||
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
// Model path
|
||||
token = parser.StripTokenQuotes(parser.ReadToken(false)).ToLowerInvariant(); // Don't skip newline
|
||||
if(string.IsNullOrEmpty(token))
|
||||
{
|
||||
parser.ReportError("Expected model name");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check invalid path chars
|
||||
if(!parser.CheckInvalidPathChars(token)) return false;
|
||||
|
||||
// Check extension
|
||||
string modelext = Path.GetExtension(token);
|
||||
if(string.IsNullOrEmpty(modelext))
|
||||
{
|
||||
parser.ReportError("Model \"" + token + "\" won't be loaded. Models without extension are not supported by GZDoom");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(modelext != ".md3" && modelext != ".md2")
|
||||
{
|
||||
parser.ReportError("Model \"" + token + "\" won't be loaded. Only MD2 and MD3 models are supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// GZDoom allows models with identical index, it uses the last one encountered
|
||||
modelnames[index] = Path.Combine(path, token);
|
||||
break;
|
||||
|
||||
case "skin":
|
||||
parser.SkipWhitespace(true);
|
||||
|
||||
// Skin index
|
||||
int skinindex;
|
||||
token = parser.ReadToken();
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out skinindex) || skinindex < 0)
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected skin index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(skinindex >= MAX_MODELS)
|
||||
{
|
||||
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " skins per MODELDEF entry");
|
||||
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 texext = Path.GetExtension(token);
|
||||
if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, texext) == -1)
|
||||
{
|
||||
parser.ReportError("Image format \"" + texext + "\" is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// GZDoom allows skins with identical index, it uses the last one encountered
|
||||
texturenames[skinindex] = Path.Combine(path, token);
|
||||
break;
|
||||
|
||||
case "scale":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref scale.Y))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale X value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref scale.X))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale Y value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref scale.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Scale Z value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "offset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref offset.X))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset X value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Y))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset Y value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected Offset Z value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "zoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref offset.Z))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected ZOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "angleoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref angleoffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected AngleOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "pitchoffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref pitchoffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected PitchOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "rolloffset":
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(!parser.ReadSignedFloat(token, ref rolloffset))
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected RollOffset value, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "inheritactorpitch": inheritactorpitch = true; break;
|
||||
case "inheritactorroll": inheritactorroll = true; break;
|
||||
|
||||
//FrameIndex <XXXX> <X> <model index> <frame number>
|
||||
case "frameindex":
|
||||
// Sprite name
|
||||
parser.SkipWhitespace(true);
|
||||
string fispritename = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(fispritename))
|
||||
{
|
||||
parser.ReportError("Expected sprite name");
|
||||
return false;
|
||||
}
|
||||
if(fispritename.Length != 4)
|
||||
{
|
||||
parser.ReportError("Sprite name must be 4 characters long");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sprite frame
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(token))
|
||||
{
|
||||
parser.ReportError("Expected sprite frame");
|
||||
return false;
|
||||
}
|
||||
if(token.Length != 1)
|
||||
{
|
||||
parser.ReportError("Sprite frame must be 1 character long");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make full name
|
||||
fispritename += token;
|
||||
|
||||
// Model index
|
||||
parser.SkipWhitespace(true);
|
||||
int fimodelindnex;
|
||||
token = parser.ReadToken();
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out fimodelindnex) || fimodelindnex < 0)
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Frame number
|
||||
parser.SkipWhitespace(true);
|
||||
int fiframeindnex;
|
||||
token = parser.ReadToken();
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out fiframeindnex) || fiframeindnex < 0)
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected frame index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to collection
|
||||
FrameStructure fifs = new FrameStructure { FrameIndex = fiframeindnex, ModelIndex = fimodelindnex, SpriteName = fispritename };
|
||||
if(!frames.ContainsKey(fispritename))
|
||||
{
|
||||
frames.Add(fispritename, new HashSet<FrameStructure>());
|
||||
frames[fispritename].Add(fifs);
|
||||
}
|
||||
else if(frames[fispritename].Contains(fifs))
|
||||
{
|
||||
parser.LogWarning("Duplicate FrameIndex definition");
|
||||
}
|
||||
else
|
||||
{
|
||||
frames[fispritename].Add(fifs);
|
||||
}
|
||||
break;
|
||||
|
||||
//Frame <XXXX> <X> <model index> <"frame name">
|
||||
case "frame":
|
||||
// Sprite name
|
||||
parser.SkipWhitespace(true);
|
||||
string spritename = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(spritename))
|
||||
{
|
||||
parser.ReportError("Expected sprite name");
|
||||
return false;
|
||||
}
|
||||
if(spritename.Length != 4)
|
||||
{
|
||||
parser.ReportError("Sprite name must be 4 characters long");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sprite frame
|
||||
parser.SkipWhitespace(true);
|
||||
token = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(token))
|
||||
{
|
||||
parser.ReportError("Expected sprite frame");
|
||||
return false;
|
||||
}
|
||||
if(token.Length != 1)
|
||||
{
|
||||
parser.ReportError("Sprite frame must be 1 character long");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make full name
|
||||
spritename += token;
|
||||
|
||||
// Model index
|
||||
parser.SkipWhitespace(true);
|
||||
int modelindnex;
|
||||
token = parser.ReadToken();
|
||||
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelindnex) || modelindnex < 0)
|
||||
{
|
||||
// Not numeric!
|
||||
parser.ReportError("Expected model index, but got \"" + token + "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Frame name
|
||||
parser.SkipWhitespace(true);
|
||||
string framename = parser.StripTokenQuotes(parser.ReadToken());
|
||||
if(string.IsNullOrEmpty(framename))
|
||||
{
|
||||
parser.ReportError("Expected frame name");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to collection
|
||||
FrameStructure fs = new FrameStructure { FrameName = framename, ModelIndex = modelindnex, SpriteName = spritename };
|
||||
if(!frames.ContainsKey(spritename))
|
||||
{
|
||||
frames.Add(spritename, new HashSet<FrameStructure>());
|
||||
frames[spritename].Add(fs);
|
||||
}
|
||||
else if(frames[spritename].Contains(fs))
|
||||
{
|
||||
parser.LogWarning("Duplicate Frame definition");
|
||||
}
|
||||
else
|
||||
{
|
||||
frames[spritename].Add(fs);
|
||||
}
|
||||
break;
|
||||
|
||||
case "{":
|
||||
parser.ReportError("Unexpected scope start");
|
||||
return false;
|
||||
|
||||
// Structure ends here
|
||||
case "}":
|
||||
parsingfinished = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find closing brace, then quit
|
||||
while(parser.SkipWhitespace(true))
|
||||
// Perform some integrity checks
|
||||
if(!parsingfinished)
|
||||
{
|
||||
token = parser.ReadToken();
|
||||
if(string.IsNullOrEmpty(token) || token == "}") break;
|
||||
}
|
||||
|
||||
// Bail out when got errors or no models are used
|
||||
if(Array.IndexOf(modelsUsed, true) == -1)
|
||||
{
|
||||
parser.ReportError("No models are used by \"" + classname + "\"");
|
||||
parser.ReportError("Unclosed structure scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Classname is set in ModeldefParser
|
||||
ModelData = new ModelData { InheritActorPitch = inheritactorpitch, InheritActorRoll = inheritactorroll };
|
||||
Matrix moffset = Matrix.Translation(offset.Y, -offset.X, offset.Z); // Things are complicated in GZDoom...
|
||||
Matrix mrotation = Matrix.RotationY(-Angle2D.DegToRad(rollOffset)) * Matrix.RotationX(-Angle2D.DegToRad(pitchOffset)) * Matrix.RotationZ(Angle2D.DegToRad(angleOffset));
|
||||
ModelData.SetTransform(mrotation, moffset, scale);
|
||||
|
||||
for(int i = 0; i < modelNames.Length; i++)
|
||||
// Any models defined?
|
||||
bool valid = false;
|
||||
for(int i = 0; i < modelnames.Length; i++)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(modelNames[i]) && modelsUsed[i])
|
||||
if(!string.IsNullOrEmpty(modelnames[i]))
|
||||
{
|
||||
ModelData.TextureNames.Add(string.IsNullOrEmpty(textureNames[i]) ? string.Empty : textureNames[i].ToLowerInvariant());
|
||||
ModelData.ModelNames.Add(modelNames[i].ToLowerInvariant());
|
||||
ModelData.FrameNames.Add(frameNames[i]);
|
||||
ModelData.FrameIndices.Add(frameIndices[i]);
|
||||
//INFO: skin may be defined in the model itself, so we don't check it here
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ModelData.ModelNames.Count == 0)
|
||||
if(!valid)
|
||||
{
|
||||
parser.ReportError("\"" + classname + "\" has no models");
|
||||
parser.ReportError("Structure doesn't define any models");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check skin-model associations
|
||||
for(int i = 0; i < texturenames.Length; i++)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(texturenames[i]) && string.IsNullOrEmpty(modelnames[i]))
|
||||
{
|
||||
parser.ReportError("No model is defined for skin " + i + ":\"" + texturenames[i] + "\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,11 +375,11 @@ namespace CodeImp.DoomBuilder
|
|||
General.Map.Graphics.Reset();
|
||||
General.MainWindow.RedrawDisplay();
|
||||
}
|
||||
else if(General.Editing.Mode is VisualMode)
|
||||
/*else if(General.Editing.Mode is VisualMode)
|
||||
{
|
||||
//General.MainWindow.StopExclusiveMouseInput();
|
||||
//General.MainWindow.StartExclusiveMouseInput();
|
||||
}
|
||||
General.MainWindow.StopExclusiveMouseInput();
|
||||
General.MainWindow.StartExclusiveMouseInput();
|
||||
}*/
|
||||
}
|
||||
|
||||
General.MainWindow.FocusDisplay();
|
||||
|
|
|
@ -1615,7 +1615,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
graphics.Shaders.Display2D.Texture1 = label.Texture;
|
||||
SetWorldTransformation(false);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, false);
|
||||
graphics.Device.SetStreamSource(0, label.VertexBuffer, 0, FlatVertex.Stride);
|
||||
|
||||
// Draw
|
||||
|
@ -1648,7 +1648,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
|
||||
graphics.Device.SetRenderState(RenderState.FogEnable, false);
|
||||
SetWorldTransformation(false);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
|
||||
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, false);
|
||||
|
||||
// Begin drawing
|
||||
graphics.Shaders.Display2D.Begin();
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
public TextAlignmentX AlignX { get { return alignx; } set { alignx = value; updateneeded = true; } }
|
||||
public TextAlignmentY AlignY { get { return aligny; } set { aligny = value; updateneeded = true; } }
|
||||
public PixelColor Color { get { return color; } set { if(!color.Equals(value)) { color = value; textureupdateneeded = true; } } }
|
||||
public PixelColor Backcolor { get { return backcolor; } set { if(!backcolor.Equals(value)) { backcolor = value; textureupdateneeded = true; } } }
|
||||
public PixelColor BackColor { get { return backcolor; } set { if(!backcolor.Equals(value)) { backcolor = value; textureupdateneeded = true; } } }
|
||||
public bool DrawBackground { get { return drawbg; } set { if(drawbg != value) { drawbg = value; textureupdateneeded = true; } } } //mxd
|
||||
internal Texture Texture { get { return texture; } } //mxd
|
||||
internal VertexBuffer VertexBuffer { get { return textbuffer; } }
|
||||
|
@ -109,7 +109,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
this.font = General.Settings.TextLabelFont; //mxd
|
||||
this.rect = new RectangleF(0f, 0f, 1f, 1f);
|
||||
this.color = new PixelColor(255, 255, 255, 255);
|
||||
this.backcolor = new PixelColor(255, 0, 0, 0);
|
||||
this.backcolor = new PixelColor(128, 0, 0, 0);
|
||||
this.alignx = TextAlignmentX.Center;
|
||||
this.aligny = TextAlignmentY.Top;
|
||||
this.textsize = new SizeF();
|
||||
|
@ -118,10 +118,6 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
|
||||
// Register as resource
|
||||
General.Map.Graphics.RegisterResource(this);
|
||||
|
||||
//mxd. Create the buffer
|
||||
this.textbuffer = new VertexBuffer(General.Map.Graphics.Device, 4 * FlatVertex.Stride,
|
||||
Usage.Dynamic | Usage.WriteOnly, VertexFormat.None, Pool.Default);
|
||||
|
||||
// We have no destructor
|
||||
GC.SuppressFinalize(this);
|
||||
|
@ -203,7 +199,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
}
|
||||
|
||||
// Create label image
|
||||
Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg);
|
||||
Bitmap img = CreateLabelImage(text, font, alignx, aligny, color, backcolor, drawbg);
|
||||
textsize = img.Size;
|
||||
|
||||
// Create texture
|
||||
|
@ -234,6 +230,13 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
case TextAlignmentY.Bottom: beginy = absview.Y + absview.Height - textsize.Height; break;
|
||||
}
|
||||
|
||||
//mxd. Create the buffer
|
||||
if(textbuffer == null || textbuffer.Disposed)
|
||||
{
|
||||
textbuffer = new VertexBuffer(General.Map.Graphics.Device, 4 * FlatVertex.Stride,
|
||||
Usage.Dynamic | Usage.WriteOnly, VertexFormat.None, Pool.Default);
|
||||
}
|
||||
|
||||
//mxd. Lock the buffer
|
||||
using(DataStream stream = textbuffer.Lock(0, 4 * FlatVertex.Stride, LockFlags.Discard | LockFlags.NoSystemLock))
|
||||
{
|
||||
|
@ -258,7 +261,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
}
|
||||
|
||||
//mxd
|
||||
private static Bitmap CreateLabelImage(string text, Font font, PixelColor color, PixelColor backcolor, bool drawbg)
|
||||
private static Bitmap CreateLabelImage(string text, Font font, TextAlignmentX alignx, TextAlignmentY aligny, PixelColor color, PixelColor backcolor, bool drawbg)
|
||||
{
|
||||
PointF textorigin = new PointF(4, 3);
|
||||
RectangleF textrect = new RectangleF(textorigin, General.Interface.MeasureString(text, font));
|
||||
|
@ -266,7 +269,25 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
textrect.Height = (float)Math.Round(textrect.Height);
|
||||
RectangleF bgrect = new RectangleF(0, 0, textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);
|
||||
|
||||
Bitmap result = new Bitmap((int)bgrect.Width, (int)bgrect.Height);
|
||||
// Make PO2 image, for speed and giggles...
|
||||
RectangleF po2rect = new RectangleF(0, 0, General.NextPowerOf2((int)bgrect.Width), General.NextPowerOf2((int)bgrect.Height));
|
||||
|
||||
switch(alignx)
|
||||
{
|
||||
case TextAlignmentX.Center: bgrect.X = (po2rect.Width - bgrect.Width) / 2; break;
|
||||
case TextAlignmentX.Right: bgrect.X = po2rect.Width - bgrect.Width; break;
|
||||
}
|
||||
|
||||
switch(aligny)
|
||||
{
|
||||
case TextAlignmentY.Middle: bgrect.Y = (po2rect.Height - bgrect.Height) / 2; break;
|
||||
case TextAlignmentY.Bottom: bgrect.Y = po2rect.Height - bgrect.Height; break;
|
||||
}
|
||||
|
||||
textrect.X += bgrect.X;
|
||||
textrect.Y += bgrect.Y;
|
||||
|
||||
Bitmap result = new Bitmap((int)po2rect.Width, (int)po2rect.Height);
|
||||
using(Graphics g = Graphics.FromImage(result))
|
||||
{
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
@ -276,7 +297,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
// Draw text
|
||||
using(StringFormat sf = new StringFormat())
|
||||
{
|
||||
sf.FormatFlags = StringFormatFlags.NoWrap;
|
||||
sf.FormatFlags = StringFormatFlags.FitBlackBox | StringFormatFlags.NoWrap;
|
||||
sf.Alignment = StringAlignment.Center;
|
||||
sf.LineAlignment = StringAlignment.Center;
|
||||
|
||||
|
@ -319,21 +340,20 @@ namespace CodeImp.DoomBuilder.Rendering
|
|||
using(SolidBrush brush = new SolidBrush(backcolor.ToColor()))
|
||||
g.DrawString(text, font, brush, textrect, sf);
|
||||
}
|
||||
// Draw text with outline
|
||||
// Draw plain text
|
||||
else
|
||||
{
|
||||
RectangleF pathrect = textrect;
|
||||
pathrect.Inflate(1, 3);
|
||||
RectangleF plainbgrect = textrect;
|
||||
if(text.Length > 1) plainbgrect.Inflate(6, 2);
|
||||
|
||||
GraphicsPath p = new GraphicsPath();
|
||||
p.AddString(text, font.FontFamily, (int)font.Style, g.DpiY * font.Size / 72f, pathrect, sf);
|
||||
RectangleF plaintextrect = textrect;
|
||||
plaintextrect.Inflate(6, 4);
|
||||
|
||||
// Draw'n'fill text
|
||||
using(Pen pen = new Pen(backcolor.ToColor(), 3))
|
||||
g.DrawPath(pen, p);
|
||||
using(SolidBrush brush = new SolidBrush(backcolor.ToColor()))
|
||||
g.FillRectangle(brush, plainbgrect);
|
||||
|
||||
using(SolidBrush brush = new SolidBrush(color.ToColor()))
|
||||
g.FillPath(brush, p);
|
||||
g.DrawString(text, font, brush, plaintextrect, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,16 +204,19 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
// Constructor
|
||||
internal MainForm()
|
||||
{
|
||||
// Fetch pointer
|
||||
windowptr = base.Handle;
|
||||
|
||||
//mxd. Graphics
|
||||
graphics = Graphics.FromHwndInternal(windowptr);
|
||||
|
||||
//mxd. Set DPI-aware icon size
|
||||
using(Graphics g = this.CreateGraphics())
|
||||
{
|
||||
DPIScaler = new SizeF(g.DpiX / 96, g.DpiY / 96);
|
||||
DPIScaler = new SizeF(graphics.DpiX / 96, graphics.DpiY / 96);
|
||||
|
||||
if(DPIScaler.Width != 1.0f || DPIScaler.Height != 1.0f)
|
||||
{
|
||||
ScaledIconSize.Width = (int)Math.Round(ScaledIconSize.Width * DPIScaler.Width);
|
||||
ScaledIconSize.Height = (int)Math.Round(ScaledIconSize.Height * DPIScaler.Height);
|
||||
}
|
||||
if(DPIScaler.Width != 1.0f || DPIScaler.Height != 1.0f)
|
||||
{
|
||||
ScaledIconSize.Width = (int)Math.Round(ScaledIconSize.Width * DPIScaler.Width);
|
||||
ScaledIconSize.Height = (int)Math.Round(ScaledIconSize.Height * DPIScaler.Height);
|
||||
}
|
||||
|
||||
// Setup controls
|
||||
|
@ -234,9 +237,6 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
labelcollapsedinfo.Text = "";
|
||||
display.Dock = DockStyle.Fill;
|
||||
|
||||
// Fetch pointer
|
||||
windowptr = base.Handle;
|
||||
|
||||
// Make array for view modes
|
||||
viewmodesbuttons = new ToolStripButton[Renderer2D.NUM_VIEW_MODES];
|
||||
viewmodesbuttons[(int)ViewMode.Normal] = buttonviewnormal;
|
||||
|
@ -290,9 +290,6 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
//mxd. Hints
|
||||
hintsPanel = new HintsPanel();
|
||||
hintsDocker = new Docker("hints", "Help", hintsPanel);
|
||||
|
||||
//mxd. Graphics
|
||||
graphics = Graphics.FromHwndInternal(windowptr);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -2679,14 +2676,14 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
private string GetDisplayFilename(string filename)
|
||||
{
|
||||
// String doesnt fit?
|
||||
if(GetStringWidth(filename) > MAX_RECENT_FILES_PIXELS)
|
||||
if(MeasureString(filename, this.Font).Width > MAX_RECENT_FILES_PIXELS)
|
||||
{
|
||||
// Start chopping off characters
|
||||
for(int i = filename.Length - 6; i >= 0; i--)
|
||||
{
|
||||
// Does it fit now?
|
||||
string newname = filename.Substring(0, 3) + "..." + filename.Substring(filename.Length - i, i);
|
||||
if(GetStringWidth(newname) <= MAX_RECENT_FILES_PIXELS) return newname;
|
||||
if(MeasureString(newname, this.Font).Width <= MAX_RECENT_FILES_PIXELS) return newname;
|
||||
}
|
||||
|
||||
// Cant find anything that fits (most unlikely!)
|
||||
|
@ -2699,14 +2696,6 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
}
|
||||
}
|
||||
|
||||
// This returns the width of a string
|
||||
private float GetStringWidth(string str)
|
||||
{
|
||||
Graphics g = Graphics.FromHwndInternal(this.Handle);
|
||||
SizeF strsize = g.MeasureString(str, this.Font);
|
||||
return strsize.Width;
|
||||
}
|
||||
|
||||
// Exit clicked
|
||||
private void itemexit_Click(object sender, EventArgs e) { this.Close(); }
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
l.AlignX = TextAlignmentX.Center;
|
||||
l.AlignY = TextAlignmentY.Middle;
|
||||
l.Color = General.Colors.InfoLine;
|
||||
l.Backcolor = General.Colors.Background.WithAlpha(255);
|
||||
l.BackColor = General.Colors.Background.WithAlpha(128);
|
||||
larr[i] = l;
|
||||
}
|
||||
|
||||
|
@ -430,7 +430,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
l.AlignX = TextAlignmentX.Center;
|
||||
l.AlignY = TextAlignmentY.Middle;
|
||||
l.Color = (linedef == highlighted ? General.Colors.Selection : General.Colors.Highlight);
|
||||
l.Backcolor = General.Colors.Background.WithAlpha(255);
|
||||
l.BackColor = General.Colors.Background.WithAlpha(192);
|
||||
l.Text = (++index).ToString();
|
||||
labels.Add(linedef, l);
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
labelarray[i].AlignX = TextAlignmentX.Center;
|
||||
labelarray[i].AlignY = TextAlignmentY.Middle;
|
||||
labelarray[i].Color = c;
|
||||
labelarray[i].Backcolor = General.Colors.Background.WithAlpha(255);
|
||||
labelarray[i].BackColor = General.Colors.Background.WithAlpha(128);
|
||||
}
|
||||
labels.Add(s, labelarray);
|
||||
}
|
||||
|
|
|
@ -936,7 +936,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
l.AlignX = TextAlignmentX.Center;
|
||||
l.AlignY = TextAlignmentY.Middle;
|
||||
l.Color = General.Colors.InfoLine;
|
||||
l.Backcolor = General.Colors.Background.WithAlpha(255);
|
||||
l.BackColor = General.Colors.Background.WithAlpha(128);
|
||||
larr[i] = l;
|
||||
}
|
||||
|
||||
|
@ -982,8 +982,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
l.Color = (thing == highlighted ? General.Colors.Selection : General.Colors.Highlight);
|
||||
l.Backcolor = General.Colors.Background.WithAlpha(255);
|
||||
l.DrawBackground = true;
|
||||
l.BackColor = General.Colors.Background.WithAlpha(192);
|
||||
l.Text = (++index).ToString();
|
||||
labels.Add(thing, l);
|
||||
}
|
||||
|
|
|
@ -103,12 +103,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Initialization
|
||||
private void Initialize()
|
||||
{
|
||||
label = new TextLabel();
|
||||
label.AlignX = TextAlignmentX.Center;
|
||||
label.AlignY = TextAlignmentY.Middle;
|
||||
label.Color = General.Colors.Highlight;
|
||||
label.Backcolor = General.Colors.Background;
|
||||
label.TransformCoords = true;
|
||||
label = new TextLabel
|
||||
{
|
||||
AlignX = TextAlignmentX.Center,
|
||||
AlignY = TextAlignmentY.Middle,
|
||||
Color = General.Colors.Highlight,
|
||||
BackColor = General.Colors.Background.WithAlpha(64),
|
||||
TransformCoords = true,
|
||||
};
|
||||
}
|
||||
|
||||
// Disposer
|
||||
|
|
Loading…
Reference in a new issue