diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 72858a3739f25e508fe71071d5614f7946e64321..0bdd93ea2d78f42c8a00c0c672073965d56f67e0 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -715,6 +715,7 @@
     <Compile Include="GZBuilder\Data\GZDoomLight.cs" />
     <Compile Include="GZBuilder\Data\ModeldefEntry.cs" />
     <Compile Include="GZBuilder\Data\ThingBoundingBox.cs" />
+    <Compile Include="GZBuilder\GZDoom\GldefsParser.cs" />
     <Compile Include="GZBuilder\GZDoom\ModeldefParser.cs" />
     <Compile Include="GZBuilder\GZDoom\ModeldefStructure.cs" />
     <Compile Include="GZBuilder\GZGeneral.cs" />
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index f01c688f1c1cc5240711281c67fac0e82f5497e2..bca1ac74abd32b1eb97ed789293432956d3eeed2 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -1394,7 +1394,7 @@ namespace CodeImp.DoomBuilder.Data
             return false;
         }
 
-        //mxd. This parses modeldefs
+        //mxd. This parses modeldefs. Should be called after all DECORATE actors are parsed
         private void loadModeldefs() {
             General.MainWindow.DisplayStatus(StatusType.Busy, "Parsing model definitions...");
 
@@ -1423,16 +1423,10 @@ namespace CodeImp.DoomBuilder.Data
 
                 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) {
+                    if (mdeParser.Parse(group.Value, currentreader.Location.location + "\\" + group.Key)) {
+                        foreach (KeyValuePair<string, ModeldefEntry> g in mdeParser.ModelDefEntries) {
                             g.Value.Location = currentreader.Location.location;
                             modelDefEntriesByName.Add(g.Key, g.Value);
                         }
@@ -1444,11 +1438,10 @@ namespace CodeImp.DoomBuilder.Data
             modeldefEntries = new Dictionary<int, ModeldefEntry>();
 
             foreach (KeyValuePair<string, ModeldefEntry> e in modelDefEntriesByName) {
-                if (Actors.ContainsKey(e.Key)) {
+                if (Actors.ContainsKey(e.Key))
                     modeldefEntries[Actors[e.Key]] = modelDefEntriesByName[e.Key];
-                } else {
+                else
                     GZBuilder.GZGeneral.LogAndTraceWarning("Got MODELDEF override for class '" + e.Key + "', but haven't found such class in Decorate");
-                }
             }
         }
 
diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs
index 50da0f4d364d2b2218f9d298d55e47f5a8d53a0f..0cecb7b136783acf7a8ddd7d402604f4567f12bc 100644
--- a/Source/Core/Data/DataReader.cs
+++ b/Source/Core/Data/DataReader.cs
@@ -159,10 +159,6 @@ namespace CodeImp.DoomBuilder.Data
         //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
 	}
 }
