using System;
using System.Collections.Generic;
using System.IO;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace SharpQuake
{
	internal static class vid
	{
		public static ushort[] Table8to16
		{
			get
			{
				return vid._8to16table;
			}
		}

		public static uint[] Table8to24
		{
			get
			{
				return vid._8to24table;
			}
		}

		public static byte[] Table15to8
		{
			get
			{
				return vid._15to8table;
			}
		}

		public static bool glMTexable
		{
			get
			{
				return vid._glMTexable;
			}
		}

		public static bool glZTrick
		{
			get
			{
				return vid._glZTrick.Value != 0f;
			}
		}

		public static bool WindowedMouse
		{
			get
			{
				return vid._WindowedMouse.Value != 0f;
			}
		}

		public static bool Wait
		{
			get
			{
				return vid._Wait.Value != 0f;
			}
		}

		public static mode_t[] Modes
		{
			get
			{
				return vid._Modes;
			}
		}

		public static int ModeNum
		{
			get
			{
				return vid._ModeNum;
			}
		}

		public static void Init(byte[] palette)
		{
			if (vid._glZTrick == null)
			{
				vid._glZTrick = new cvar("gl_ztrick", "1");
				vid._Mode = new cvar("vid_mode", "0", false);
				vid._DefaultMode = new cvar("_vid_default_mode", "0", true);
				vid._DefaultModeWin = new cvar("_vid_default_mode_win", "3", true);
				vid._Wait = new cvar("vid_wait", "0");
				vid._NoPageFlip = new cvar("vid_nopageflip", "0", true);
				vid._WaitOverride = new cvar("_vid_wait_override", "0", true);
				vid._ConfigX = new cvar("vid_config_x", "800", true);
				vid._ConfigY = new cvar("vid_config_y", "600", true);
				vid._StretchBy2 = new cvar("vid_stretch_by_2", "1", true);
				vid._WindowedMouse = new cvar("_windowed_mouse", "1", true);
			}
			cmd.Add("vid_nummodes", new xcommand_t(vid.NumModes_f));
			cmd.Add("vid_describecurrentmode", new xcommand_t(vid.DescribeCurrentMode_f));
			cmd.Add("vid_describemode", new xcommand_t(vid.DescribeMode_f));
			cmd.Add("vid_describemodes", new xcommand_t(vid.DescribeModes_f));
			DisplayDevice displayDevice = mainwindow.DisplayDevice;
			List<mode_t> list = new List<mode_t>(displayDevice.AvailableResolutions.Count);
			using (IEnumerator<DisplayResolution> enumerator = displayDevice.AvailableResolutions.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					DisplayResolution res = enumerator.Current;
					if (res.BitsPerPixel > 8)
					{
						Predicate<mode_t> match = (mode_t m) => m.width == res.Width && m.height == res.Height && m.bpp == res.BitsPerPixel;
						if (!list.Exists(match))
						{
							list.Add(new mode_t
							{
								width = res.Width,
								height = res.Height,
								bpp = res.BitsPerPixel,
								refreshRate = res.RefreshRate
							});
						}
					}
				}
			}
			vid._Modes = list.ToArray();
			mode_t mode_t = new mode_t();
			mode_t.width = displayDevice.Width;
			mode_t.height = displayDevice.Height;
			mode_t.bpp = displayDevice.BitsPerPixel;
			mode_t.refreshRate = displayDevice.RefreshRate;
			mode_t.fullScreen = true;
			int num = displayDevice.Width;
			int height = displayDevice.Height;
			int i = common.CheckParm("-width");
			if (i > 0 && i < common.Argc - 1)
			{
				num = common.atoi(common.Argv(i + 1));
				foreach (DisplayResolution displayResolution in displayDevice.AvailableResolutions)
				{
					if (displayResolution.Width == num)
					{
						height = displayResolution.Height;
						break;
					}
				}
			}
			i = common.CheckParm("-height");
			if (i > 0 && i < common.Argc - 1)
			{
				height = common.atoi(common.Argv(i + 1));
			}
			mode_t.width = num;
			mode_t.height = height;
			if (common.HasParam("-window"))
			{
				vid._Windowed = true;
			}
			else
			{
				vid._Windowed = false;
				if (common.HasParam("-current"))
				{
					mode_t.width = displayDevice.Width;
					mode_t.height = displayDevice.Height;
				}
				else
				{
					int bpp = mode_t.bpp;
					i = common.CheckParm("-bpp");
					if (i > 0 && i < common.Argc - 1)
					{
						bpp = common.atoi(common.Argv(i + 1));
					}
					mode_t.bpp = bpp;
				}
			}
			int num2 = common.CheckParm("-conwidth");
			if (num2 > 0)
			{
				Scr.vid.conwidth = common.atoi(common.Argv(num2 + 1));
			}
			else
			{
				Scr.vid.conwidth = 640;
			}
			Scr.vid.conwidth &= 65528;
			if (Scr.vid.conwidth < 320)
			{
				Scr.vid.conwidth = 320;
			}
			Scr.vid.conheight = Scr.vid.conwidth * 3 / 4;
			num2 = common.CheckParm("-conheight");
			if (num2 > 0)
			{
				Scr.vid.conheight = common.atoi(common.Argv(num2 + 1));
			}
			if (Scr.vid.conheight < 200)
			{
				Scr.vid.conheight = 200;
			}
			Scr.vid.maxwarpwidth = 320;
			Scr.vid.maxwarpheight = 200;
			Scr.vid.colormap = host.ColorMap;
			int l = BitConverter.ToInt32(host.ColorMap, 2048);
			Scr.vid.fullbright = 256 - common.LittleLong(l);
			vid.CheckGamma(palette);
			vid.SetPalette(palette);
			mode_t.fullScreen = !vid._Windowed;
			vid._DefModeNum = -1;
			for (i = 0; i < vid._Modes.Length; i++)
			{
				mode_t mode_t2 = vid._Modes[i];
				if (mode_t2.width == mode_t.width && mode_t2.height == mode_t.height)
				{
					vid._DefModeNum = i;
					if (mode_t2.bpp == mode_t.bpp && mode_t2.refreshRate == mode_t.refreshRate)
					{
						break;
					}
				}
			}
			if (vid._DefModeNum == -1)
			{
				vid._DefModeNum = 0;
			}
			vid.SetMode(vid._DefModeNum, palette);
			vid.InitOpenGL();
			Directory.CreateDirectory(Path.Combine(common.GameDir, "glquake"));
		}

		public static void Shutdown()
		{
		}

		public static void SetMode(int modenum, byte[] palette)
		{
			if (modenum < 0 || modenum >= vid._Modes.Length)
			{
				sys.Error("Bad video mode\n", Array.Empty<object>());
			}
			mode_t mode_t = vid._Modes[modenum];
			bool isDisabledForLoading = Scr.IsDisabledForLoading;
			Scr.IsDisabledForLoading = true;
			cd_audio.Pause();
			DisplayDevice displayDevice = mainwindow.DisplayDevice;
			mainwindow instance = mainwindow.Instance;
			if (vid._Windowed)
			{
				try
				{
					displayDevice.ChangeResolution(mode_t.width, mode_t.height, mode_t.bpp, mode_t.refreshRate);
				}
				catch (Exception ex)
				{
					sys.Error("Couldn't set video mode: " + ex.Message, Array.Empty<object>());
				}
				instance.WindowState = WindowState.Normal;
				instance.WindowBorder = WindowBorder.Fixed;
			}
			else
			{
				try
				{
					displayDevice.ChangeResolution(mode_t.width, mode_t.height, mode_t.bpp, mode_t.refreshRate);
				}
				catch (Exception ex2)
				{
					sys.Error("Couldn't set video mode: " + ex2.Message, Array.Empty<object>());
				}
				instance.WindowState = WindowState.Fullscreen;
				instance.WindowBorder = WindowBorder.Hidden;
			}
			viddef_t vid = Scr.vid;
			if (vid.conheight > displayDevice.Height)
			{
				vid.conheight = displayDevice.Height;
			}
			if (vid.conwidth > displayDevice.Width)
			{
				vid.conwidth = displayDevice.Width;
			}
			vid.width = vid.conwidth;
			vid.height = vid.conheight;
			vid.numpages = 2;
			cd_audio.Resume();
			Scr.IsDisabledForLoading = isDisabledForLoading;
			vid._ModeNum = modenum;
			cvar.Set("vid_mode", (float)vid._ModeNum);
			vid.ClearAllStates();
			Con.SafePrint("Video mode {0} initialized.\n", new object[]
			{
				vid.GetModeDescription(vid._ModeNum)
			});
			vid.SetPalette(palette);
			vid.recalc_refdef = true;
		}

		public static string GetModeDescription(int mode)
		{
			if (mode < 0 || mode >= vid._Modes.Length)
			{
				return string.Empty;
			}
			mode_t mode_t = vid._Modes[mode];
			return string.Format("{0}x{1}x{2} {3}", new object[]
			{
				mode_t.width,
				mode_t.height,
				mode_t.bpp,
				vid._Windowed ? "windowed" : "fullscreen"
			});
		}

		public static void SetPalette(byte[] palette)
		{
			int num = 0;
			uint[] 8to24table = vid._8to24table;
			for (int i = 0; i < 8to24table.Length; i++)
			{
				uint num2 = (uint)palette[num];
				uint num3 = (uint)palette[num + 1];
				uint num4 = (uint)palette[num + 2];
				8to24table[i] = 4278190080u + num2 + (num3 << 8) + (num4 << 16);
				num += 3;
			}
			8to24table[255] &= 16777215u;
			Union4b empty = Union4b.Empty;
			for (uint num5 = 0u; num5 < 32768u; num5 += 1u)
			{
				uint num6 = ((num5 & 31u) << 3) + 4u;
				uint num7 = ((num5 & 992u) >> 2) + 4u;
				uint num8 = ((num5 & 31744u) >> 7) + 4u;
				uint num9 = 0u;
				uint num10 = 100000000u;
				for (uint num11 = 0u; num11 < 256u; num11 += 1u)
				{
					empty.ui0 = vid._8to24table[(int)num11];
					uint num12 = num6 - (uint)empty.b0;
					uint num13 = num7 - (uint)empty.b1;
					uint num14 = num8 - (uint)empty.b2;
					uint num15 = num12 * num12 + num13 * num13 + num14 * num14;
					if (num15 < num10)
					{
						num9 = num11;
						num10 = num15;
					}
				}
				vid._15to8table[(int)num5] = (byte)num9;
			}
		}

		private static void InitOpenGL()
		{
			vid._glVendor = GL.GetString(StringName.Vendor);
			Con.Print("GL_VENDOR: {0}\n", new object[]
			{
				vid._glVendor
			});
			vid._glRenderer = GL.GetString(StringName.Renderer);
			Con.Print("GL_RENDERER: {0}\n", new object[]
			{
				vid._glRenderer
			});
			vid._glVersion = GL.GetString(StringName.Version);
			Con.Print("GL_VERSION: {0}\n", new object[]
			{
				vid._glVersion
			});
			vid._glExtensions = GL.GetString(StringName.Extensions);
			Con.Print("GL_EXTENSIONS: {0}\n", new object[]
			{
				vid._glExtensions
			});
			if (vid._glRenderer.StartsWith("PowerVR", StringComparison.InvariantCultureIgnoreCase))
			{
				Scr.FullSbarDraw = true;
			}
			if (vid._glRenderer.StartsWith("Permedia", StringComparison.InvariantCultureIgnoreCase))
			{
				Scr.IsPermedia = true;
			}
			vid.CheckTextureExtensions();
			vid.CheckMultiTextureExtensions();
			GL.ClearColor(1f, 0f, 0f, 0f);
			GL.CullFace(CullFaceMode.Front);
			GL.Enable(EnableCap.Texture2D);
			GL.Enable(EnableCap.AlphaTest);
			GL.AlphaFunc(AlphaFunction.Greater, 0.666f);
			GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
			GL.ShadeModel(ShadingModel.Flat);
			Drawer.SetTextureFilters(TextureMinFilter.Nearest, TextureMagFilter.Nearest);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, 10497);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, 10497);
			GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
			GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, 7681);
		}

		private static void NumModes_f()
		{
			int num = vid._Modes.Length;
			if (num == 1)
			{
				Con.Print("{0} video mode is available\n", new object[]
				{
					num
				});
				return;
			}
			Con.Print("{0} video modes are available\n", new object[]
			{
				num
			});
		}

		private static void DescribeCurrentMode_f()
		{
			Con.Print("{0}\n", new object[]
			{
				vid.GetExtModeDescription(vid._ModeNum)
			});
		}

		private static void DescribeMode_f()
		{
			int mode = common.atoi(cmd.Argv(1));
			Con.Print("{0}\n", new object[]
			{
				vid.GetExtModeDescription(mode)
			});
		}

		private static void DescribeModes_f()
		{
			for (int i = 0; i < vid._Modes.Length; i++)
			{
				Con.Print("{0}:{1}\n", new object[]
				{
					i,
					vid.GetExtModeDescription(i)
				});
			}
		}

		private static string GetExtModeDescription(int mode)
		{
			return vid.GetModeDescription(mode);
		}

		private static void CheckGamma(byte[] pal)
		{
			int i = common.CheckParm("-gamma");
			if (i == 0)
			{
				string @string = GL.GetString(StringName.Renderer);
				string string2 = GL.GetString(StringName.Vendor);
				if (@string.Contains("Voodoo") || string2.Contains("3Dfx"))
				{
					vid._Gamma = 1f;
				}
				else
				{
					vid._Gamma = 0.7f;
				}
			}
			else
			{
				vid._Gamma = float.Parse(common.Argv(i + 1));
			}
			for (i = 0; i < pal.Length; i++)
			{
				double num = Math.Pow((double)(pal[i] + 1) / 256.0, (double)vid._Gamma) * 255.0 + 0.5;
				if (num < 0.0)
				{
					num = 0.0;
				}
				if (num > 255.0)
				{
					num = 255.0;
				}
				pal[i] = (byte)num;
			}
		}

		private static void ClearAllStates()
		{
			for (int i = 0; i < 256; i++)
			{
				Key.Event(i, false);
			}
			Key.ClearStates();
			input.ClearStates();
		}

		private static void CheckTextureExtensions()
		{
			vid._glExtensions.Contains("GL_EXT_texture_object");
		}

		private static void CheckMultiTextureExtensions()
		{
			if (vid._glExtensions.Contains("GL_SGIS_multitexture ") && !common.HasParam("-nomtex"))
			{
				Con.Print("Multitexture extensions found.\n", Array.Empty<object>());
				vid._glMTexable = true;
			}
		}

		public const int VID_CBITS = 6;

		public const int VID_GRADES = 64;

		public const int VID_ROW_SIZE = 3;

		private const int WARP_WIDTH = 320;

		private const int WARP_HEIGHT = 200;

		private static ushort[] _8to16table = new ushort[256];

		private static uint[] _8to24table = new uint[256];

		private static byte[] _15to8table = new byte[65536];

		private static mode_t[] _Modes;

		private static int _ModeNum;

		private static cvar _glZTrick;

		private static cvar _Mode;

		private static cvar _DefaultMode;

		private static cvar _DefaultModeWin;

		private static cvar _Wait;

		private static cvar _NoPageFlip;

		private static cvar _WaitOverride;

		private static cvar _ConfigX;

		private static cvar _ConfigY;

		private static cvar _StretchBy2;

		private static cvar _WindowedMouse;

		private static bool _Windowed;

		private static float _Gamma = 1f;

		private static int _DefModeNum;

		private static bool _glMTexable = false;

		private static string _glVendor;

		private static string _glRenderer;

		private static string _glVersion;

		private static string _glExtensions;
	}
}
