Inheritance: IDisposable
		public static void GenerateWhiteImage(idImage image)
		{
			// solid white texture
			byte[] data = new byte[DefaultImageSize * DefaultImageSize * 4];
			int count = data.Length;

			for(int i = 0; i < count; i++)
			{
				data[i] = 255;
			}

			image.Generate(data, DefaultImageSize, DefaultImageSize, TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.Default);
		}
		public static void GenerateDefaultImage(idImage image)
		{
			image.MakeDefault();
		}
		public static void GenerateFlatNormalImage(idImage image)
		{
			byte[, ,] data = new byte[DefaultImageSize, DefaultImageSize, 4];

			int red = (idE.CvarSystem.GetInteger("image_useNormalCompression") == 1) ? 0 : 3;
			int alpha = (red == 0) ? 3 : 0;

			// flat normal map for default bunp mapping
			for(int i = 0; i < 4; i++)
			{
				data[0, i, red] = 128;
				data[0, i, 1] = 128;
				data[0, i, 2] = 255;
				data[0, i, alpha] = 255;
			}

			image.Generate(idHelper.Flatten<byte>(data), 2, 2, TextureFilter.Default, true, TextureRepeat.Repeat, TextureDepth.HighQuality);
		}
Exemple #4
0
		private void Clear()
		{
			_description = "<none>";
			_renderBump = string.Empty;

			_contentFlags = ContentFlags.Solid;
			_surfaceFlags = SurfaceFlags.None;
			_materialFlags = 0;

			_sort = (float) MaterialSort.Bad;
			_coverage = MaterialCoverage.Bad;
			_cullType = CullType.Front;

			_deformType = DeformType.None;
			_deformRegisters = new int[4];

			_ops = null;
			_expressionRegisters = null;
			_constantRegisters = null;
			_stages = new MaterialStage[] { };

			_stageCount = 0;
			_ambientStageCount = 0;
			_registerCount = 0;
			
			_lightFalloffImage = null;
			_entityGui = 0;
			_shouldCreateBackSides = false;
			_editorImageName = null;

			_fogLight = false;
			_blendLight = false;
			_ambientLight = false;
			_noFog = false;
			_hasSubview = false;
			_allowOverlays = true;
			_unsmoothedTangents = false;

			_userInterface = null;
			_referenceCount = 0;
			
			/*editorAlpha = 1.0;*/
			_spectrum = 0;

			_polygonOffset = 0;
			_suppressInSubview = false;
			_portalSky = false;

			_decalInfo.StayTime = 10000;
			_decalInfo.FadeTime = 4000;
			_decalInfo.Start = new float[] { 1, 1, 1, 1 };
			_decalInfo.End = new float[] { 0, 0, 0, 0 };
		}
		public static void GenerateBorderClampImage(idImage image)
		{
			// the size determines how far away from the edge the blocks start fading
			int borderClampSize = 32;

			byte[, ,] data = new byte[borderClampSize, borderClampSize, 4];

			// solid white texture with a single pixel black border
			for(int y = 0; y < borderClampSize; y++)
			{
				for(int x = 0; x < borderClampSize; x++)
				{
					data[y, x, 0] = 255;
					data[y, x, 1] = 255;
					data[y, x, 2] = 255;
					data[y, x, 3] = 255;
				}
			}

			for(int i = 0; i < borderClampSize; i++)
			{
				data[i, 0, 0] =
					data[i, 0, 1] =
					data[i, 0, 2] =
					data[i, 0, 3] =

				data[i, borderClampSize - 1, 0] =
					data[i, borderClampSize - 1, 1] =
					data[i, borderClampSize - 1, 2] =
					data[i, borderClampSize - 1, 3] =

				data[0, i, 0] =
					data[0, i, 1] =
					data[0, i, 2] =
					data[0, i, 3] =

				data[borderClampSize - 1, i, 0] =
					data[borderClampSize - 1, i, 1] =
					data[borderClampSize - 1, i, 2] =
					data[borderClampSize - 1, i, 3] = 0;
			}

			image.Generate(idHelper.Flatten<byte>(data), borderClampSize, borderClampSize, TextureFilter.Linear, false, TextureRepeat.ClampToBorder, TextureDepth.Default);

			if(idE.RenderSystem.IsRunning == false)
			{
				// can't call qglTexParameterfv yet
				return;
			}

			// explicit zero border
			float[] color = new float[4];


			//Gl.glTexParameterfv(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BORDER_COLOR, color);
		}
		/// <summary>
		/// Creates a ramp that matches our fudged specular calculation.
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateSpecularTableImage(idImage image)
		{
			byte[,] data = new byte[256, 4];

			for(int x = 0; x < 256; x++)
			{
				float f = x / 255.0f;

				// this is the behavior of the hacked up fragment programs that can't really do a power function
				f = (f - 0.75f) * 4;

				if(f < 0)
				{
					f = 0;
				}

				f = f * f;

				int b = (int) (f * 255);

				data[x, 0] =
					data[x, 1] =
					data[x, 2] =
					data[x, 3] = (byte) b;
			}

			image.Generate(idHelper.Flatten<byte>(data), 256, 1, TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		/// <summary>
		/// Creates a 0-255 ramp image.
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateAlphaRampImage(idImage image)
		{
			byte[,] data = new byte[256, 4];

			for(int x = 0; x < 256; x++)
			{
				data[x, 0] =
					data[x, 1] =
					data[x, 2] = 255;
				data[x, 3] = (byte) x;
			}

			image.Generate(idHelper.Flatten<byte>(data), 256, 1, TextureFilter.Nearest, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		private idImage CreateImage(string name, TextureType type, TextureFilter filter, TextureRepeat repeat, TextureDepth depth, CubeFiles cubeMap, bool allowDownSize)
		{
			idImage image = new idImage(name, type, filter, repeat, depth, cubeMap, allowDownSize);

			_images.Add(image);
			_imageDictionary.Add(name, image);

			return image;
		}
		public void Init()
		{
			// set default texture filter modes
			ChangeTextureFilter();

			// create built in images
			_defaultImage = ImageFromFile("_default", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.Default);
			_whiteImage = ImageFromFile("_white", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.Default);
			_blackImage = ImageFromFile("_black", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.Default);
			_borderClampImage = ImageFromFile("_borderClamp", TextureFilter.Linear, false, TextureRepeat.ClampToBorder, TextureDepth.Default);
			_flatNormalMap = ImageFromFile("_flat", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.HighQuality);
			// TODO: _ambientNormalMap = LoadFromCallback("_ambient", GenerateAmbientNormalImage);
			/*_specularTableImage = LoadFromCallback("_specularTable", GenerateSpecularTableImage);
			_specular2DTableImage = LoadFromCallback("_specular2DTable", GenerateSpecular2DTableImage);
			_rampImage = LoadFromCallback("_ramp", GenerateRampImage);
			_alphaRampImage = LoadFromCallback("_alphaRamp", GenerateRampImage);
			_alphaNotchImage = LoadFromCallback("_alphaNotch", GenerateAlphaNotchImage);*/
			_fogImage = ImageFromFile("_fog", TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
			_fogEnterImage = ImageFromFile("_fogEnter", TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
			// TODO: _normalCubeMapImage = LoadFromCallback("_normalCubeMap", makeNormalizeVectorCubeMap);*/
			_noFalloffImage = ImageFromFile("_noFalloff", TextureFilter.Default, false, TextureRepeat.ClampToZero, TextureDepth.HighQuality);

			ImageFromFile("_quadratic", TextureFilter.Default, false, TextureRepeat.Clamp, TextureDepth.HighQuality);

			// cinematicImage is used for cinematic drawing
			// scratchImage is used for screen wipes/doublevision etc..
			/*_cinematicImage = LoadFromCallback("_cinematic", GenerateRGBA8Image);*/
			_scratchImage = ImageFromFile("_scratch", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.HighQuality);
			_scratchImage2 = ImageFromFile("_scratch2", TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.HighQuality);
			/*_accumImage = LoadFromCallback("_accum", GenerateRGBA8Image);*/
			// TODO: _scratchCubeMapImage = LoadFromCallback("_scratchCubeMap", makeNormalizeVectorCubeMap);*/
			//_currentRenderImage = LoadFromCallback("_currentRender", GenerateRGBA8Image);

			// TODO: cmds
			idE.CmdSystem.AddCommand("reloadImages", "reloads images", CommandFlags.Renderer, new EventHandler<CommandEventArgs>(Cmd_ReloadImages));
			/*cmdSystem->AddCommand("listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images");
			cmdSystem->AddCommand("combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression");*/

			// should forceLoadImages be here?
		}
		/// <summary>
		/// This is a solid white texture that is zero clamped.
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateNoFalloffImage(idImage image)
		{
			byte[, ,] data = new byte[16, FalloffTextureSize, 4];

			for(int x = 1; x < (FalloffTextureSize - 1); x++)
			{
				for(int y = 1; y < 15; y++)
				{
					data[y, x, 0] = 255;
					data[y, x, 1] = 255;
					data[y, x, 2] = 255;
					data[y, x, 3] = 255;
				}
			}

			image.Generate(idHelper.Flatten<byte>(data), FalloffTextureSize, 16, TextureFilter.Default, false, TextureRepeat.ClampToZero, TextureDepth.HighQuality);
		}
		private idImage CreateImage(string name, ImageLoadCallback generator)
		{
			idImage image = new idImage(name, generator);

			_images.Add(image);
			_imageDictionary.Add(name, image);

			return image;
		}
		public static void GenerateQuadraticImage(idImage image)
		{
			byte[, ,] data = new byte[QuadraticHeight, QuadraticWidth, 4];

			for(int x = 0; x < QuadraticWidth; x++)
			{
				for(int y = 0; y < QuadraticHeight; y++)
				{
					float d = x - ((QuadraticWidth / 2) - 0.5f);
					d = idMath.Abs(d);
					d -= 0.5f;
					d /= QuadraticWidth / 2;

					d = 1.0f - d;
					d = d * d;

					int b = (byte) (d * 255);

					if(b <= 0)
					{
						b = 0;
					}
					else if(b > 255)
					{
						b = 255;
					}

					data[y, x, 0] =
						data[y, x, 1] =
						data[y, x, 2] = (byte) b;
					data[y, x, 3] = 255;
				}
			}

			image.Generate(idHelper.Flatten<byte>(data), QuadraticWidth, QuadraticHeight, TextureFilter.Default, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		/// <summary>
		/// We calculate distance correctly in two planes, but the third will still be projection based.
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateFogImage(idImage image)
		{
			byte[, ,] data = new byte[FogSize, FogSize, 4];
			float[] step = new float[256];
			float remaining = 1.0f;

			for(int i = 0; i < 256; i++)
			{
				step[i] = remaining;
				remaining *= 0.982f;
			}

			for(int x = 0; x < FogSize; x++)
			{
				for(int y = 0; y < FogSize; y++)
				{
					float d = (float) idMath.Sqrt((x - (FogSize / 2)) * (x - (FogSize / 2))
						+ (y - (FogSize / 2)) * (y - (FogSize / 2)));
					d /= FogSize / 2 - 1;

					int b = (byte) (d * 255);

					if(b <= 0)
					{
						b = 0;
					}
					else if(b > 255)
					{
						b = 255;
					}

					b = (byte) (255 * (1.0f - step[b]));

					if((x == 0) || (x == (FogSize - 1)) || (y == 0) || (y == (FogSize - 1)))
					{
						b = 255; // avoid clamping issues
					}

					data[y, x, 0] =
						data[y, x, 1] =
						data[y, x, 2] = 255;
					data[y, x, 3] = (byte) b;
				}
			}

			image.Generate(idHelper.Flatten<byte>(data), FogSize, FogSize, TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
Exemple #14
0
		/// <summary>
		/// Parses the material, if there are any errors during parsing the defaultShader will be set.
		/// </summary>
		/// <param name="lexer"></param>
		private void ParseMaterial(idLexer lexer)
		{
			_registerCount = PredefinedRegisterCount; // leave space for the parms to be copied in.

			for(int i = 0; i < _registerCount; i++)
			{
				_parsingData.RegisterIsTemporary[i] = true; // they aren't constants that can be folded.
			}

			TextureRepeat textureRepeatDefault = TextureRepeat.Repeat; // allow a global setting for repeat.
			idToken token = null;

			string tokenValue;
			string tokenLower;
			int count;

			while(true)
			{
				if(TestMaterialFlag(Renderer.MaterialFlags.Defaulted) == true)
				{
					// we have a parse error.
					return;
				}

				if((token = lexer.ExpectAnyToken()) == null)
				{
					this.MaterialFlag = MaterialFlags.Defaulted;
					return;
				}

				tokenValue = token.ToString();
				tokenLower = tokenValue.ToLower();

				// end of material definition
				if(tokenLower == "}")
				{
					break;
				}
				else if(tokenLower == "qer_editorimage")
				{
					token = lexer.ReadTokenOnLine();
					_editorImageName = (token != null) ? token.ToString() : string.Empty;

					lexer.SkipRestOfLine();
				}
				else if(tokenLower == "description")
				{
					token = lexer.ReadTokenOnLine();
					_description = (token != null) ? token.ToString() : string.Empty;
				}
				// check for the surface / content bit flags.
				else if(CheckSurfaceParameter(token) == true)
				{

				}
				else if(tokenLower == "polygonoffset")
				{
					this.MaterialFlag = Renderer.MaterialFlags.PolygonOffset;

					if((token = lexer.ReadTokenOnLine()) == null)
					{
						_polygonOffset = 1;
					}
					else
					{
						_polygonOffset = token.ToFloat();
					}
				}
				// noshadow.
				else if(tokenLower == "noshadows")
				{
					this.MaterialFlag = MaterialFlags.NoShadows;
				}
				else if(tokenLower == "suppressinsubview")
				{
					_suppressInSubview = true;
				}
				else if(tokenLower == "portalsky")
				{
					_portalSky = true;
				}
				else if(tokenLower == "noselfshadow")
				{
					this.MaterialFlag = Renderer.MaterialFlags.NoSelfShadow;
				}
				else if(tokenLower == "noportalfog")
				{
					this.MaterialFlag = Renderer.MaterialFlags.NoPortalFog;
				}
				// forceShadows allows nodraw surfaces to cast shadows.
				else if(tokenLower == "forceshadows")
				{
					this.MaterialFlag = Renderer.MaterialFlags.ForceShadows;
				}
				// overlay / decal suppression.
				else if(tokenLower == "nooverlays")
				{
					_allowOverlays = false;
				}
				// moster blood overlay forcing for alpha tested or translucent surfaces.
				else if(tokenLower == "forceoverlays")
				{
					_parsingData.ForceOverlays = true;
				}
				else if(tokenLower == "translucent")
				{
					_coverage = MaterialCoverage.Translucent;
				}
				// global zero clamp.
				else if(tokenLower == "zeroclamp")
				{
					textureRepeatDefault = TextureRepeat.ClampToZero;
				}
				// global clamp.
				else if(tokenLower == "clamp")
				{
					textureRepeatDefault = TextureRepeat.Clamp;
				}
				// global clamp.
				else if(tokenLower == "alphazeroclamp")
				{
					textureRepeatDefault = TextureRepeat.ClampToZero;
				}
				// forceOpaque is used for skies-behind-windows.
				else if(tokenLower == "forceopaque")
				{
					_coverage = MaterialCoverage.Opaque;
				}
				else if(tokenLower == "twosided")
				{
					_cullType = CullType.TwoSided;

					// twoSided implies no-shadows, because the shadow
					// volume would be coplanar with the surface, giving depth fighting
					// we could make this no-self-shadows, but it may be more important
					// to receive shadows from no-self-shadow monsters.
					this.MaterialFlag = Renderer.MaterialFlags.NoShadows;
				}
				else if(tokenLower == "backsided")
				{
					_cullType = CullType.Back;

					// the shadow code doesn't handle this, so just disable shadows.
					// We could fix this in the future if there was a need.
					this.MaterialFlag = Renderer.MaterialFlags.NoShadows;
				}
				else if(tokenLower == "foglight")
				{
					_fogLight = true;
				}
				else if(tokenLower == "blendlight")
				{
					_blendLight = true;
				}
				else if(tokenLower == "ambientlight")
				{
					_ambientLight = true;
				}
				else if(tokenLower == "mirror")
				{
					_sort = (float) MaterialSort.Subview;
					_coverage = MaterialCoverage.Opaque;
				}
				else if(tokenLower == "nofog")
				{
					_noFog = true;
				}
				else if(tokenLower == "unsmoothedtangents")
				{
					_unsmoothedTangents = true;
				}
				// lightFallofImage <imageprogram>
				// specifies the image to use for the third axis of projected
				// light volumes.
				else if(tokenLower == "lightfalloffimage")
				{
					_lightFalloffImage = idE.ImageManager.ImageFromFile(ParsePastImageProgram(lexer), TextureFilter.Default, false, TextureRepeat.Clamp, TextureDepth.Default);
				}
				// guisurf <guifile> | guisurf entity
				// an entity guisurf must have an idUserInterface
				// specified in the renderEntity.
				else if(tokenLower == "guisurf")
				{
					token = lexer.ReadTokenOnLine();
					tokenLower = token.ToString().ToLower();

					if(tokenLower == "entity")
					{
						_entityGui = 1;
					}
					else if(tokenLower == "entity2")
					{
						_entityGui = 2;
					}
					else if(tokenLower == "entity3")
					{
						_entityGui = 3;
					}
					else
					{
						_userInterface = idE.UIManager.FindInterface(token.ToString(), true);
					}
				}
				// sort.
				else if(tokenLower == "sort")
				{
					ParseSort(lexer);
				}
				// spectrum <integer>.
				else if(tokenLower == "spectrum")
				{
					int.TryParse(lexer.ReadTokenOnLine().ToString(), out _spectrum);
				}
				// deform < sprite | tube | flare >.
				else if(tokenLower == "deform")
				{
					ParseDeform(lexer);
				}
				// decalInfo <staySeconds> <fadeSeconds> (<start rgb>) (<end rgb>).
				else if(tokenLower == "decalinfo")
				{
					ParseDecalInfo(lexer);
				}
				// renderbump <args...>.
				else if(tokenLower == "renderbump")
				{
					_renderBump = lexer.ParseRestOfLine();
				}
				// diffusemap for stage shortcut.
				else if(tokenLower == "diffusemap")
				{
					idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames);
					newLexer.LoadMemory(string.Format("blend diffusemap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "diffusemap");

					ParseStage(newLexer, textureRepeatDefault);
				}
				// specularmap for stage shortcut.
				else if(tokenLower == "specularmap")
				{
					idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames);
					newLexer.LoadMemory(string.Format("blend specularmap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "specularmap");

					ParseStage(newLexer, textureRepeatDefault);
				}
				// normalmap for stage shortcut.
				else if(tokenLower == "bumpmap")
				{
					idLexer newLexer = new idLexer(LexerOptions.NoFatalErrors | LexerOptions.NoStringConcatination | LexerOptions.NoStringEscapeCharacters | LexerOptions.AllowPathNames);
					newLexer.LoadMemory(string.Format("blend bumpmap\nmap {0}\n}}\n", ParsePastImageProgram(lexer)), "bumpmap");

					ParseStage(newLexer, textureRepeatDefault);
				}
				// DECAL_MACRO for backwards compatibility with the preprocessor macros.
				else if(tokenLower == "decal_macro")
				{
					// polygonOffset
					this.MaterialFlag = Renderer.MaterialFlags.PolygonOffset;
					_polygonOffset = -1;

					// discrete
					_surfaceFlags |= SurfaceFlags.Discrete;
					_contentFlags &= ~ContentFlags.Solid;

					// sort decal.
					_sort = (float) MaterialSort.Decal;

					// noShadows
					this.MaterialFlag = Renderer.MaterialFlags.NoShadows;
				}
				else if(tokenValue == "{")
				{
					// create the new stage.
					ParseStage(lexer, textureRepeatDefault);
				}
				else
				{
					idConsole.WriteLine("unknown general material parameter '{0}' in '{1}'", tokenValue, this.Name);
					return;
				}
			}

			// add _flat or _white stages if needed.
			AddImplicitStages();

			// order the diffuse / bump / specular stages properly.
			SortInteractionStages();

			// if we need to do anything with normals (lighting or environment mapping)
			// and two sided lighting was asked for, flag
			// shouldCreateBackSides() and change culling back to single sided,
			// so we get proper tangent vectors on both sides.

			// we can't just call ReceivesLighting(), because the stages are still
			// in temporary form.
			if(_cullType == CullType.TwoSided)
			{
				count = _parsingData.Stages.Count;

				for(int i = 0; i < count; i++)
				{
					if((_parsingData.Stages[i].Lighting != StageLighting.Ambient) || (_parsingData.Stages[i].Texture.TextureCoordinates != TextureCoordinateGeneration.Explicit))
					{
						if(_cullType == CullType.TwoSided)
						{
							_cullType = CullType.Front;
							_shouldCreateBackSides = true;
						}

						break;
					}
				}
			}

			// currently a surface can only have one unique texgen for all the stages on old hardware.
			TextureCoordinateGeneration firstGen = TextureCoordinateGeneration.Explicit;

			count = _parsingData.Stages.Count;

			for(int i = 0; i < count; i++)
			{
				if(_parsingData.Stages[i].Texture.TextureCoordinates != TextureCoordinateGeneration.Explicit)
				{
					if(firstGen == TextureCoordinateGeneration.Explicit)
					{
						firstGen = _parsingData.Stages[i].Texture.TextureCoordinates;
					}
					else if(firstGen != _parsingData.Stages[i].Texture.TextureCoordinates)
					{
						idConsole.Warning("material '{0}' has multiple stages with a texgen", this.Name);
						break;
					}
				}
			}
		}
		public static void GenerateRGB8Image(idImage image)
		{
			byte[, ,] data = new byte[DefaultImageSize, DefaultImageSize, 4];

			data[0, 0, 0] = 16;
			data[0, 0, 1] = 32;
			data[0, 0, 2] = 48;
			data[0, 0, 3] = 255;

			image.Generate(idHelper.Flatten<byte>(data), DefaultImageSize, DefaultImageSize, TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.HighQuality);
		}
		public void QueueBackgroundLoad(idImage image)
		{
			string fileName = idE.ImageManager.ImageProgramStringToCompressedFileName(image.Name);

			BackgroundDownload backgroundDownload = new BackgroundDownload();
			backgroundDownload.Stream = idE.FileSystem.OpenFileRead(fileName);

			if(backgroundDownload.Stream == null)
			{
				idConsole.Warning("idImageManager.StartBackgroundLoad: Couldn't load {0}", image.Name);
			}
			else
			{
				idE.FileSystem.QueueBackgroundLoad(backgroundDownload);

				_backgroundImageLoads.Add(image, backgroundDownload);

				// TODO: purge image cache
				/*// purge some images if necessary
				int		totalSize = 0;
				for ( idImage *check = globalImages->cacheLRU.cacheUsageNext ; check != &globalImages->cacheLRU ; check = check->cacheUsageNext ) {
					totalSize += check->StorageSize();
				}
				int	needed = this->StorageSize();

				while ( ( totalSize + needed ) > globalImages->image_cacheMegs.GetFloat() * 1024 * 1024 ) {
					// purge the least recently used
					idImage	*check = globalImages->cacheLRU.cacheUsagePrev;
					if ( check->texnum != TEXTURE_NOT_LOADED ) {
						totalSize -= check->StorageSize();
						if ( globalImages->image_showBackgroundLoads.GetBool() ) {
							common->Printf( "purging %s\n", check->imgName.c_str() );
						}
						check->PurgeImage();
					}
					// remove it from the cached list
					check->cacheUsageNext->cacheUsagePrev = check->cacheUsagePrev;
					check->cacheUsagePrev->cacheUsageNext = check->cacheUsageNext;
					check->cacheUsageNext = NULL;
					check->cacheUsagePrev = NULL;
				}*/
			}
		}
		public static void GenerateAlphaNotchImage(idImage image)
		{
			byte[,] data = new byte[2, 4];

			// this is used for alpha test clip planes
			data[0, 0] = data[0, 1] = data[0, 2] = 255;
			data[0, 3] = 0;
			data[1, 0] = data[1, 1] = data[1, 2] = 255;
			data[1, 3] = 255;

			image.Generate(idHelper.Flatten<byte>(data), 2, 1, TextureFilter.Nearest, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		public static void GenerateAmbientNormalImage(idImage image)
		{
			byte[, ,] data = new byte[DefaultImageSize, DefaultImageSize, 4];

			int red = (idE.CvarSystem.GetInteger("image_useNormalCompression") == 1) ? 0 : 3;
			int alpha = (red == 0) ? 3 : 0;

			Vector4 ambientLightVector = idE.RenderSystem.AmbientLightVector;

			// flat normal map for default bunp mapping
			for(int i = 0; i < 4; i++)
			{
				data[0, i, red] = (byte) (255 * ambientLightVector.X);
				data[0, i, 1] = (byte) (255 * ambientLightVector.Y);
				data[0, i, 2] = (byte) (255 * ambientLightVector.Z);
				data[0, i, alpha] = 255;
			}

			byte[,] pics = new byte[6, 4];

			for(int i = 0; i < 6; i++)
			{
				pics[i, 0] = data[0, 0, 0];
				pics[i, 1] = data[0, 0, 1];
				pics[i, 2] = data[0, 0, 2];
				pics[i, 3] = data[0, 0, 3];
			}

			// this must be a cube map for fragment programs to simply substitute for the normalization cube map
			idConsole.Warning("TODO: image->GenerateCubeImage( pics, 2, TF_DEFAULT, true, TD_HIGH_QUALITY );");
		}
		/// <summary>
		/// Create a 2D table that calculates (reflection dot , specularity).
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateSpecular2DTableImage(idImage image)
		{
			byte[, ,] data = new byte[256, 256, 4];

			for(int x = 0; x < 256; x++)
			{
				float f = x / 255.0f;

				for(int y = 0; y < 256; y++)
				{
					int b = (int) (idMath.Pow(f, y) * 255.0f);

					if(b == 0)
					{
						// as soon as b equals zero all remaining values in this column are going to be zero
						// we early out to avoid pow() underflows
						break;
					}

					data[y, x, 0] =
					data[y, x, 1] =
					data[y, x, 2] =
					data[y, x, 3] = (byte) b;
				}
			}

			image.Generate(idHelper.Flatten<byte>(data), 256, 256, TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		public static void GenerateBlackImage(idImage image)
		{
			// solid black texture
			byte[] data = new byte[DefaultImageSize * DefaultImageSize * 4];
			//image.Generate(data, DefaultImageSize, DefaultImageSize, TextureFilter.Default, false, TextureRepeat.Repeat, TextureDepth.Default);
		}
		/// <summary>
		/// Modulate the fog alpha density based on the distance of the start and end points to the terminator plane.
		/// </summary>
		/// <param name="image"></param>
		public static void GenerateFogEnterImage(idImage image)
		{
			byte[, ,] data = new byte[FogEnterSize, FogEnterSize, 4];

			for(int x = 0; x < FogEnterSize; x++)
			{
				for(int y = 0; y < FogEnterSize; y++)
				{
					float d = FogFraction(x - (FogEnterSize / 2), y - (FogEnterSize / 2));
					int b = (byte) (d * 255);

					if(b <= 0)
					{
						b = 0;
					}
					else if(b > 255)
					{
						b = 255;
					}

					data[y, x, 0] =
						data[y, x, 1] =
						data[y, x, 2] = 255;
					data[y, x, 3] = (byte) b;
				}
			}

			// if mipmapped, acutely viewed surfaces fade wrong
			//image.Generate(idHelper.Flatten<byte>(data), FogEnterSize, FogEnterSize, TextureFilter.Linear, false, TextureRepeat.Clamp, TextureDepth.HighQuality);
		}
		public void BindTexture(idImage texture)
		{
			_backendRenderer.BindTexture(texture);
		}