diff --git a/Builder.sln.DotSettings.user b/Builder.sln.DotSettings.user
index 66ccfb21..9af4ab9e 100644
--- a/Builder.sln.DotSettings.user
+++ b/Builder.sln.DotSettings.user
@@ -4,4 +4,6 @@
DO_NOT_SHOW
UDMF
<Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
- <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
\ No newline at end of file
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ True
+ True
\ No newline at end of file
diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 94e8b858..28070d03 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -209,6 +209,7 @@
Component
+
@@ -1307,6 +1308,7 @@
+
@@ -1365,6 +1367,7 @@
+
diff --git a/Source/Core/BuilderMono.csproj b/Source/Core/BuilderMono.csproj
index 0af6f83a..66d5d4db 100644
--- a/Source/Core/BuilderMono.csproj
+++ b/Source/Core/BuilderMono.csproj
@@ -206,6 +206,7 @@
Component
+
diff --git a/Source/Core/Config/ProgramConfiguration.cs b/Source/Core/Config/ProgramConfiguration.cs
index 50ecf744..57e41880 100755
--- a/Source/Core/Config/ProgramConfiguration.cs
+++ b/Source/Core/Config/ProgramConfiguration.cs
@@ -146,6 +146,9 @@ namespace CodeImp.DoomBuilder.Config
private bool dynamicgridsize;
private int ignoredremoterevision;
+ //volte
+ private bool classicRendering;
+
// These are not stored in the configuration, only used at runtime
private int defaultbrightness;
private int defaultfloorheight;
@@ -270,6 +273,9 @@ namespace CodeImp.DoomBuilder.Config
public bool RenderGrid { get { return rendergrid; } internal set { rendergrid = value; } } //mxd
public bool DynamicGridSize { get { return dynamicgridsize; } internal set { dynamicgridsize = value; } } //mxd
internal int IgnoredRemoteRevision { get { return ignoredremoterevision; } set { ignoredremoterevision = value; } } //mxd
+
+ //volte
+ public bool ClassicRendering { get { return classicRendering; } internal set { classicRendering = value; } }
//mxd. Left here for compatibility reasons...
public string DefaultTexture { get { return General.Map != null ? General.Map.Options.DefaultWallTexture : "-"; } set { if(General.Map != null) General.Map.Options.DefaultWallTexture = value; } }
@@ -404,6 +410,9 @@ namespace CodeImp.DoomBuilder.Config
dynamicgridsize = cfg.ReadSetting("dynamicgridsize", true); //mxd
ignoredremoterevision = cfg.ReadSetting("ignoredremoterevision", 0); //mxd
+ // volte
+ classicRendering = cfg.ReadSetting("classicrendering", false);
+
//mxd. Sector defaults
defaultceilheight = cfg.ReadSetting("defaultceilheight", 128);
defaultfloorheight = cfg.ReadSetting("defaultfloorheight", 0);
@@ -544,6 +553,9 @@ namespace CodeImp.DoomBuilder.Config
cfg.WriteSetting("dynamicgridsize", dynamicgridsize); //mxd
cfg.WriteSetting("ignoredremoterevision", ignoredremoterevision); //mxd
+ //volte
+ cfg.WriteSetting("classicrendering", classicRendering);
+
//mxd. Sector defaults
cfg.WriteSetting("defaultceilheight", defaultceilheight);
cfg.WriteSetting("defaultfloorheight", defaultfloorheight);
diff --git a/Source/Core/Data/ColorMap.cs b/Source/Core/Data/ColorMap.cs
new file mode 100644
index 00000000..06a7faaa
--- /dev/null
+++ b/Source/Core/Data/ColorMap.cs
@@ -0,0 +1,107 @@
+#region ================== Copyright
+
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#endregion
+
+#region ================== Namespaces
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Runtime.CompilerServices;
+using CodeImp.DoomBuilder.Rendering;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.Data
+{
+ public sealed class ColorMap
+ {
+ #region ================== Constants
+
+ #endregion
+
+ #region ================== Variables
+
+ private PixelColor[] colors;
+
+ #endregion
+
+ #region ================== Properties
+
+ public PixelColor this[int index] { get { return colors[index]; } }
+
+ #endregion
+
+ #region ================== Constructor / Disposer
+
+ // Constructor
+ public ColorMap()
+ {
+ colors = new PixelColor[34 * 256];
+ for(int i = 0; i < 34 * 256; i++)
+ {
+ // Set colors to gray
+ colors[i].r = 127;
+ colors[i].g = 127;
+ colors[i].b = 127;
+ colors[i].a = 255;
+ }
+ }
+
+ // Constructor
+ public ColorMap(Stream stream, Playpal palette)
+ {
+ BinaryReader reader = new BinaryReader(stream);
+ var colors = new List();
+
+ // Read all palette entries
+ stream.Seek(0, SeekOrigin.Begin);
+ while (stream.Position < stream.Length)
+ {
+ // Read colors
+ var index = reader.ReadByte();
+ var color = palette[index];
+ colors.Add(color);
+ }
+
+ this.colors = colors.ToArray();
+ }
+
+ #endregion
+
+ #region ================== Methods
+
+ public Bitmap CreateBitmap() {
+ var width = 256;
+ var height = (int)Math.Ceiling((float)colors.Length / 256);
+ var bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int index = width * y + x;
+ bitmap.SetPixel(x, y, colors[index].ToColor());
+ }
+ }
+ return bitmap;
+ }
+
+ #endregion
+ }
+}
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index ed7852f6..eece1803 100755
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -66,7 +66,8 @@ namespace CodeImp.DoomBuilder.Data
// Palette
private Playpal palette;
-
+ private ColorMap mainColormap;
+
// Textures, Flats and Sprites
private Dictionary textures;
private Dictionary texturenamesshorttofull; //mxd
@@ -163,6 +164,7 @@ namespace CodeImp.DoomBuilder.Data
internal IEnumerable Containers { get { return containers; } }
public Playpal Palette { get { return palette; } }
+ public ColorMap MainColorMap { get { return mainColormap; } }
public ICollection Textures { get { return textures.Values; } }
public ICollection Flats { get { return flats.Values; } }
public List TextureNames { get { return texturenames; } }
@@ -428,6 +430,7 @@ namespace CodeImp.DoomBuilder.Data
// Load stuff
LoadX11R6RGB(); //mxd
LoadPalette();
+ LoadMainColorMap();
Dictionary cachedparsers = new Dictionary(); //mxd
int texcount = LoadTextures(texturesonly, texturenamesshorttofull, cachedparsers);
int flatcount = LoadFlats(flatsonly, flatnamesshorttofull, cachedparsers);
@@ -839,6 +842,24 @@ namespace CodeImp.DoomBuilder.Data
}
}
+ private void LoadMainColorMap()
+ {
+ // Go for all opened containers
+ for(int i = containers.Count - 1; i >= 0; i--)
+ {
+ // Load palette
+ mainColormap = containers[i].LoadMainColorMap(palette);
+ if(mainColormap != null) break;
+ }
+
+ // Make empty palette when still no palette found
+ if(mainColormap == null)
+ {
+ General.ErrorLogger.Add(ErrorType.Warning, "None of the loaded resources define a colormap. Did you forget to configure an IWAD for this game configuration?");
+ mainColormap = new ColorMap();
+ }
+ }
+
#endregion
#region ================== Colormaps
diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs
index 7bef45e9..932ec8c0 100755
--- a/Source/Core/Data/DataReader.cs
+++ b/Source/Core/Data/DataReader.cs
@@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.IO;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
+using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.ZDoom;
#endregion
@@ -164,6 +165,8 @@ namespace CodeImp.DoomBuilder.Data
// When implemented, this should find and load a PLAYPAL palette
public virtual Playpal LoadPalette() { return null; }
+
+ public virtual ColorMap LoadMainColorMap(Playpal palette) { return null; }
#endregion
diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs
index 1e97762c..2d0a288b 100755
--- a/Source/Core/Data/ImageData.cs
+++ b/Source/Core/Data/ImageData.cs
@@ -37,7 +37,8 @@ namespace CodeImp.DoomBuilder.Data
public abstract unsafe class ImageData : IDisposable
{
#region ================== Constants
-
+
+ public const int TEXTURE_INDEXED = 1;
#endregion
#region ================== Variables
@@ -61,6 +62,7 @@ namespace CodeImp.DoomBuilder.Data
protected bool hasPatchWithSameName; //mxd
protected int namewidth; // biwa
protected int shortnamewidth; // biwa
+ protected bool wantIndexed; // volte
//mxd. Hashing
private static int hashcounter;
@@ -85,6 +87,7 @@ namespace CodeImp.DoomBuilder.Data
private int mipmaplevels; // 0 = all mipmaps
protected bool dynamictexture;
private Texture texture;
+ private Texture indexedTexture;
// Disposing
protected bool isdisposed;
@@ -105,7 +108,8 @@ namespace CodeImp.DoomBuilder.Data
public bool HasPatchWithSameName { get { return hasPatchWithSameName; } } //mxd
internal bool HasLongName { get { return hasLongName; } } //mxd
public bool UseColorCorrection { get { return usecolorcorrection; } set { usecolorcorrection = value; } }
- public Texture Texture { get { return GetTexture(); } }
+ public Texture Texture { get { return GetTexture(false); } }
+ public Texture IndexedTexture { get { return GetTexture(true); } }
public bool IsPreviewLoaded
{
get
@@ -176,6 +180,7 @@ namespace CodeImp.DoomBuilder.Data
previewbitmap?.Dispose();
spritepreviewbitmap?.Dispose();
texture?.Dispose();
+ indexedTexture?.Dispose();
loadedbitmap = null;
previewbitmap = null;
spritepreviewbitmap = null;
@@ -330,6 +335,7 @@ namespace CodeImp.DoomBuilder.Data
loadedbitmap?.Dispose();
texture?.Dispose();
+ indexedTexture?.Dispose();
imagestate = ImageLoadState.Ready;
loadedbitmap = loadResult.bitmap;
alphatest = loadResult.alphatest;
@@ -676,30 +682,78 @@ namespace CodeImp.DoomBuilder.Data
loadResult.bitmap.UnlockBits(bmpdata);
}
- Texture GetTexture()
+ Texture GetTexture(bool indexed = false)
{
- if (texture != null)
- return texture;
- else if (imagestate == ImageLoadState.Loading)
- return General.Map.Data.LoadingTexture;
- else if (loadfailed)
- return General.Map.Data.FailedTexture;
+ if (indexed && indexedTexture != null)
+ return indexedTexture;
+ if (!indexed && texture != null)
+ return texture;
- if (imagestate == ImageLoadState.None)
- {
- General.Map.Data.QueueLoadImage(this);
- return General.Map.Data.LoadingTexture;
- }
+ if (indexed && !wantIndexed)
+ {
+ // indexed texture requested, but we didn't generate it, so we have to reload the image
+ ReleaseTexture();
+ imagestate = ImageLoadState.None;
+ wantIndexed = true;
+ }
+
+ if (imagestate == ImageLoadState.Loading)
+ return General.Map.Data.LoadingTexture;
+ if (loadfailed)
+ return General.Map.Data.FailedTexture;
- texture = new Texture(General.Map.Graphics, loadedbitmap);
+ if (imagestate == ImageLoadState.None)
+ {
+ General.Map.Data.QueueLoadImage(this);
+ return General.Map.Data.LoadingTexture;
+ }
+
+ if (loadedbitmap == null)
+ {
+ return General.Map.Data.LoadingTexture;
+ }
- loadedbitmap.Dispose();
- loadedbitmap = null;
+ texture = new Texture(General.Map.Graphics, loadedbitmap);
+ if (wantIndexed)
+ {
+ Bitmap indexedBitmap = CreateIndexedBitmap(loadedbitmap, General.Map.Data.Palette);
+ indexedTexture = new Texture(General.Map.Graphics, indexedBitmap);
+ indexedTexture.UserData = TEXTURE_INDEXED;
+ }
+
+ loadedbitmap.Dispose();
+ loadedbitmap = null;
#if DEBUG
texture.Tag = name; //mxd. Helps with tracking undisposed resources...
#endif
- return texture;
+
+ return indexed ? indexedTexture : texture;
+ }
+
+ Bitmap CreateIndexedBitmap(Bitmap original, Playpal palette)
+ {
+ int[] indices = new int[original.Width * original.Height];
+
+ Bitmap indexed = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
+ BitmapData indata = original.LockBits(new Rectangle(0, 0, original.Size.Width, original.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
+ PixelColor* inpixels = (PixelColor*)indata.Scan0.ToPointer();
+ General.Colors.QuantizeColorsToPlaypal(inpixels, indices, palette);
+
+ BitmapData outdata = indexed.LockBits(new Rectangle(0, 0, indexed.Size.Width, indexed.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
+ PixelColor *outpixels = (PixelColor*)outdata.Scan0.ToPointer();
+ for (int i = 0; i < indices.Length; i++)
+ {
+ outpixels[i].r = (byte)indices[i];
+ outpixels[i].g = 0;
+ outpixels[i].b = 0;
+ outpixels[i].a = inpixels[i].a;
+ }
+
+ original.UnlockBits(indata);
+ indexed.UnlockBits(outdata);
+
+ return indexed;
}
// This updates a dynamic texture
@@ -718,6 +772,8 @@ namespace CodeImp.DoomBuilder.Data
{
texture?.Dispose();
texture = null;
+ indexedTexture?.Dispose();
+ indexedTexture = null;
}
// This returns a preview image
diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs
index c932e976..99cc69ba 100755
--- a/Source/Core/Data/PK3StructuredReader.cs
+++ b/Source/Core/Data/PK3StructuredReader.cs
@@ -151,6 +151,37 @@ namespace CodeImp.DoomBuilder.Data
// Done
return palette;
}
+
+ // This loads the COLORMAP
+ public override ColorMap LoadMainColorMap(Playpal palette)
+ {
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Colormap from wad(s)
+ ColorMap colormap = null;
+ foreach(WADReader wr in wads)
+ {
+ ColorMap wadcolormap = wr.LoadMainColorMap(palette);
+ if(wadcolormap != null) return wadcolormap;
+ }
+
+ // Find in root directory
+ string foundfile = FindFirstFile("COLORMAP", false);
+ if((foundfile != null) && FileExists(foundfile))
+ {
+ MemoryStream stream = LoadFile(foundfile);
+
+ if(stream.Length >= 256) //mxd
+ colormap = new ColorMap(stream, palette);
+ else
+ General.ErrorLogger.Add(ErrorType.Warning, "Warning: invalid colormap \"" + foundfile + "\"");
+ stream.Dispose();
+ }
+
+ // Done
+ return colormap;
+ }
#endregion
diff --git a/Source/Core/Data/Playpal.cs b/Source/Core/Data/Playpal.cs
index d90cc0fb..92b719ec 100755
--- a/Source/Core/Data/Playpal.cs
+++ b/Source/Core/Data/Playpal.cs
@@ -16,6 +16,9 @@
#region ================== Namespaces
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
using System.IO;
using CodeImp.DoomBuilder.Rendering;
@@ -38,7 +41,7 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Properties
public PixelColor this[int index] { get { return colors[index]; } }
-
+
#endregion
#region ================== Constructor / Disposer
@@ -84,6 +87,38 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Methods
+ public Bitmap CreateBitmap() {
+ var bitmap = new Bitmap(16, 16, PixelFormat.Format32bppRgb);
+ for (int y = 0; y < 16; y++) {
+ for (int x = 0; x < 16; x++) {
+ int index = 16 * y + x;
+ bitmap.SetPixel(x, y, colors[index].ToColor());
+ }
+ }
+ return bitmap;
+ }
+
+ public int FindClosestColor(PixelColor match)
+ {
+ float minDist = 99999;
+ int minIndex = 0;
+ for (int i = 0; i < colors.Length; i++)
+ {
+ PixelColor color = colors[i];
+ float dr = (float)match.r - (float)color.r;
+ float dg = (float)match.g - (float)color.g;
+ float db = (float)match.b - (float)color.b;
+ float sqDist = dr * dr + dg * dg + db * db;
+ if (sqDist < minDist)
+ {
+ minIndex = i;
+ minDist = sqDist;
+ }
+ }
+
+ return minIndex;
+ }
+
#endregion
}
}
diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs
index a0e60b36..2a14be00 100755
--- a/Source/Core/Data/WADReader.cs
+++ b/Source/Core/Data/WADReader.cs
@@ -26,6 +26,7 @@ using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Data.Scripting;
using CodeImp.DoomBuilder.GZBuilder.Data;
using CodeImp.DoomBuilder.IO;
+using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.ZDoom;
#endregion
@@ -308,6 +309,21 @@ namespace CodeImp.DoomBuilder.Data
return null; // No palette
}
+ public override ColorMap LoadMainColorMap(Playpal palette)
+ {
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Look for a lump named COLORMAP
+ Lump lump = file.FindLump("COLORMAP");
+ if (lump != null)
+ {
+ using (Stream s = lump.GetSafeStream())
+ return new ColorMap(s, palette);
+ }
+ return null; // No palette
+ }
+
#endregion
#region ================== Colormaps
diff --git a/Source/Core/Properties/Resources.Designer.cs b/Source/Core/Properties/Resources.Designer.cs
index dacd671f..0b487770 100755
--- a/Source/Core/Properties/Resources.Designer.cs
+++ b/Source/Core/Properties/Resources.Designer.cs
@@ -210,6 +210,16 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap ClassicRendering {
+ get {
+ object obj = ResourceManager.GetObject("ClassicRendering", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/Source/Core/Properties/Resources.resx b/Source/Core/Properties/Resources.resx
index 0af1b28f..b52d9d29 100755
--- a/Source/Core/Properties/Resources.resx
+++ b/Source/Core/Properties/Resources.resx
@@ -532,6 +532,9 @@
..\Resources\Sky.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\ClassicRendering.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\Pin.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
diff --git a/Source/Core/Rendering/ColorCollection.cs b/Source/Core/Rendering/ColorCollection.cs
index 1ffef750..ae5d2c5b 100755
--- a/Source/Core/Rendering/ColorCollection.cs
+++ b/Source/Core/Rendering/ColorCollection.cs
@@ -19,6 +19,7 @@
using System;
using System.Globalization;
using System.Drawing;
+using CodeImp.DoomBuilder.Data;
using Configuration = CodeImp.DoomBuilder.IO.Configuration;
#endregion
@@ -275,6 +276,12 @@ namespace CodeImp.DoomBuilder.Rendering
cp->b = correctiontable[cp->b];
}
}
+
+ // This quantizes an image to a PLAYPAL lump, putting indices into an array of integers.
+ internal unsafe void QuantizeColorsToPlaypal(PixelColor* inPixels, int[] indices, Playpal playpal)
+ {
+ System.Threading.Tasks.Parallel.For(0, indices.Length, (i) => indices[i] = playpal.FindClosestColor(inPixels[i]));
+ }
// This clamps a value between 0 and 1
private static float Saturate(float v)
diff --git a/Source/Core/Rendering/IRenderer3D.cs b/Source/Core/Rendering/IRenderer3D.cs
index 9beb3c60..8d18a7c8 100755
--- a/Source/Core/Rendering/IRenderer3D.cs
+++ b/Source/Core/Rendering/IRenderer3D.cs
@@ -17,6 +17,7 @@
#region ================== Namespaces
using System.Collections.Generic;
+using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.VisualModes;
@@ -45,7 +46,8 @@ namespace CodeImp.DoomBuilder.Rendering
// Rendering methods
int CalculateBrightness(int level);
int CalculateBrightness(int level, Sidedef sd); //mxd
-
+
+ void SetClassicLightingColorMap(ColorMap colormap);
void SetHighlightedObject(IVisualPickable obj);
void AddSectorGeometry(VisualGeometry g);
void AddThingGeometry(VisualThing t);
diff --git a/Source/Core/Rendering/RenderDevice.cs b/Source/Core/Rendering/RenderDevice.cs
index bb64ecfa..c7088273 100755
--- a/Source/Core/Rendering/RenderDevice.cs
+++ b/Source/Core/Rendering/RenderDevice.cs
@@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Controls;
@@ -69,6 +70,11 @@ namespace CodeImp.DoomBuilder.Rendering
DeclareUniform(UniformName.sectorfogcolor, "sectorfogcolor", UniformType.Vec4f);
DeclareUniform(UniformName.lightsEnabled, "lightsEnabled", UniformType.Float);
DeclareUniform(UniformName.slopeHandleLength, "slopeHandleLength", UniformType.Float);
+
+ // volte: classic rendering
+ DeclareUniform(UniformName.drawPaletted, "drawPaletted", UniformType.Int);
+ DeclareUniform(UniformName.colormapSize, "colormapSize", UniformType.Vec2i);
+ DeclareUniform(UniformName.lightLevel, "lightLevel", UniformType.Int);
// 2d fsaa
CompileShader(ShaderName.display2d_fsaa, "display2d.shader", "display2d_fsaa");
@@ -90,6 +96,10 @@ namespace CodeImp.DoomBuilder.Rendering
CompileShader(ShaderName.world3d_vertex_color, "world3d.shader", "world3d_vertex_color");
CompileShader(ShaderName.world3d_main_vertexcolor, "world3d.shader", "world3d_main_vertexcolor");
CompileShader(ShaderName.world3d_constant_color, "world3d.shader", "world3d_constant_color");
+
+ // classic rendering
+ CompileShader(ShaderName.world3d_classic, "world3d.shader", "world3d_classic");
+ CompileShader(ShaderName.world3d_classic_highlight, "world3d.shader", "world3d_classic_highlight");
// skybox shader
CompileShader(ShaderName.world3d_skybox, "world3d_skybox.shader", "world3d_skybox");
@@ -125,7 +135,11 @@ namespace CodeImp.DoomBuilder.Rendering
Handle = RenderDevice_New(display, RenderTarget.Handle);
if (Handle == IntPtr.Zero)
- throw new RenderDeviceException(string.Format("Could not create render device: {0}", BuilderNative_GetError()));
+ {
+ StringBuilder sb = new StringBuilder(4096);
+ BuilderNative_GetError(sb, sb.Capacity);
+ throw new RenderDeviceException(string.Format("Could not create render device: {0}", sb));
+ }
}
public bool Disposed { get { return Handle == IntPtr.Zero; } }
@@ -133,7 +147,11 @@ namespace CodeImp.DoomBuilder.Rendering
void ThrowIfFailed(bool result)
{
if (!result)
- throw new RenderDeviceException(BuilderNative_GetError());
+ {
+ StringBuilder sb = new StringBuilder(4096);
+ BuilderNative_GetError(sb, sb.Capacity);
+ throw new RenderDeviceException(sb.ToString());
+ }
}
public void Dispose()
@@ -359,24 +377,24 @@ namespace CodeImp.DoomBuilder.Rendering
RenderDevice_SetZWriteEnable(Handle, value);
}
- public void SetTexture(BaseTexture value)
+ public void SetTexture(BaseTexture value, int unit = 0)
{
- RenderDevice_SetTexture(Handle, value != null ? value.Handle : IntPtr.Zero);
+ RenderDevice_SetTexture(Handle, unit, value != null ? value.Handle : IntPtr.Zero);
}
- public void SetSamplerFilter(TextureFilter filter)
+ public void SetSamplerFilter(TextureFilter filter, int unit = 0)
{
- SetSamplerFilter(filter, filter, MipmapFilter.None, 0.0f);
+ SetSamplerFilter(filter, filter, MipmapFilter.None, 0.0f, unit);
}
- public void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy)
+ public void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy, int unit = 0)
{
- RenderDevice_SetSamplerFilter(Handle, minfilter, magfilter, mipfilter, maxanisotropy);
+ RenderDevice_SetSamplerFilter(Handle, unit, minfilter, magfilter, mipfilter, maxanisotropy);
}
- public void SetSamplerState(TextureAddress address)
+ public void SetSamplerState(TextureAddress address, int unit = 0)
{
- RenderDevice_SetSamplerState(Handle, address);
+ RenderDevice_SetSamplerState(Handle, unit, address);
}
public void DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount)
@@ -564,7 +582,7 @@ namespace CodeImp.DoomBuilder.Rendering
static extern void RenderDevice_DeclareShader(IntPtr handle, ShaderName index, string name, string vertexShader, string fragShader);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- static extern string BuilderNative_GetError();
+ static extern void BuilderNative_GetError(StringBuilder str, int length);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern bool RenderDevice_SetShader(IntPtr handle, ShaderName name);
@@ -615,13 +633,13 @@ namespace CodeImp.DoomBuilder.Rendering
static extern void RenderDevice_SetZWriteEnable(IntPtr handle, bool value);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- static extern void RenderDevice_SetTexture(IntPtr handle, IntPtr texture);
+ static extern void RenderDevice_SetTexture(IntPtr handle, int unit, IntPtr texture);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- static extern void RenderDevice_SetSamplerFilter(IntPtr handle, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy);
+ static extern void RenderDevice_SetSamplerFilter(IntPtr handle, int unit, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- static extern void RenderDevice_SetSamplerState(IntPtr handle, TextureAddress address);
+ static extern void RenderDevice_SetSamplerState(IntPtr handle, int unit, TextureAddress address);
[DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
static extern bool RenderDevice_Draw(IntPtr handle, PrimitiveType type, int startIndex, int primitiveCount);
@@ -735,7 +753,10 @@ namespace CodeImp.DoomBuilder.Rendering
world3d_main_highlight_fog_vertexcolor,
world3d_vertex_color,
world3d_constant_color,
- world3d_slope_handle
+ world3d_slope_handle,
+ world3d_classic,
+ world3d_p19,
+ world3d_classic_highlight
}
public enum UniformType : int
@@ -778,7 +799,10 @@ namespace CodeImp.DoomBuilder.Rendering
fogcolor,
sectorfogcolor,
lightsEnabled,
- slopeHandleLength
+ slopeHandleLength,
+ drawPaletted,
+ colormapSize,
+ lightLevel
}
public enum VertexFormat : int { Flat, World }
diff --git a/Source/Core/Rendering/Renderer.cs b/Source/Core/Rendering/Renderer.cs
index b6c6d478..0aa2e21e 100755
--- a/Source/Core/Rendering/Renderer.cs
+++ b/Source/Core/Rendering/Renderer.cs
@@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Rendering
// Disposing
public bool IsDisposed { get { return isdisposed; } }
public static bool FullBrightness { get { return fullbrightness; } set { fullbrightness = value; } } //mxd
-
+
#endregion
#region ================== Constructor / Disposer
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 4a710bdc..e845921a 100755
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
+using System.Drawing.Drawing2D;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.GZBuilder.Data;
@@ -26,6 +27,7 @@ using CodeImp.DoomBuilder.GZBuilder.MD3;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.VisualModes;
using CodeImp.DoomBuilder.GZBuilder;
+using ColorMap = System.Drawing.Imaging.ColorMap;
#endregion
@@ -64,7 +66,10 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd
private VisualVertexHandle vertexhandle;
private int[] lightOffsets;
-
+
+ private Data.ColorMap classicLightingColorMap = null;
+ private Texture classicLightingColorMapTex = null;
+
// Slope handle
private VisualSlopeHandle visualslopehandle;
@@ -135,6 +140,11 @@ namespace CodeImp.DoomBuilder.Rendering
public bool ShowSelection { get { return showselection; } set { showselection = value; } }
public bool ShowHighlight { get { return showhighlight; } set { showhighlight = value; } }
+ protected bool UseIndexedTexture
+ {
+ get { return General.Settings.ClassicRendering && !fullbrightness; }
+ }
+
#endregion
#region ================== Constructor / Disposer
@@ -294,6 +304,25 @@ namespace CodeImp.DoomBuilder.Rendering
billboard = Matrix.RotationZ((float)(anglexy + Angle2D.PI));
}
+
+ // volte: Set the active colormap for classic lighting
+ public void SetClassicLightingColorMap(Data.ColorMap colormap)
+ {
+ if (colormap == classicLightingColorMap)
+ {
+ return;
+ }
+ classicLightingColorMap = colormap;
+ if (classicLightingColorMap == null)
+ {
+ classicLightingColorMapTex = null;
+ }
+ else
+ {
+ classicLightingColorMapTex = new Texture(graphics, classicLightingColorMap.CreateBitmap());
+ }
+ }
+
// This creates 2D view matrix
private void CreateMatrices2D()
{
@@ -302,7 +331,7 @@ namespace CodeImp.DoomBuilder.Rendering
Matrix translate = Matrix.Translation(-(float)windowsize.Width * 0.5f, -(float)windowsize.Height * 0.5f, 0f);
view2d = translate * scaling;
}
-
+
#endregion
#region ================== Start / Finish
@@ -327,13 +356,15 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.SetUniform(UniformName.fogcolor, General.Colors.Background.ToColorValue());
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
graphics.SetUniform(UniformName.highlightcolor, new Color4()); //mxd
- TextureFilter texFilter = General.Settings.VisualBilinear ? TextureFilter.Linear : TextureFilter.Nearest;
- graphics.SetSamplerFilter(texFilter, texFilter, MipmapFilter.Linear, General.Settings.FilterAnisotropy);
+ TextureFilter texFilter = (!General.Settings.ClassicRendering && General.Settings.VisualBilinear) ? TextureFilter.Linear : TextureFilter.Nearest;
+ MipmapFilter mipFilter = General.Settings.ClassicRendering ? MipmapFilter.None : MipmapFilter.Linear;
+ float aniso = General.Settings.ClassicRendering ? 0 : General.Settings.FilterAnisotropy;
+ graphics.SetSamplerFilter(texFilter, texFilter, mipFilter, aniso);
// Texture addressing
graphics.SetSamplerState(TextureAddress.Wrap);
- // Matrices
+ // Matrices
world = Matrix.Identity;
graphics.SetUniform(UniformName.projection, ref projection);
graphics.SetUniform(UniformName.world, ref world);
@@ -352,7 +383,18 @@ namespace CodeImp.DoomBuilder.Rendering
}
// Determine shader pass to use
- shaderpass = (fullbrightness ? ShaderName.world3d_fullbright : ShaderName.world3d_main);
+ if (fullbrightness)
+ {
+ shaderpass = ShaderName.world3d_fullbright;
+ }
+ else if (General.Settings.ClassicRendering)
+ {
+ shaderpass = ShaderName.world3d_classic;
+ }
+ else
+ {
+ shaderpass = ShaderName.world3d_main;
+ }
// Create crosshair vertices
if(crosshairverts == null)
@@ -787,14 +829,25 @@ namespace CodeImp.DoomBuilder.Rendering
bool hadlights = false;
+ // volte: Set textures for classic lighting
+ if (classicLightingColorMap != null)
+ {
+ graphics.SetUniform(UniformName.colormapSize, new Vector2i(classicLightingColorMapTex.Width, classicLightingColorMapTex.Height));
+ graphics.SetTexture(classicLightingColorMapTex, 1);
+ graphics.SetSamplerFilter(TextureFilter.Nearest, TextureFilter.Nearest, MipmapFilter.None, 0, 1);
+ graphics.SetSamplerState(TextureAddress.Clamp, 1);
+ }
+
// Render the geometry collected
foreach (KeyValuePair> group in geopass)
{
curtexture = group.Key;
- // Apply texture
- graphics.SetTexture(curtexture.Texture);
-
+ // Apply texture
+ Texture texture = UseIndexedTexture ? curtexture.IndexedTexture : curtexture.Texture;
+ graphics.SetTexture(texture);
+ graphics.SetUniform(UniformName.drawPaletted, texture.UserData == ImageData.TEXTURE_INDEXED);
+
//mxd. Sort geometry by sector index
group.Value.Sort((g1, g2) => g1.Sector.Sector.FixedIndex - g2.Sector.Sector.FixedIndex);
@@ -880,7 +933,7 @@ namespace CodeImp.DoomBuilder.Rendering
ShaderName wantedshaderpass = (((g == highlighted) && showhighlight) || (g.Selected && showselection)) ? highshaderpass : shaderpass;
//mxd. Render fog?
- if(General.Settings.GZDrawFog && !fullbrightness && sector.Sector.FogMode != SectorFogMode.NONE)
+ if(General.Settings.GZDrawFog && !fullbrightness && !General.Settings.ClassicRendering && sector.Sector.FogMode != SectorFogMode.NONE)
wantedshaderpass += 8;
// Switch shader pass?
@@ -895,6 +948,9 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.SetUniform(UniformName.modelnormal, Matrix.Identity);
}
}
+
+ // volte: set sector light level for classic rendering mode
+ graphics.SetUniform(UniformName.lightLevel, sector.Sector.Brightness);
//mxd. Set variables for fog rendering?
if(wantedshaderpass > ShaderName.world3d_p7)
@@ -933,8 +989,10 @@ namespace CodeImp.DoomBuilder.Rendering
curtexture = group.Key;
- // Apply texture
- graphics.SetTexture(curtexture.Texture);
+ // Apply texture
+ Texture texture = UseIndexedTexture ? curtexture.IndexedTexture : curtexture.Texture;
+ graphics.SetTexture(texture);
+ graphics.SetUniform(UniformName.drawPaletted, texture.UserData == ImageData.TEXTURE_INDEXED);
// Render all things with this texture
foreach(VisualThing t in group.Value)
@@ -958,20 +1016,20 @@ namespace CodeImp.DoomBuilder.Rendering
ShaderName wantedshaderpass = (((t == highlighted) && showhighlight) || (t.Selected && showselection)) ? highshaderpass : shaderpass;
//mxd. If fog is enagled, switch to shader, which calculates it
- if(General.Settings.GZDrawFog && !fullbrightness && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
+ if(General.Settings.GZDrawFog && !fullbrightness && !General.Settings.ClassicRendering && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
wantedshaderpass += 8;
//mxd. Create the matrix for positioning
world = CreateThingPositionMatrix(t);
//mxd. If current thing is light - set it's color to light color
- if(t.LightType != null && t.LightType.LightInternal && !fullbrightness)
+ if(t.LightType != null && t.LightType.LightInternal && !fullbrightness && !General.Settings.ClassicRendering)
{
wantedshaderpass += 4; // Render using one of passes, which uses World3D.VertexColor
vertexcolor = t.LightColor;
}
//mxd. Check if Thing is affected by dynamic lights and set color accordingly
- else if(General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && lightthings.Count > 0)
+ else if(General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && !General.Settings.ClassicRendering && lightthings.Count > 0)
{
Color4 litcolor = GetLitColorForThing(t);
if(litcolor.ToArgb() != 0)
@@ -1000,7 +1058,11 @@ namespace CodeImp.DoomBuilder.Rendering
}
// Set the colors to use
- if(t.Thing.Sector != null) graphics.SetUniform(UniformName.sectorfogcolor, t.Thing.Sector.FogColor);
+ if (t.Thing.Sector != null)
+ {
+ graphics.SetUniform(UniformName.lightLevel, t.Thing.Sector.Brightness);
+ graphics.SetUniform(UniformName.sectorfogcolor, t.Thing.Sector.FogColor);
+ }
graphics.SetUniform(UniformName.vertexColor, vertexcolor);
graphics.SetUniform(UniformName.highlightcolor, CalculateHighlightColor((t == highlighted) && showhighlight, (t.Selected && showselection)));
@@ -1162,8 +1224,11 @@ namespace CodeImp.DoomBuilder.Rendering
{
curtexture = g.Texture;
- // Apply texture
- graphics.SetTexture(curtexture.Texture);
+ // Apply texture
+ Texture texture = UseIndexedTexture ? curtexture.IndexedTexture : curtexture.Texture;
+ graphics.SetTexture(texture);
+ graphics.SetUniform(UniformName.drawPaletted, texture.UserData == ImageData.TEXTURE_INDEXED);
+
curtexturename = g.Texture.LongName;
}
@@ -1195,7 +1260,7 @@ namespace CodeImp.DoomBuilder.Rendering
ShaderName wantedshaderpass = (((g == highlighted) && showhighlight) || (g.Selected && showselection)) ? highshaderpass : shaderpass;
//mxd. Render fog?
- if (General.Settings.GZDrawFog && !fullbrightness && sector.Sector.FogMode != SectorFogMode.NONE)
+ if (General.Settings.GZDrawFog && !fullbrightness && !General.Settings.ClassicRendering && sector.Sector.FogMode != SectorFogMode.NONE)
wantedshaderpass += 8;
// Switch shader pass?
@@ -1294,8 +1359,11 @@ namespace CodeImp.DoomBuilder.Rendering
{
curtexture = t.Texture;
- // Apply texture
- graphics.SetTexture(curtexture.Texture);
+ // Apply texture
+ Texture texture = UseIndexedTexture ? curtexture.IndexedTexture : curtexture.Texture;
+ graphics.SetTexture(texture);
+ graphics.SetUniform(UniformName.drawPaletted, texture.UserData == ImageData.TEXTURE_INDEXED);
+
curtexturename = t.Texture.LongName;
}
@@ -1306,20 +1374,20 @@ namespace CodeImp.DoomBuilder.Rendering
ShaderName wantedshaderpass = (((t == highlighted) && showhighlight) || (t.Selected && showselection)) ? highshaderpass : shaderpass;
//mxd. if fog is enagled, switch to shader, which calculates it
- if(General.Settings.GZDrawFog && !fullbrightness && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
+ if(General.Settings.GZDrawFog && !fullbrightness && !General.Settings.ClassicRendering && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
wantedshaderpass += 8;
//mxd. Create the matrix for positioning
world = CreateThingPositionMatrix(t);
//mxd. If current thing is light - set it's color to light color
- if(t.LightType != null && t.LightType.LightInternal && !fullbrightness)
+ if(t.LightType != null && t.LightType.LightInternal && !fullbrightness && !General.Settings.ClassicRendering)
{
wantedshaderpass += 4; // Render using one of passes, which uses World3D.VertexColor
vertexcolor = t.LightColor;
}
//mxd. Check if Thing is affected by dynamic lights and set color accordingly
- else if(General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && lightthings.Count > 0)
+ else if(General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && !General.Settings.ClassicRendering && lightthings.Count > 0)
{
Color4 litcolor = GetLitColorForThing(t);
if(litcolor.ToArgb() != 0)
@@ -1506,7 +1574,7 @@ namespace CodeImp.DoomBuilder.Rendering
ShaderName wantedshaderpass = ((((t == highlighted) && showhighlight) || (t.Selected && showselection)) ? highshaderpass : shaderpass);
// If fog is enagled, switch to shader, which calculates it
- if (General.Settings.GZDrawFog && !fullbrightness && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
+ if (General.Settings.GZDrawFog && !fullbrightness && !General.Settings.ClassicRendering && t.Thing.Sector != null && t.Thing.Sector.FogMode != SectorFogMode.NONE)
wantedshaderpass += 8;
// Switch shader pass?
diff --git a/Source/Core/Rendering/Texture.cs b/Source/Core/Rendering/Texture.cs
index d99f7c54..217cfcdc 100644
--- a/Source/Core/Rendering/Texture.cs
+++ b/Source/Core/Rendering/Texture.cs
@@ -1,111 +1,112 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Runtime.InteropServices;
-
-namespace CodeImp.DoomBuilder.Rendering
-{
- public enum TextureFormat : int
- {
- Rgba8,
- Bgra8,
- Rg16f,
- Rgba16f,
- R32f,
- Rg32f,
- Rgb32f,
- Rgba32f,
- D32f_S8,
- D24_S8
- }
-
- public class BaseTexture : IDisposable
- {
- public BaseTexture()
- {
- Handle = Texture_New();
- if (Handle == IntPtr.Zero)
- throw new Exception("Texture_New failed");
- }
-
- ~BaseTexture()
- {
- Dispose();
- }
-
- public bool Disposed { get { return Handle == IntPtr.Zero; } }
-
- public void Dispose()
- {
- if (!Disposed)
- {
- Texture_Delete(Handle);
- Handle = IntPtr.Zero;
- }
- }
-
- internal IntPtr Handle;
-
- [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- protected static extern IntPtr Texture_New();
-
- [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- protected static extern void Texture_Delete(IntPtr handle);
-
- [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- protected static extern void Texture_Set2DImage(IntPtr handle, int width, int height, TextureFormat format);
-
- [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
- protected static extern void Texture_SetCubeImage(IntPtr handle, int size, TextureFormat format);
- }
-
- public class Texture : BaseTexture
- {
- public Texture(int width, int height, TextureFormat format)
- {
- Width = width;
- Height = height;
- Format = format;
- Texture_Set2DImage(Handle, Width, Height, Format);
- }
-
- public Texture(RenderDevice device, System.Drawing.Bitmap bitmap)
- {
- Width = bitmap.Width;
- Height = bitmap.Height;
- Format = TextureFormat.Bgra8;
- Texture_Set2DImage(Handle, Width, Height, Format);
- device.SetPixels(this, bitmap);
- }
-
- public Texture(RenderDevice device, System.Drawing.Image image)
- {
- using (var bitmap = new System.Drawing.Bitmap(image))
- {
- Width = bitmap.Width;
- Height = bitmap.Height;
- Format = TextureFormat.Bgra8;
- Texture_Set2DImage(Handle, Width, Height, Format);
- device.SetPixels(this, bitmap);
- }
- }
-
- public int Width { get; private set; }
- public int Height { get; private set; }
- public TextureFormat Format { get; private set; }
-
- public object Tag { get; set; }
- }
-
- public class CubeTexture : BaseTexture
- {
- public CubeTexture(RenderDevice device, int size)
- {
- Texture_SetCubeImage(Handle, size, TextureFormat.Bgra8);
- }
- }
-
- public enum CubeMapFace : int { PositiveX, PositiveY, PositiveZ, NegativeX, NegativeY, NegativeZ }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+namespace CodeImp.DoomBuilder.Rendering
+{
+ public enum TextureFormat : int
+ {
+ Rgba8,
+ Bgra8,
+ Rg16f,
+ Rgba16f,
+ R32f,
+ Rg32f,
+ Rgb32f,
+ Rgba32f,
+ D32f_S8,
+ D24_S8
+ }
+
+ public class BaseTexture : IDisposable
+ {
+ public BaseTexture()
+ {
+ Handle = Texture_New();
+ if (Handle == IntPtr.Zero)
+ throw new Exception("Texture_New failed");
+ }
+
+ ~BaseTexture()
+ {
+ Dispose();
+ }
+
+ public bool Disposed { get { return Handle == IntPtr.Zero; } }
+
+ public void Dispose()
+ {
+ if (!Disposed)
+ {
+ Texture_Delete(Handle);
+ Handle = IntPtr.Zero;
+ }
+ }
+
+ internal IntPtr Handle;
+
+ [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
+ protected static extern IntPtr Texture_New();
+
+ [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
+ protected static extern void Texture_Delete(IntPtr handle);
+
+ [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
+ protected static extern void Texture_Set2DImage(IntPtr handle, int width, int height, TextureFormat format);
+
+ [DllImport("BuilderNative", CallingConvention = CallingConvention.Cdecl)]
+ protected static extern void Texture_SetCubeImage(IntPtr handle, int size, TextureFormat format);
+ }
+
+ public class Texture : BaseTexture
+ {
+ public Texture(int width, int height, TextureFormat format)
+ {
+ Width = width;
+ Height = height;
+ Format = format;
+ Texture_Set2DImage(Handle, Width, Height, Format);
+ }
+
+ public Texture(RenderDevice device, System.Drawing.Bitmap bitmap)
+ {
+ Width = bitmap.Width;
+ Height = bitmap.Height;
+ Format = TextureFormat.Bgra8;
+ Texture_Set2DImage(Handle, Width, Height, Format);
+ device.SetPixels(this, bitmap);
+ }
+
+ public Texture(RenderDevice device, System.Drawing.Image image)
+ {
+ using (var bitmap = new System.Drawing.Bitmap(image))
+ {
+ Width = bitmap.Width;
+ Height = bitmap.Height;
+ Format = TextureFormat.Bgra8;
+ Texture_Set2DImage(Handle, Width, Height, Format);
+ device.SetPixels(this, bitmap);
+ }
+ }
+
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public TextureFormat Format { get; private set; }
+
+ public object Tag { get; set; }
+ public int UserData { get; set; }
+ }
+
+ public class CubeTexture : BaseTexture
+ {
+ public CubeTexture(RenderDevice device, int size)
+ {
+ Texture_SetCubeImage(Handle, size, TextureFormat.Bgra8);
+ }
+ }
+
+ public enum CubeMapFace : int { PositiveX, PositiveY, PositiveZ, NegativeX, NegativeY, NegativeZ }
+}
diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg
index e739692b..9690d234 100755
--- a/Source/Core/Resources/Actions.cfg
+++ b/Source/Core/Resources/Actions.cfg
@@ -1330,6 +1330,16 @@ gztogglevisualvertices
default = 262230;
}
+toggleclassicrendering
+{
+ title = "Toggle classic rendering";
+ category = "visual";
+ description = "When enabled, attempts to simulate classic Doom rendering with banded light and palettized textures.";
+ allowkeys = true;
+ allowmouse = true;
+ allowscroll = false;
+}
+
gztoggleenhancedrendering
{
title = "Toggle Enhanced Rendering Effects";
diff --git a/Source/Core/Resources/ClassicRendering.png b/Source/Core/Resources/ClassicRendering.png
new file mode 100644
index 00000000..81b944c8
Binary files /dev/null and b/Source/Core/Resources/ClassicRendering.png differ
diff --git a/Source/Core/Resources/world3d.shader b/Source/Core/Resources/world3d.shader
index 84503bd7..0e54d50b 100755
--- a/Source/Core/Resources/world3d.shader
+++ b/Source/Core/Resources/world3d.shader
@@ -6,7 +6,7 @@ uniforms
mat4 modelnormal;
vec4 campos;
- vec4 highlightcolor;
+ vec4 highlightcolor;
vec4 stencilColor;
float desaturation;
@@ -16,30 +16,90 @@ uniforms
vec4 vertexColor;
sampler2D texture1;
+ sampler2D texture2;
+ sampler2D texture3;
+
+ // classic lighting related
+ int drawPaletted;
+ ivec2 colormapSize;
+ int lightLevel;
// dynamic light related
- vec4 lightPosAndRadius[64];
- vec4 lightOrientation[64]; // this is a vector that points in light's direction
- vec2 light2Radius[64]; // this is used with spotlights
- vec4 lightColor[64];
- float ignoreNormals;
- float lightsEnabled;
-
- // Slope handle length
- float slopeHandleLength;
-
+ vec4 lightPosAndRadius[64];
+ vec4 lightOrientation[64]; // this is a vector that points in light's direction
+ vec2 light2Radius[64]; // this is used with spotlights
+ vec4 lightColor[64];
+ float ignoreNormals;
+ float lightsEnabled;
+
+ // Slope handle length
+ float slopeHandleLength;
+
}
functions
{
- // This adds fog color to current pixel color
- vec4 getFogColor(vec3 PosW, vec4 color)
- {
- float fogdist = max(16.0, distance(PosW, campos.xyz));
- float fogfactor = exp2(campos.w * fogdist);
-
- color.rgb = mix(sectorfogcolor.rgb, color.rgb, fogfactor);
- return color;
+ vec4 getColorMappedColor(int entry, int depth)
+ {
+ vec2 uv = vec2((float(entry) + 0.5) / colormapSize.x, (float(depth) + 0.5) / colormapSize.y);
+ vec4 colormapColor = texture(texture2, uv);
+ return colormapColor;
+ }
+
+ int classicLightLevelToColorMapOffset(int lightLevel, vec3 position, vec3 normal)
+ {
+ const int LIGHTLEVELS = 16;
+ const int LIGHTSEGSHIFT = 4;
+ const int NUMCOLORMAPS = 32;
+ const int MAXLIGHTSCALE = 48;
+ const int DISTMAP = 2;
+
+ int scaledLightLevel = lightLevel >> LIGHTSEGSHIFT;
+
+ bool isFlat = abs(dot(normal, vec3(0, 0, 1))) > 1e-3;
+
+ if (abs(dot(normal, vec3(0, 1, 0))) < 1e-3)
+ {
+ scaledLightLevel++;
+ }
+ else if (abs(dot(normal, vec3(1, 0, 0))) < 1e-3)
+ {
+ scaledLightLevel--;
+ }
+
+ int level;
+ float dist = distance(position, campos.xyz);
+
+ if (!isFlat)
+ {
+ int startmap = int(((LIGHTLEVELS-1-scaledLightLevel)*2)*NUMCOLORMAPS/LIGHTLEVELS);
+
+ // same calculation as Eternity Engine
+ int index = int(2560.0 / dist);
+ if (index >= MAXLIGHTSCALE) index = MAXLIGHTSCALE - 1;
+ level = startmap - index / DISTMAP;
+ }
+ else
+ {
+ // same calculation as Eternity Engine
+ float startmap = 2.0 * (30.0 - lightLevel / 8.0f);
+ level = int(startmap - (1280.0f / dist)) + 1;
+ }
+
+
+ if (level < 0) level = 0;
+ if (level >= NUMCOLORMAPS) level = NUMCOLORMAPS - 1;
+ return level;
+ }
+
+ // This adds fog color to current pixel color
+ vec4 getFogColor(vec3 PosW, vec4 color)
+ {
+ float fogdist = max(16.0, distance(PosW, campos.xyz));
+ float fogfactor = exp2(campos.w * fogdist);
+
+ color.rgb = mix(sectorfogcolor.rgb, color.rgb, fogfactor);
+ return color;
}
vec4 desaturate(vec4 texel)
@@ -51,20 +111,20 @@ functions
vec3 getOneDynLightContribution(vec3 PosW, vec3 Normal, vec3 light, vec4 lColor, vec4 lPosAndRadius, vec4 lOrientation, vec2 l2Radius)
{
- //is face facing away from light source?
- // update 01.02.2017: offset the equation by 3px back to try to emulate GZDoom's broken visibility check.
- float diffuseContribution = dot(Normal, normalize(lPosAndRadius.xyz - PosW + Normal * 3.0));
- if (diffuseContribution < 0.0 && (ignoreNormals == 0 || (lColor.a > 0.979 && lColor.a < 0.981))) // attenuated light and facing away
- return light;
-
- diffuseContribution = max(diffuseContribution, 0.0); // to make sure
-
- //is pixel in light range?
- float dist = distance(PosW, lPosAndRadius.xyz);
-
- if (dist > lPosAndRadius.w)
- return light;
-
+ //is face facing away from light source?
+ // update 01.02.2017: offset the equation by 3px back to try to emulate GZDoom's broken visibility check.
+ float diffuseContribution = dot(Normal, normalize(lPosAndRadius.xyz - PosW + Normal * 3.0));
+ if (diffuseContribution < 0.0 && (ignoreNormals == 0 || (lColor.a > 0.979 && lColor.a < 0.981))) // attenuated light and facing away
+ return light;
+
+ diffuseContribution = max(diffuseContribution, 0.0); // to make sure
+
+ //is pixel in light range?
+ float dist = distance(PosW, lPosAndRadius.xyz);
+
+ if (dist > lPosAndRadius.w)
+ return light;
+
float power = 1.0;
power *= max(lPosAndRadius.w - dist, 0.0) / lPosAndRadius.w;
@@ -74,18 +134,18 @@ functions
float cosDir = dot(lightDirection, lOrientation.xyz);
float df = smoothstep(l2Radius.y, l2Radius.x, cosDir);
power *= df;
- }
-
+ }
+
if (lColor.a > 0.979 && lColor.a < 0.981) // attenuated light 98%
- power *= diffuseContribution;
-
- // for w/e reason GZDoom also does this
- power *= lColor.a;
-
- if (lColor.a >= 1)
- return light.rgb - lColor.rgb * power;
-
- return light.rgb + lColor.rgb * power;
+ power *= diffuseContribution;
+
+ // for w/e reason GZDoom also does this
+ power *= lColor.a;
+
+ if (lColor.a >= 1)
+ return light.rgb - lColor.rgb * power;
+
+ return light.rgb + lColor.rgb * power;
}
@@ -136,11 +196,11 @@ shader world3d_main
vertex
{
- v2f.viewpos = view * world * vec4(in.Position, 1.0);
- gl_Position = projection * v2f.viewpos;
- v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
- v2f.Color = in.Color;
- v2f.UV = in.TextureCoordinate;
+ v2f.viewpos = view * world * vec4(in.Position, 1.0);
+ gl_Position = projection * v2f.viewpos;
+ v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
+ v2f.Color = in.Color;
+ v2f.UV = in.TextureCoordinate;
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
}
@@ -163,15 +223,15 @@ shader world3d_fullbright extends world3d_main
{
fragment
{
- vec4 tcolor = texture(texture1, v2f.UV);
- tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
- tcolor.a *= v2f.Color.a;
- out.FragColor = tcolor;
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ vec4 tcolor = texture(texture1, v2f.UV);
+ tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
+ tcolor.a *= v2f.Color.a;
+ out.FragColor = tcolor;
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -180,25 +240,25 @@ shader world3d_main_highlight extends world3d_main
{
fragment
{
- vec4 tcolor = texture(texture1, v2f.UV);
- tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
+ vec4 tcolor = texture(texture1, v2f.UV);
+ tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
- if (tcolor.a == 0.0)
- {
- out.FragColor = tcolor;
- }
- else
- {
- // Blend texture color and vertex color
- vec4 ncolor = desaturate(tcolor);
-
- out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
- }
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ if (tcolor.a == 0.0)
+ {
+ out.FragColor = tcolor;
+ }
+ else
+ {
+ // Blend texture color and vertex color
+ vec4 ncolor = desaturate(tcolor);
+
+ out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
+ }
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -207,24 +267,24 @@ shader world3d_fullbright_highlight extends world3d_fullbright
{
fragment
{
- vec4 tcolor = texture(texture1, v2f.UV);
- tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
- if(tcolor.a == 0.0)
- {
- out.FragColor = tcolor;
- }
- else
- {
- // Blend texture color and vertex color
- vec4 ncolor = tcolor * v2f.Color;
-
- out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (tcolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
- }
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ vec4 tcolor = texture(texture1, v2f.UV);
+ tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
+ if(tcolor.a == 0.0)
+ {
+ out.FragColor = tcolor;
+ }
+ else
+ {
+ // Blend texture color and vertex color
+ vec4 ncolor = tcolor * v2f.Color;
+
+ out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (tcolor.rgb - 0.4 * highlightcolor.a), max(v2f.Color.a + 0.25, 0.5));
+ }
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -233,12 +293,12 @@ shader world3d_vertex_color extends world3d_main
{
fragment
{
- out.FragColor = v2f.Color;
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ out.FragColor = v2f.Color;
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -247,9 +307,9 @@ shader world3d_main_vertexcolor extends world3d_main
{
vertex
{
- v2f.viewpos = view * world * vec4(in.Position, 1.0);
- gl_Position = projection * v2f.viewpos;
- v2f.Color = vertexColor;
+ v2f.viewpos = view * world * vec4(in.Position, 1.0);
+ gl_Position = projection * v2f.viewpos;
+ v2f.Color = vertexColor;
v2f.UV = in.TextureCoordinate;
}
}
@@ -258,12 +318,12 @@ shader world3d_constant_color extends world3d_main_vertexcolor
{
fragment
{
- out.FragColor = vertexColor;
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ out.FragColor = vertexColor;
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0f) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -274,9 +334,9 @@ shader world3d_highlight_vertexcolor extends world3d_main_highlight
{
vertex
{
- v2f.viewpos = view * world * vec4(in.Position, 1.0);
- gl_Position = projection * v2f.viewpos;
- v2f.Color = vertexColor;
+ v2f.viewpos = view * world * vec4(in.Position, 1.0);
+ gl_Position = projection * v2f.viewpos;
+ v2f.Color = vertexColor;
v2f.UV = in.TextureCoordinate;
}
}
@@ -285,22 +345,22 @@ shader world3d_main_fog extends world3d_main
{
fragment
{
- vec4 tcolor = texture(texture1, v2f.UV);
- tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
- tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
- if (tcolor.a == 0.0)
- {
- out.FragColor = tcolor;
- }
- else
- {
- out.FragColor = desaturate(getFogColor(v2f.PosW, tcolor));
- }
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ vec4 tcolor = texture(texture1, v2f.UV);
+ tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
+ tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal);
+ if (tcolor.a == 0.0)
+ {
+ out.FragColor = tcolor;
+ }
+ else
+ {
+ out.FragColor = desaturate(getFogColor(v2f.PosW, tcolor));
+ }
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -309,25 +369,25 @@ shader world3d_main_highlight_fog extends world3d_main_fog
{
fragment
{
- vec4 tcolor = texture(texture1, v2f.UV);
- tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
- tcolor = vec4(getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal).rgb, tcolor.a);
- if (tcolor.a == 0.0)
- {
- out.FragColor = tcolor;
- }
- else
- {
- // Blend texture color and vertex color
- vec4 ncolor = desaturate(getFogColor(v2f.PosW, tcolor));
-
- out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(ncolor.a + 0.25, 0.5));
- }
-
- #if defined(ALPHA_TEST)
- if (out.FragColor.a < 0.5) discard;
- #endif
-
+ vec4 tcolor = texture(texture1, v2f.UV);
+ tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a);
+ tcolor = vec4(getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal).rgb, tcolor.a);
+ if (tcolor.a == 0.0)
+ {
+ out.FragColor = tcolor;
+ }
+ else
+ {
+ // Blend texture color and vertex color
+ vec4 ncolor = desaturate(getFogColor(v2f.PosW, tcolor));
+
+ out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (ncolor.rgb - 0.4 * highlightcolor.a), max(ncolor.a + 0.25, 0.5));
+ }
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+
if (fogsettings.x >= 0.0) out.FragColor = mix(out.FragColor, fogcolor, clamp((-v2f.viewpos.z - fogsettings.x) / (fogsettings.y - fogsettings.x), 0.0, 1.0));
}
}
@@ -338,11 +398,11 @@ shader world3d_main_fog_vertexcolor extends world3d_main_fog
{
vertex
{
- v2f.viewpos = view * world * vec4(in.Position, 1.0);
- gl_Position = projection * v2f.viewpos;
- v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
- v2f.Color = vertexColor;
- v2f.UV = in.TextureCoordinate;
+ v2f.viewpos = view * world * vec4(in.Position, 1.0);
+ gl_Position = projection * v2f.viewpos;
+ v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
+ v2f.Color = vertexColor;
+ v2f.UV = in.TextureCoordinate;
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
}
}
@@ -351,11 +411,11 @@ shader world3d_main_highlight_fog_vertexcolor extends world3d_main_highlight_fog
{
vertex
{
- v2f.viewpos = view * world * vec4(in.Position, 1.0);
- gl_Position = projection * v2f.viewpos;
- v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
- v2f.Color = vertexColor;
- v2f.UV = in.TextureCoordinate;
+ v2f.viewpos = view * world * vec4(in.Position, 1.0);
+ gl_Position = projection * v2f.viewpos;
+ v2f.PosW = (world * vec4(in.Position, 1.0)).xyz;
+ v2f.Color = vertexColor;
+ v2f.UV = in.TextureCoordinate;
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
}
}
@@ -370,4 +430,67 @@ shader world3d_slope_handle extends world3d_vertex_color
v2f.Color = in.Color * vertexColor;
v2f.UV = in.TextureCoordinate;
}
+}
+
+
+shader world3d_classic extends world3d_main
+{
+ fragment
+ {
+ vec4 pcolor;
+
+ if (bool(drawPaletted))
+ {
+ vec4 color = texture(texture1, v2f.UV);
+ int entry = int(color.r * 255);
+ float alpha = color.a;
+ int colorMapOffset = classicLightLevelToColorMapOffset(lightLevel, v2f.PosW, v2f.Normal);
+ pcolor = getColorMappedColor(entry, colorMapOffset);
+ pcolor.a = alpha;
+ }
+ else
+ {
+ pcolor = texture(texture1, v2f.UV);
+ }
+
+ out.FragColor = pcolor;
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+ }
+}
+
+shader world3d_classic_highlight extends world3d_main
+{
+ fragment
+ {
+ vec4 pcolor;
+
+ if (bool(drawPaletted))
+ {
+ vec4 color = texture(texture1, v2f.UV);
+ int entry = int(color.r * 255);
+ float alpha = color.a;
+ int modifiedLightLevel = max(lightLevel, 128);
+ int colorMapOffset = classicLightLevelToColorMapOffset(modifiedLightLevel, v2f.PosW, v2f.Normal);
+ pcolor = getColorMappedColor(entry, colorMapOffset);
+ pcolor.a = alpha;
+ }
+ else
+ {
+ pcolor = texture(texture1, v2f.UV);
+ }
+
+ out.FragColor = pcolor;
+
+ if (pcolor.a > 0.0)
+ {
+ out.FragColor = vec4(highlightcolor.rgb * highlightcolor.a + (pcolor.rgb - 0.4 * highlightcolor.a), max(pcolor.a + 0.25, 0.5));
+ }
+
+ #if defined(ALPHA_TEST)
+ if (out.FragColor.a < 0.5) discard;
+ #endif
+ }
}
\ No newline at end of file
diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs
index 759036c5..90e0deef 100755
--- a/Source/Core/Windows/MainForm.Designer.cs
+++ b/Source/Core/Windows/MainForm.Designer.cs
@@ -191,6 +191,7 @@ namespace CodeImp.DoomBuilder.Windows
this.itemallmdl = new System.Windows.Forms.ToolStripMenuItem();
this.itemtogglefog = new System.Windows.Forms.ToolStripMenuItem();
this.itemtogglesky = new System.Windows.Forms.ToolStripMenuItem();
+ this.itemtoggleclassicrendering = new System.Windows.Forms.ToolStripMenuItem();
this.itemtoggleeventlines = new System.Windows.Forms.ToolStripMenuItem();
this.itemtogglevisualverts = new System.Windows.Forms.ToolStripMenuItem();
this.buttonfullbrightness = new System.Windows.Forms.ToolStripButton();
@@ -224,6 +225,7 @@ namespace CodeImp.DoomBuilder.Windows
this.modelsshowall = new System.Windows.Forms.ToolStripMenuItem();
this.buttontogglefog = new System.Windows.Forms.ToolStripButton();
this.buttontogglesky = new System.Windows.Forms.ToolStripButton();
+ this.buttontoggleclassicrendering = new System.Windows.Forms.ToolStripButton();
this.buttontoggleeventlines = new System.Windows.Forms.ToolStripButton();
this.buttontogglevisualvertices = new System.Windows.Forms.ToolStripButton();
this.separatorgzmodes = new System.Windows.Forms.ToolStripSeparator();
@@ -798,6 +800,7 @@ namespace CodeImp.DoomBuilder.Windows
this.itemmodelmodes,
this.itemtogglefog,
this.itemtogglesky,
+ this.itemtoggleclassicrendering,
this.itemtoggleeventlines,
this.itemtogglevisualverts,
this.separatorhelpers,
@@ -1395,6 +1398,7 @@ namespace CodeImp.DoomBuilder.Windows
this.modelrendermode,
this.buttontogglefog,
this.buttontogglesky,
+ this.buttontoggleclassicrendering,
this.buttontoggleeventlines,
this.buttontogglevisualvertices,
this.separatorgzmodes,
@@ -1797,6 +1801,16 @@ namespace CodeImp.DoomBuilder.Windows
this.itemtogglesky.Text = "Render sky (Visual mode)";
this.itemtogglesky.Click += new System.EventHandler(this.InvokeTaggedAction);
//
+ // itemclassicrendering
+ //
+ this.itemtoggleclassicrendering.CheckOnClick = true;
+ this.itemtoggleclassicrendering.Image = global::CodeImp.DoomBuilder.Properties.Resources.ClassicRendering;
+ this.itemtoggleclassicrendering.Name = "itemtoggleclassicrendering";
+ this.itemtoggleclassicrendering.Size = new System.Drawing.Size(273, 22);
+ this.itemtoggleclassicrendering.Tag = "builder_toggleclassicrendering";
+ this.itemtoggleclassicrendering.Text = "Classic rendering (Visual mode)";
+ this.itemtoggleclassicrendering.Click += new System.EventHandler(this.InvokeTaggedAction);
+ //
// itemeventlines
//
this.itemtoggleeventlines.CheckOnClick = true;
@@ -2170,6 +2184,18 @@ namespace CodeImp.DoomBuilder.Windows
this.buttontogglesky.Text = "Render Sky (Visual mode)";
this.buttontogglesky.Click += new System.EventHandler(this.InvokeTaggedAction);
//
+ // buttontoggleclassicrendering
+ //
+ this.buttontoggleclassicrendering.CheckOnClick = true;
+ this.buttontoggleclassicrendering.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttontoggleclassicrendering.Image = global::CodeImp.DoomBuilder.Properties.Resources.ClassicRendering;
+ this.buttontoggleclassicrendering.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttontoggleclassicrendering.Name = "buttontoggleclassicrendering";
+ this.buttontoggleclassicrendering.Size = new System.Drawing.Size(23, 20);
+ this.buttontoggleclassicrendering.Tag = "builder_toggleclassicrendering";
+ this.buttontoggleclassicrendering.Text = "Classic Rendering (Visual mode)";
+ this.buttontoggleclassicrendering.Click += new System.EventHandler(this.InvokeTaggedAction);
+ //
// buttontoggleeventlines
//
this.buttontoggleeventlines.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
@@ -3013,6 +3039,7 @@ namespace CodeImp.DoomBuilder.Windows
private System.Windows.Forms.ToolStripSeparator seperatorgeometry;
private System.Windows.Forms.ToolStripButton buttontogglefog;
private System.Windows.Forms.ToolStripButton buttontogglesky;
+ private System.Windows.Forms.ToolStripButton buttontoggleclassicrendering;
private System.Windows.Forms.ToolStripStatusLabel warnsLabel;
private System.Windows.Forms.ToolStripMenuItem itemReloadModedef;
private System.Windows.Forms.ToolStripMenuItem itemReloadGldefs;
@@ -3072,6 +3099,7 @@ namespace CodeImp.DoomBuilder.Windows
private System.Windows.Forms.ToolStripMenuItem itemallmdl;
private System.Windows.Forms.ToolStripMenuItem itemtogglefog;
private System.Windows.Forms.ToolStripMenuItem itemtogglesky;
+ private System.Windows.Forms.ToolStripMenuItem itemtoggleclassicrendering;
private System.Windows.Forms.ToolStripMenuItem itemtoggleeventlines;
private System.Windows.Forms.ToolStripMenuItem itemtogglevisualverts;
private ToolStripMenuItem itemimport;
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index 47d47e60..63080077 100755
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -2164,6 +2164,7 @@ namespace CodeImp.DoomBuilder.Windows
buttonsplitjoinedsectors.Checked = General.Settings.SplitJoinedSectors; //mxd
buttonautoclearsidetextures.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd
buttontest.Visible = General.Settings.ToolbarTesting && maploaded;
+ buttontoggleclassicrendering.Visible = General.Settings.ToolbarViewModes && maploaded;
//mxd
modelrendermode.Visible = General.Settings.GZToolbarGZDoom && maploaded;
@@ -2330,6 +2331,7 @@ namespace CodeImp.DoomBuilder.Windows
buttontogglefog.Checked = General.Settings.GZDrawFog;
buttontogglesky.Checked = General.Settings.GZDrawSky;
+ buttontoggleclassicrendering.Checked = General.Settings.ClassicRendering;
buttontoggleeventlines.Checked = General.Settings.GZShowEventLines;
buttontogglevisualvertices.Visible = General.Map.UDMF;
buttontogglevisualvertices.Checked = General.Settings.GZShowVisualVertices;
@@ -3141,6 +3143,7 @@ namespace CodeImp.DoomBuilder.Windows
itemtogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd
itemtogglefog.Checked = General.Settings.GZDrawFog;
itemtogglesky.Checked = General.Settings.GZDrawSky;
+ itemtoggleclassicrendering.Checked = General.Settings.ClassicRendering;
itemtoggleeventlines.Checked = General.Settings.GZShowEventLines;
itemtogglevisualverts.Visible = (General.Map != null && General.Map.UDMF);
itemtogglevisualverts.Checked = General.Settings.GZShowVisualVertices;
@@ -3214,6 +3217,20 @@ namespace CodeImp.DoomBuilder.Windows
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateGZDoomPanel();
}
+
+ //mxd
+ [BeginAction("toggleclassicrendering")]
+ internal void ToggleClassicRendering()
+ {
+ General.Settings.ClassicRendering = !General.Settings.ClassicRendering;
+
+ itemtoggleclassicrendering.Checked = General.Settings.ClassicRendering;
+ buttontoggleclassicrendering.Checked = General.Settings.ClassicRendering;
+
+ General.MainWindow.DisplayStatus(StatusType.Action, "Classic rendering is " + (General.Settings.ClassicRendering ? "ENABLED" : "DISABLED"));
+ General.MainWindow.RedrawDisplay();
+ General.MainWindow.UpdateGZDoomPanel();
+ }
[BeginAction("gztoggleeventlines")]
internal void ToggleEventLines()
diff --git a/Source/Native/Backend.cpp b/Source/Native/Backend.cpp
index abe31c14..b361b149 100644
--- a/Source/Native/Backend.cpp
+++ b/Source/Native/Backend.cpp
@@ -76,9 +76,12 @@ extern "C"
Backend::Get()->DeleteRenderDevice(device);
}
- const char* BuilderNative_GetError()
+ void BuilderNative_GetError(char *out, int len)
{
- return GetError();
+ std::string result = mLastError;
+ result = result.substr(0, len);
+ std::copy(result.begin(), result.end(), out);
+ out[std::min(len - 1, (int)result.size())] = 0;
}
void RenderDevice_DeclareUniform(RenderDevice* device, UniformName name, const char* variablename, UniformType type)
@@ -161,19 +164,19 @@ extern "C"
device->SetZWriteEnable(value);
}
- void RenderDevice_SetTexture(RenderDevice* device, Texture* texture)
+ void RenderDevice_SetTexture(RenderDevice* device, int unit, Texture* texture)
{
- device->SetTexture(texture);
+ device->SetTexture(unit, texture);
}
- void RenderDevice_SetSamplerFilter(RenderDevice* device, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy)
+ void RenderDevice_SetSamplerFilter(RenderDevice* device, int unit, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy)
{
- device->SetSamplerFilter(minfilter, magfilter, mipfilter, maxanisotropy);
+ device->SetSamplerFilter(unit, minfilter, magfilter, mipfilter, maxanisotropy);
}
- void RenderDevice_SetSamplerState(RenderDevice* device, TextureAddress address)
+ void RenderDevice_SetSamplerState(RenderDevice* device, int unit, TextureAddress address)
{
- device->SetSamplerState(address);
+ device->SetSamplerState(unit, address);
}
bool RenderDevice_Draw(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount)
diff --git a/Source/Native/Backend.h b/Source/Native/Backend.h
index b5c18292..2d6ebbca 100644
--- a/Source/Native/Backend.h
+++ b/Source/Native/Backend.h
@@ -83,9 +83,9 @@ public:
virtual void SetMultisampleAntialias(bool value) = 0;
virtual void SetZEnable(bool value) = 0;
virtual void SetZWriteEnable(bool value) = 0;
- virtual void SetTexture(Texture* texture) = 0;
- virtual void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy) = 0;
- virtual void SetSamplerState(TextureAddress address) = 0;
+ virtual void SetTexture(int unit, Texture* texture) = 0;
+ virtual void SetSamplerFilter(int unit, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy) = 0;
+ virtual void SetSamplerState(int unit, TextureAddress address) = 0;
virtual bool Draw(PrimitiveType type, int startIndex, int primitiveCount) = 0;
virtual bool DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) = 0;
virtual bool DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) = 0;
diff --git a/Source/Native/OpenGL/GLRenderDevice.cpp b/Source/Native/OpenGL/GLRenderDevice.cpp
index ebd37497..f2f8f656 100644
--- a/Source/Native/OpenGL/GLRenderDevice.cpp
+++ b/Source/Native/OpenGL/GLRenderDevice.cpp
@@ -113,16 +113,15 @@ GLRenderDevice::~GLRenderDevice()
glDeleteVertexArrays(1, &handle);
}
- for (auto& it : mSamplers)
+ for (auto& it : mTextureUnit)
{
- for (GLuint handle : it.second.WrapModes)
- {
- if (handle != 0)
- glDeleteSamplers(1, &handle);
- }
+ GLuint &handle = it.SamplerHandle;
+ if (handle != 0)
+ {
+ glDeleteSamplers(1, &handle);
+ }
}
-
mShaderManager->ReleaseResources();
Context->ClearCurrent();
}
@@ -264,30 +263,49 @@ void GLRenderDevice::SetZWriteEnable(bool value)
}
}
-void GLRenderDevice::SetTexture(Texture* texture)
+void GLRenderDevice::SetTexture(int unit, Texture* texture)
{
- if (mTextureUnit.Tex != texture)
+ if (mTextureUnit[unit].Tex != texture)
{
- mTextureUnit.Tex = static_cast(texture);
+ mTextureUnit[unit].Tex = static_cast(texture);
mNeedApply = true;
mTexturesChanged = true;
}
}
-void GLRenderDevice::SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy)
+void GLRenderDevice::SetSamplerFilter(int unit, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy)
{
- SamplerFilterKey key;
- key.MinFilter = GetGLMinFilter(minfilter, mipfilter);
- key.MagFilter = (magfilter == TextureFilter::Nearest) ? GL_NEAREST : GL_LINEAR;
- key.MaxAnisotropy = maxanisotropy;
- if (mSamplerFilterKey != key)
- {
- mSamplerFilterKey = key;
- mSamplerFilter = &mSamplers[mSamplerFilterKey];
+ bool dirty = false;
+
+ if (mTextureUnit[unit].MinFilter != minfilter)
+ {
+ mTextureUnit[unit].MinFilter = minfilter;
+ dirty = true;
+ }
+
+ if (mTextureUnit[unit].MagFilter != magfilter)
+ {
+ mTextureUnit[unit].MagFilter = magfilter;
+ dirty = true;
+ }
+
+ if (mTextureUnit[unit].MipFilter != mipfilter)
+ {
+ mTextureUnit[unit].MipFilter = mipfilter;
+ dirty = true;
+ }
- mNeedApply = true;
- mTexturesChanged = true;
- }
+ if ( mTextureUnit[unit].MaxAnisotropy != maxanisotropy)
+ {
+ mTextureUnit[unit].MaxAnisotropy = maxanisotropy;
+ dirty = true;
+ }
+
+ if (dirty)
+ {
+ mNeedApply = true;
+ mTexturesChanged = true;
+ }
}
GLint GLRenderDevice::GetGLMinFilter(TextureFilter filter, MipmapFilter mipfilter)
@@ -315,11 +333,20 @@ GLint GLRenderDevice::GetGLMinFilter(TextureFilter filter, MipmapFilter mipfilte
}
}
-void GLRenderDevice::SetSamplerState(TextureAddress address)
+GLRenderDevice::SamplerFilterKey GLRenderDevice::GetSamplerFilterKey(TextureFilter filter, MipmapFilter mipFilter, float maxAnisotropy)
{
- if (mTextureUnit.WrapMode != address)
+ SamplerFilterKey key;
+ key.MinFilter = GetGLMinFilter(filter, mipFilter);
+ key.MagFilter = (filter == TextureFilter::Linear) ? GL_LINEAR : GL_NEAREST;
+ key.MaxAnisotropy = maxAnisotropy;
+ return key;
+}
+
+void GLRenderDevice::SetSamplerState(int unit, TextureAddress address)
+{
+ if (mTextureUnit[unit].WrapMode != address)
{
- mTextureUnit.WrapMode = address;
+ mTextureUnit[unit].WrapMode = address;
mNeedApply = true;
mTexturesChanged = true;
}
@@ -901,42 +928,47 @@ bool GLRenderDevice::ApplyUniforms()
bool GLRenderDevice::ApplyTextures()
{
- glActiveTexture(GL_TEXTURE0);
- if (mTextureUnit.Tex)
- {
- GLenum target = mTextureUnit.Tex->IsCubeTexture() ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+ bool hasError = false;
+ for (int index = 0; index < 10; index++)
+ {
+ TextureUnit &unit = mTextureUnit[index];
+ if (unit.Tex)
+ {
+ glActiveTexture(GL_TEXTURE0 + index);
+ GLenum target = unit.Tex->IsCubeTexture() ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+
+ glBindTexture(target, unit.Tex->GetTexture(this));
- glBindTexture(target, mTextureUnit.Tex->GetTexture(this));
+ SamplerFilterKey key = GetSamplerFilterKey(unit.MagFilter, unit.MipFilter, unit.MaxAnisotropy);
+ SamplerFilter &filter = mSamplers[key];
+ GLuint &samplerHandle = filter.WrapModes[(int)unit.WrapMode];
- GLuint& samplerHandle = mSamplerFilter->WrapModes[(int)mTextureUnit.WrapMode];
- if (samplerHandle == 0)
- {
- static const int wrapMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE };
+ if (samplerHandle == 0)
+ {
+ static const int wrapMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE };
- glGenSamplers(1, &samplerHandle);
- glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, mSamplerFilterKey.MinFilter);
- glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, mSamplerFilterKey.MagFilter);
- glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrapMode[(int)mTextureUnit.WrapMode]);
- glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrapMode[(int)mTextureUnit.WrapMode]);
- glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrapMode[(int)mTextureUnit.WrapMode]);
- if (mSamplerFilterKey.MaxAnisotropy > 0.0f)
- glSamplerParameterf(samplerHandle, GL_TEXTURE_MAX_ANISOTROPY_EXT, mSamplerFilterKey.MaxAnisotropy);
- }
-
- if (mTextureUnit.SamplerHandle != samplerHandle)
- {
- mTextureUnit.SamplerHandle = samplerHandle;
- glBindSampler(0, samplerHandle);
- }
- }
- else
- {
- glBindTexture(GL_TEXTURE_2D, 0);
- }
-
- mTexturesChanged = false;
-
- return CheckGLError();
+ glGenSamplers(1, &samplerHandle);
+ glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, key.MinFilter);
+ glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, key.MagFilter);
+ glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrapMode[(int)unit.WrapMode]);
+ glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrapMode[(int)unit.WrapMode]);
+ glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrapMode[(int)unit.WrapMode]);
+ if (key.MaxAnisotropy > 0.0f)
+ glSamplerParameterf(samplerHandle, GL_TEXTURE_MAX_ANISOTROPY_EXT, key.MaxAnisotropy);
+ }
+
+ if (unit.SamplerHandle != samplerHandle)
+ {
+ unit.SamplerHandle = samplerHandle;
+ glBindSampler(index, samplerHandle);
+ }
+ }
+
+ hasError |= CheckGLError();
+ }
+
+ mTexturesChanged = false;
+ return hasError;
}
std::mutex& GLRenderDevice::GetMutex()
diff --git a/Source/Native/OpenGL/GLRenderDevice.h b/Source/Native/OpenGL/GLRenderDevice.h
index e91ac9fa..c943bffe 100644
--- a/Source/Native/OpenGL/GLRenderDevice.h
+++ b/Source/Native/OpenGL/GLRenderDevice.h
@@ -54,9 +54,9 @@ public:
void SetMultisampleAntialias(bool value) override;
void SetZEnable(bool value) override;
void SetZWriteEnable(bool value) override;
- void SetTexture(Texture* texture) override;
- void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy) override;
- void SetSamplerState(TextureAddress address) override;
+ void SetTexture(int unit, Texture* texture) override;
+ void SetSamplerFilter(int unit, TextureFilter minfilter, TextureFilter magfilter, MipmapFilter mipfilter, float maxanisotropy) override;
+ void SetSamplerState(int unit, TextureAddress address) override;
bool Draw(PrimitiveType type, int startIndex, int primitiveCount) override;
bool DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) override;
bool DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) override;
@@ -114,13 +114,17 @@ public:
std::vector IndexBuffers;
std::vector Textures;
} mDeleteList;
-
+
struct TextureUnit
{
GLTexture* Tex = nullptr;
TextureAddress WrapMode = TextureAddress::Wrap;
GLuint SamplerHandle = 0;
- } mTextureUnit;
+ TextureFilter MinFilter = TextureFilter::Nearest;
+ TextureFilter MagFilter = TextureFilter::Nearest;
+ MipmapFilter MipFilter = MipmapFilter::None;
+ float MaxAnisotropy = 1;
+ } mTextureUnit[10];
struct SamplerFilterKey
{
@@ -132,15 +136,15 @@ public:
bool operator==(const SamplerFilterKey& b) const { return memcmp(this, &b, sizeof(SamplerFilterKey)) == 0; }
bool operator!=(const SamplerFilterKey& b) const { return memcmp(this, &b, sizeof(SamplerFilterKey)) != 0; }
};
-
+
struct SamplerFilter
- {
- GLuint WrapModes[2] = { 0, 0 };
- };
+ {
+ GLuint WrapModes[2] = { 0, 0 };
+ };
- std::map mSamplers;
- SamplerFilterKey mSamplerFilterKey;
- SamplerFilter* mSamplerFilter = nullptr;
+ std::map mSamplers;
+
+ SamplerFilterKey GetSamplerFilterKey(TextureFilter filter, MipmapFilter mipFilter, float maxAnisotropy);
int mVertexBuffer = -1;
int64_t mVertexBufferStartIndex = 0;
diff --git a/Source/Native/OpenGL/GLShader.cpp b/Source/Native/OpenGL/GLShader.cpp
index f819562c..32d005f9 100644
--- a/Source/Native/OpenGL/GLShader.cpp
+++ b/Source/Native/OpenGL/GLShader.cpp
@@ -41,6 +41,8 @@ bool GLShader::CheckCompile(GLRenderDevice* device)
CreateProgram(device);
glUseProgram(mProgram);
glUniform1i(glGetUniformLocation(mProgram, "texture1"), 0);
+ glUniform1i(glGetUniformLocation(mProgram, "texture2"), 1);
+ glUniform1i(glGetUniformLocation(mProgram, "texture3"), 2);
glUseProgram(0);
}
diff --git a/Source/Native/OpenGL/GLTexture.cpp b/Source/Native/OpenGL/GLTexture.cpp
index 6d2628c4..b9a0f80c 100644
--- a/Source/Native/OpenGL/GLTexture.cpp
+++ b/Source/Native/OpenGL/GLTexture.cpp
@@ -74,7 +74,7 @@ bool GLTexture::SetPixels(GLRenderDevice* device, const void* data)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexImage2D(GL_TEXTURE_2D, 0, ToInternalFormat(mFormat), mWidth, mHeight, 0, ToDataFormat(mFormat), ToDataType(mFormat), data);
- if (data != nullptr)
+ if (data != nullptr)
glGenerateMipmap(GL_TEXTURE_2D);
//
diff --git a/Source/Native/Precomp.h b/Source/Native/Precomp.h
index 569fc710..88cb80b1 100644
--- a/Source/Native/Precomp.h
+++ b/Source/Native/Precomp.h
@@ -24,9 +24,11 @@
#define _CRT_SECURE_NO_WARNINGS
#include
+#include
#include
#include