diff --git a/Source/Core/GZBuilder/GZDoom/GldefsParser.cs b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cb07a72e9d502958af9a41478dab53cc49b8667
--- /dev/null
+++ b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
@@ -0,0 +1,348 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+using CodeImp.DoomBuilder.ZDoom;
+
+using SlimDX;
+using SlimDX.Direct3D9;
+
+namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
+    public class GldefsParser : ZDTextParser {
+        private Dictionary<string, GldefsLight> gldefsEntries;
+        public Dictionary<string, GldefsLight> GldefsEntries { get { return gldefsEntries; } }
+        public string Source { get { return sourcename; } }
+
+        public override bool Parse(Stream stream, string sourcefilename) {
+            base.Parse(stream, sourcefilename);
+
+            gldefsEntries = new Dictionary<string, GldefsLight>();
+            Dictionary<string, GldefsLight> lightsByName = new Dictionary<string, GldefsLight>();
+            List<string> objects = new List<string>();
+
+            // Continue until at the end of the stream
+            while (SkipWhitespace(true)) {
+                string token = ReadToken();
+                if (!string.IsNullOrEmpty(token)) {
+                    token = token.ToLowerInvariant();
+
+                    //got light structure
+                    if (token == GldefsLightType.POINT || token == GldefsLightType.PULSE || token == GldefsLightType.FLICKER || token == GldefsLightType.FLICKER2 || token == GldefsLightType.SECTOR) {
+                        bool gotErrors = false;
+                        string lightType = token; //todo: set correct type
+                        GldefsLight light = new GldefsLight();
+
+                        //find classname
+                        SkipWhitespace(true);
+                        string lightName = ReadToken().ToLowerInvariant();
+
+                        if (!string.IsNullOrEmpty(lightName)) {
+                            if (lightsByName.ContainsKey(lightName)) {
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Already got light '" + lightName + "'; entry skipped");
+                                continue; //already got this light; continue to next one
+                            }
+
+                            //now find opening brace
+                            SkipWhitespace(true);
+                            token = ReadToken();
+                            if (token != "{") {
+                                //Form1.Trace("Unexpected token found in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got " + 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
+                            }
+
+                            //read gldefs light structure
+                            while (SkipWhitespace(true)) {
+                                token = ReadToken();
+
+                                if (!string.IsNullOrEmpty(token)) {
+                                    token = token.ToLowerInvariant();
+                                    //color
+                                    if (token == "color") {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Red)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Red Color value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Green)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Green Color value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Blue)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Blue Color value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //size
+                                    } else if (token == "size") {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.Size)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Size value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //offset
+                                    } else if (token == "offset") {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.X)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.Y)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Y value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Offset.Z)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Z value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //subtractive
+                                    } else if (token == "subtractive") {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        int i;
+                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Subtractive value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        light.Subtractive = i == 1;
+                                        //dontlightself
+                                    } else if (token == "dontlightself") {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        int i;
+                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Dontlightself value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        light.DontLightSelf = i == 1;
+                                        //interval
+                                    } else if (token == "interval" && (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER2)) {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Interval)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Interval value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //todo: modify Interval based on light type
+
+                                        //secondarysize
+                                    } else if (token == "secondarysize" && (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER || lightType == GldefsLightType.FLICKER2)) {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.SecondarySize)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected SecondarySize value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //chance
+                                    } else if (token == "chance" && lightType == GldefsLightType.FLICKER) {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Chance)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Chance value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //scale
+                                    } else if (token == "scale" && lightType == GldefsLightType.SECTOR) {
+                                        SkipWhitespace(true);
+
+                                        token = ReadToken();
+                                        if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Scale)) {
+                                            // Not numeric!
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'");
+                                            gotErrors = true;
+                                            break;
+                                        }
+
+                                        if (light.Scale < 0 || light.Scale > 1) {
+                                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": scale must be in 0.0 - 1.0 range, but is " + light.Scale);
+                                            gotErrors = true;
+                                            break;
+                                        }
+                                        //end of structure
+                                    } else if (token == "}") {
+                                        if (!gotErrors) {
+                                            //check light
+                                            bool valid = true;
+                                            if (light.Color.Red == 0.0f && light.Color.Green == 0.0f && light.Color.Blue == 0.0f) {
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("'" + lightName + "' light Color is 0,0,0. It won't be shown in GZDoom!");
+                                                valid = false;
+                                            }
+                                            if (light.Size == 0) {
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("'" + lightName + "' light Size is 0. It won't be shown in GZDoom!");
+                                                valid = false;
+                                            }
+
+                                            if (valid) lightsByName.Add(lightName, light);
+                                        }
+                                        break; //break out of this parsing loop
+                                    }
+                                }
+                            }
+                        }
+
+                    } else if (token == "object") {
+                        SkipWhitespace(true);
+
+                        //read object class
+                        string objectClass = ReadToken().ToLowerInvariant();
+
+                        if (!string.IsNullOrEmpty(objectClass)) {
+                            if (objects.Contains(objectClass)) {
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": already got object '" + objectClass + "'; entry skipped");
+                                continue; //already got this object; continue to next one
+                            }
+
+                            objects.Add(objectClass);
+
+                            //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;
+                            }
+
+                            //read frames structure
+                            while (SkipWhitespace(true)) {
+                                token = ReadToken();
+
+                                if (!string.IsNullOrEmpty(token)) {
+                                    token = token.ToLowerInvariant();
+
+                                    if (token == "light") { //just use first light from first frame and be done with it
+                                        SkipWhitespace(true);
+                                        token = ReadToken().ToLowerInvariant(); //should be light name
+
+                                        if (!string.IsNullOrEmpty(token)) {
+                                            if (lightsByName.ContainsKey(token)) {
+                                                gldefsEntries.Add(objectClass, lightsByName[token]);
+                                            } else {
+                                                GZBuilder.GZGeneral.LogAndTraceWarning("Light declaration not found for light '" + token + "' in '" + sourcefilename+"'");
+                                            }
+                                            break;
+                                        }
+                                    }
+
+                                }
+                            }
+
+                        }
+
+                    } else if (token == "#include") {
+                        SkipWhitespace(true);
+                        string includeLump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
+
+                        if (!string.IsNullOrEmpty(includeLump) && includeLump.IndexOf(".gl") != -1) {
+                            //todo: load included file. check for recursive includes?
+                        } else {
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive with missing or incorrect include path: '" + includeLump + "'");
+                        }
+
+                    } 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 (gldefsEntries.Count > 0)
+                return true;
+            return false;
+        }
+    }
+
+    public class GldefsLight {
+        public int Type;
+        public Color3 Color;
+        public int Size;
+        public int SecondarySize;
+        public float Interval;
+        public Vector3 Offset;
+        public float Chance;
+        public float Scale;
+        public bool Subtractive;
+        public bool DontLightSelf;
+
+        public GldefsLight() {
+            Color = new Color3();
+            Offset = new Vector3();
+        }
+    }
+
+    public struct GldefsLightType {
+        public const string POINT = "pointlight";
+        public const string PULSE = "pulselight";
+        public const string FLICKER = "flickerlight";
+        public const string FLICKER2 = "flickerlight2";
+        public const string SECTOR = "sectorlight";
+    }
+}
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
index af491586a8d2f6b9585d0f59531aacd4de2b021b..e5ecbc1195339758da0847c727ff94886db86ffa 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
@@ -25,6 +25,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
             // Continue until at the end of the stream
             while (SkipWhitespace(true)) {
                 string token = ReadToken();
+
                 if (token != null) {
                     token = token.ToLowerInvariant();
 
@@ -48,12 +49,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             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 {
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
index 9c53faaf71e62022222e46ee73f3649784ba5581..7296b762911a061b0722443e6def9efbd0ac8e88 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
@@ -27,21 +27,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                 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 + "'");
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line "+parser.GetCurrentLineNumber()+": expected path to model, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -54,7 +46,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model index, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -62,7 +54,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         //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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model name, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         } else {
@@ -76,7 +68,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             }
 
                             if (modelNames[modelIndex] != null) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Error: already got model for index " + modelIndex + " in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": already got model for index " + modelIndex);
                                 gotErrors = true;
                                 break;
                             } else {
@@ -92,7 +84,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected skin index, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -100,7 +92,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         //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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected skin name, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         } else {
@@ -111,7 +103,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                                 token = ModeldefParser.INVALID_TEXTURE;
 
                             if (textureNames[skinIndex] != null) {
-                                GZBuilder.GZGeneral.LogAndTraceWarning("Already got model for index " + skinIndex + " in " + parser.Source + " at line " + parser.GetCurrentLineNumber());
+                                GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": already got model for index " + skinIndex);
                                 gotErrors = true;
                                 break;
                             } else {
@@ -132,7 +124,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale X value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -150,7 +142,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale Y value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -169,7 +161,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected scale Z value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
@@ -188,7 +180,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
 
                         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());
