New feature: classic lighting renderer for visual mode (#680)

Added classic rendering mode to closer emulate software renderer visuals in visual mode
This commit is contained in:
volte 2022-01-04 14:17:12 -05:00 committed by GitHub
parent 90896acd43
commit 7fbd07e586
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1039 additions and 414 deletions

View file

@ -4,4 +4,6 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UDMF/@EntryIndexedValue">UDMF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=Builder_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -209,6 +209,7 @@
<Compile Include="Controls\Scripting\ScriptLumpDocumentTab.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Data\ColorMap.cs" />
<Compile Include="Data\DirectoryReader.cs" />
<Compile Include="Data\FileImage.cs" />
<Compile Include="Data\FlatImage.cs" />
@ -1307,6 +1308,7 @@
<None Include="Resources\Angle6.png" />
<None Include="Resources\Angle7.png" />
<None Include="Resources\AboutBack.png" />
<Content Include="Resources\ClassicRendering.png" />
<Content Include="Resources\DB2.ico" />
<None Include="Resources\GZDB2.ico" />
<None Include="Resources\UDB.ico" />
@ -1365,6 +1367,7 @@
<None Include="Resources\ScriptError.png" />
<None Include="Resources\ScriptConstant.png" />
<None Include="Resources\Sky.png" />
<None Include="Resources\ClassicRendering.png" />
<None Include="Resources\Update.png" />
<None Include="Resources\Reload.png" />
<None Include="Resources\Preferences.png" />

View file

@ -206,6 +206,7 @@
<Compile Include="Controls\Scripting\ScriptLumpDocumentTab.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Data\ColorMap.cs" />
<Compile Include="Data\DirectoryReader.cs" />
<Compile Include="Data\FileImage.cs" />
<Compile Include="Data\FlatImage.cs" />

View file

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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<PixelColor>();
// 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
}
}

View file

@ -66,7 +66,8 @@ namespace CodeImp.DoomBuilder.Data
// Palette
private Playpal palette;
private ColorMap mainColormap;
// Textures, Flats and Sprites
private Dictionary<long, ImageData> textures;
private Dictionary<long, long> texturenamesshorttofull; //mxd
@ -163,6 +164,7 @@ namespace CodeImp.DoomBuilder.Data
internal IEnumerable<DataReader> Containers { get { return containers; } }
public Playpal Palette { get { return palette; } }
public ColorMap MainColorMap { get { return mainColormap; } }
public ICollection<ImageData> Textures { get { return textures.Values; } }
public ICollection<ImageData> Flats { get { return flats.Values; } }
public List<string> TextureNames { get { return texturenames; } }
@ -428,6 +430,7 @@ namespace CodeImp.DoomBuilder.Data
// Load stuff
LoadX11R6RGB(); //mxd
LoadPalette();
LoadMainColorMap();
Dictionary<string, TexturesParser> cachedparsers = new Dictionary<string, TexturesParser>(); //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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -210,6 +210,16 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ClassicRendering {
get {
object obj = ResourceManager.GetObject("ClassicRendering", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -532,6 +532,9 @@
<data name="Sky" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Sky.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ClassicRendering" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ClassicRendering.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Pin" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Pin.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

View file

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

View file

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

View file

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

View file

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

View file

@ -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<ImageData, List<VisualGeometry>> 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?

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<GLTexture*>(texture);
mTextureUnit[unit].Tex = static_cast<GLTexture*>(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()

View file

@ -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<GLIndexBuffer*> IndexBuffers;
std::vector<GLTexture*> 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<SamplerFilterKey, SamplerFilter> mSamplers;
SamplerFilterKey mSamplerFilterKey;
SamplerFilter* mSamplerFilter = nullptr;
std::map<SamplerFilterKey, SamplerFilter> mSamplers;
SamplerFilterKey GetSamplerFilterKey(TextureFilter filter, MipmapFilter mipFilter, float maxAnisotropy);
int mVertexBuffer = -1;
int64_t mVertexBufferStartIndex = 0;

View file

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

View file

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

View file

@ -24,9 +24,11 @@
#define _CRT_SECURE_NO_WARNINGS
#include <cstdint>
#include <algorithm>
#include <vector>
#include <map>
#include <memory>
#include <string>
#ifdef WIN32
#include <Windows.h>

View file

@ -1614,6 +1614,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This draws a frame
public override void OnRedrawDisplay()
{
renderer.SetClassicLightingColorMap(General.Map.Data.MainColorMap);
// Start drawing
if(renderer.Start())
{