//----------------------------------------------------------------------------- // Texture.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.IO; using RacingGame.Helpers; namespace RacingGame.Graphics { /// /// Texture class helping you with using DirectX Textures and handling /// possible errors that can happen while loading (stupid DirectX /// error messages telling you absolutely nothing, so a lot of pre-checks /// help you determinate the error before even calling DirectX methods). /// public class Texture : IDisposable { public static SpriteBatch alphaSprite; public static SpriteBatch additiveSprite; /// /// Texture filename /// protected string texFilename = ""; /// /// Get filename of texture. /// public string Filename { get { return texFilename; } } /// /// Size of texture /// protected int texWidth, texHeight; /// /// Width of texture /// public int Width { get { return texWidth; } } /// /// Height of texture /// public int Height { get { return texHeight; } } /// /// Gfx rectangle /// /// Rectangle public Rectangle GfxRectangle { get { return new Rectangle(0, 0, texWidth, texHeight); } } /// /// Size of half a pixel, will be calculated when size is set. /// private Vector2 precaledHalfPixelSize = Vector2.Zero; /// /// Get the size of half a pixel, used to correct texture /// coordinates when rendering on screen, see Texture.RenderOnScreen. /// public Vector2 HalfPixelSize { get { return precaledHalfPixelSize; } } /// /// Calc half pixel size /// protected void CalcHalfPixelSize() { precaledHalfPixelSize = new Vector2( (1.0f / texWidth) / 2.0f, (1.0f / texHeight) / 2.0f); } /// /// XNA Framework Graphic Texture /// protected Texture2D internalXnaTexture; /// /// XNA Framework texture /// public virtual Texture2D XnaTexture { get { return internalXnaTexture; } } /// /// Loading succeeded? /// protected bool loaded = true; /// /// Error? /// protected string error = ""; /// /// Is texture valid? Will be false if loading failed. /// public virtual bool Valid { get { return loaded && internalXnaTexture != null; } } /// /// Has alpha? /// private bool hasAlpha; /// /// Has texture alpha information? /// public bool HasAlphaPixels { get { return hasAlpha; } } /// /// Create texture from a given filename. /// /// Set filename, must be relative and be a /// valid file in the Textures directory. public Texture(string setFilename) { if (alphaSprite == null) alphaSprite = new SpriteBatch(BaseGame.Device); if (additiveSprite == null) additiveSprite = new SpriteBatch(BaseGame.Device); if (String.IsNullOrEmpty(setFilename)) throw new ArgumentNullException(nameof(setFilename), "Unable to create texture without valid filename."); // Set content name (cut off extension!) texFilename = Path.GetFileNameWithoutExtension(setFilename); string fullFilename = Path.Combine(Directories.ContentDirectory, "Textures", texFilename); // Try loading as 2d texture internalXnaTexture = BaseGame.Content.Load(fullFilename); // Get info from the texture directly. texWidth = internalXnaTexture.Width; texHeight = internalXnaTexture.Height; // We will use alpha for Dxt3 and Dxt5 textures. hasAlpha = (internalXnaTexture.Format == SurfaceFormat.Dxt5 || internalXnaTexture.Format == SurfaceFormat.Dxt3); loaded = true; CalcHalfPixelSize(); } /// /// Create texture, protected version for derived classes. /// protected Texture() { } /// /// Create texture by just assigning a Texture2D. /// /// Tex public Texture(Texture2D tex) { if (alphaSprite == null) alphaSprite = new SpriteBatch(BaseGame.Device); if (additiveSprite == null) additiveSprite = new SpriteBatch(BaseGame.Device); if (tex == null) throw new ArgumentNullException(nameof(tex)); internalXnaTexture = tex; // Get info from the texture directly. texWidth = internalXnaTexture.Width; texHeight = internalXnaTexture.Height; loaded = true; // We will use alpha for Dxt3 and Dxt5 textures hasAlpha = (internalXnaTexture.Format == SurfaceFormat.Dxt5 || internalXnaTexture.Format == SurfaceFormat.Dxt3); CalcHalfPixelSize(); } /// /// Dispose /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Dispose /// /// Disposing protected virtual void Dispose(bool disposing) { if (disposing) { if (internalXnaTexture != null) internalXnaTexture.Dispose(); internalXnaTexture = null; } loaded = false; } /// /// Render texture at rect directly on screen using pixelRect. /// /// Rectangle /// Pixel rectangle public void RenderOnScreen(Rectangle rect, Rectangle pixelRect) { alphaSprite.Draw(internalXnaTexture, rect, pixelRect, Color.White); //SpriteHelper.AddSpriteToRender(this, rect, pixelRect); } /// /// Render on screen /// /// Rectangle /// Pixel x /// Pixel y /// Pixel width /// Pixel height public void RenderOnScreen(Rectangle rect, int pixelX, int pixelY, int pixelWidth, int pixelHeight) { alphaSprite.Draw(internalXnaTexture, rect, new Rectangle(pixelX, pixelY, pixelWidth, pixelHeight), Color.White); } /// /// Render on screen /// /// Position public void RenderOnScreen(Point pos) { alphaSprite.Draw(internalXnaTexture, new Rectangle(pos.X, pos.Y, texWidth, texHeight), new Rectangle(0, 0, texWidth, texHeight), Color.White); } /// /// Render on screen /// /// Render rectangle public void RenderOnScreen(Rectangle renderRect) { alphaSprite.Draw(internalXnaTexture, renderRect, GfxRectangle, Color.White); //SpriteHelper.AddSpriteToRender(this, // renderRect, GfxRectangle); } /// /// Render on screen relative for 1024x640 (16:9) graphics. /// /// Rel x /// Rel y /// Pixel rectangle public void RenderOnScreenRelative16To9(int relX, int relY, Rectangle pixelRect) { alphaSprite.Draw(internalXnaTexture, BaseGame.CalcRectangle( relX, relY, pixelRect.Width, pixelRect.Height), pixelRect, Color.White); //SpriteHelper.AddSpriteToRender(this, // BaseGame.CalcRectangle( // relX, relY, pixelRect.Width, pixelRect.Height), // pixelRect); } /// /// Render on screen relative 1024x786 (4:3) /// /// Rel x /// Rel y /// Pixel rectangle public void RenderOnScreenRelative4To3(int relX, int relY, Rectangle pixelRect) { alphaSprite.Draw(internalXnaTexture, BaseGame.CalcRectangleKeep4To3( relX, relY, pixelRect.Width, pixelRect.Height), pixelRect, Color.White); //SpriteHelper.AddSpriteToRender(this, // BaseGame.CalcRectangleKeep4To3( // relX, relY, pixelRect.Width, pixelRect.Height), // pixelRect); } /// /// Render on screen relative for 1600px width graphics. /// /// Rel x /// Rel y /// Pixel rectangle public void RenderOnScreenRelative1600( int relX, int relY, Rectangle pixelRect) { alphaSprite.Draw(internalXnaTexture, BaseGame.CalcRectangle1600( relX, relY, pixelRect.Width, pixelRect.Height), pixelRect, Color.White); //SpriteHelper.AddSpriteToRender(this, // BaseGame.CalcRectangle1600( // relX, relY, pixelRect.Width, pixelRect.Height), // pixelRect); } /// /// Render texture at rect directly on screen using texture cordinates. /// This method allows to render with specific color and alpha values. /// /// Rectangle /// Pixel rectangle /// Color public void RenderOnScreen(Rectangle rect, Rectangle pixelRect, Color color) { alphaSprite.Draw(internalXnaTexture, rect, pixelRect, color); //SpriteHelper.AddSpriteToRender(this, rect, pixelRect, color); } /// /// Render on screen /// /// Rectangle /// Pixel rectangle /// Color /// Blend mode public void RenderOnScreen(Rectangle rect, Rectangle pixelRect, Color color, BlendState blendState) { if (blendState == BlendState.Additive) additiveSprite.Draw(internalXnaTexture, rect, pixelRect, color); else alphaSprite.Draw(internalXnaTexture, rect, pixelRect, color); //SpriteHelper.AddSpriteToRender(this, rect, pixelRect, color, blendState); } /// /// Render on screen with rotation /// /// /// Pixel rectangle /// Rotation /// public void RenderOnScreenWithRotation( Rectangle rect, Rectangle pixelRect, float rotation, Vector2 rotationPoint) { alphaSprite.Draw(internalXnaTexture, rect, pixelRect, Color.White, rotation, rotationPoint, SpriteEffects.None, 0); } /// /// To string /// public override string ToString() { return "Texture(filename=" + texFilename + ", width=" + texWidth + ", height=" + texHeight + ", xnaTexture=" + (internalXnaTexture != null ? "valid" : "null") + ")"; } } }