+                            GZBuilder.GZGeneral.LogAndTraceWarning("Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected ZOffset value, but got '" + token + "'");
                             gotErrors = true;
                             break;
                         }
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index c3b147837982b0bcc36b89c59cc4ff083c120867..166d3412aaa957cee62cad475c093411f5dcb5e9 100644
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -544,13 +544,16 @@ namespace CodeImp.DoomBuilder.Rendering
 			ApplyMatrices3D();
 			RenderSinglePass((int)RenderPass.Solid);
 
-            //mxd. Render models
+            //mxd. Render models, without culling. The way it's done in GZDoom... Fixes Rendering of things like grass and models with negative Scale
+            graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
+            graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
             RenderModels();
+            graphics.Device.SetRenderState(RenderState.CullMode, Cull.Counterclockwise);
 
 			// MASK PASS
             world = Matrix.Identity;
             ApplyMatrices3D();
-            graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
+            //graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
             RenderSinglePass((int)RenderPass.Mask);
 
             // ALPHA PASS
diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs
index 14924fa3f14b665be35452db2aaa80716038b4cf..0e7a8a839742d44c4b48d6b1ad21254ed5c0620c 100644
--- a/Source/Core/ZDoom/ZDTextParser.cs
+++ b/Source/Core/ZDoom/ZDTextParser.cs
@@ -297,24 +297,6 @@ namespace CodeImp.DoomBuilder.ZDoom
 		// This reports an error
 		protected internal void ReportError(string message)
 		{
-			/*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);*/
-			
 			// Set error information
 			errordesc = message;
             errorline = GetCurrentLineNumber();