using System; using System.Collections; using System.IO; using UnityEngine; using UnityEngine.Networking; namespace BrainFailProductions.PolyFew.AsImpL { /// /// Class for loading textures files into Unity scene at run-time and in editor mode. /// /// /// Derived from "Runtime OBJ Loader" /// (http://forum.unity3d.com/threads/free-runtime-obj-loader.365884/) /// and from "runtime .OBJ file loader for Unity3D" /// (https://github.com/hammmm/unity-obj-loader) and /// (https://github.com/cmdr2/unity-remote-obj-loader) /// /// public class TextureLoader : MonoBehaviour { /// /// Load an image from a file into a Texture2D. /// /// URL of the texture image. /// The loaded texture or null on error. public static Texture2D LoadTextureFromUrl(string url) { const string prefix = "file:///"; if (url.StartsWith(prefix)) { url = url.Substring(prefix.Length); } else { url = Path.GetFullPath(url); } return LoadTexture(url); } /// /// Load an image from a file into a Texture2D. /// /// file name of the image to load /// The loaded texture or null on error. public static Texture2D LoadTexture(string fileName) { string ext = Path.GetExtension(fileName).ToLower(); if (ext == ".png" || ext == ".jpg") { Texture2D t2d = new Texture2D(1, 1); t2d.LoadImage(File.ReadAllBytes(fileName)); return t2d; } else if (ext == ".dds") { Texture2D returnTex = LoadDDSManual(fileName); return returnTex; } else if (ext == ".tga") { Texture2D returnTex = LoadTGA(fileName); return returnTex; } else { Debug.Log("texture not supported : " + fileName); } return null; } /// /// Load a TGA image from a file into a Texture2D. /// /// file name of the image to load /// The loaded texture or null on error. public static Texture2D LoadTGA(string fileName) { using (var imageFile = File.OpenRead(fileName)) { return LoadTGA(imageFile); } } /// /// Load a DDS image from a file into a Texture2D. /// /// file name of the image to load /// The loaded texture or null on error. public static Texture2D LoadDDSManual(string ddsPath) { try { byte[] ddsBytes = File.ReadAllBytes(ddsPath); byte ddsSizeCheck = ddsBytes[4]; if (ddsSizeCheck != 124) throw new System.Exception("Invalid DDS DXTn texture. Unable to read"); //this header byte should be 124 for DDS image files int height = ddsBytes[13] * 256 + ddsBytes[12]; int width = ddsBytes[17] * 256 + ddsBytes[16]; byte DXTType = ddsBytes[87]; TextureFormat textureFormat = TextureFormat.DXT5; if (DXTType == 49) { textureFormat = TextureFormat.DXT1; // Debug.Log ("DXT1"); } if (DXTType == 53) { textureFormat = TextureFormat.DXT5; // Debug.Log ("DXT5"); } int DDS_HEADER_SIZE = 128; byte[] dxtBytes = new byte[ddsBytes.Length - DDS_HEADER_SIZE]; Buffer.BlockCopy(ddsBytes, DDS_HEADER_SIZE, dxtBytes, 0, ddsBytes.Length - DDS_HEADER_SIZE); System.IO.FileInfo finf = new System.IO.FileInfo(ddsPath); Texture2D texture = new Texture2D(width, height, textureFormat, false); texture.LoadRawTextureData(dxtBytes); texture.Apply(); texture.name = finf.Name; return (texture); } catch (System.Exception ex) { Debug.LogError("Could not load DDS: " + ex); return new Texture2D(8, 8); } } /// /// Load a TGA image from a stram into a Texture2D. /// /// input stream /// The loaded Texture2D /// /// This directly comes from the code submitted by aaro4130 and edited by ALLCAPS on the Unity forums (thanks to all!). /// https://forum.unity3d.com/threads/tga-loader-for-unity3d.172291/ /// public static Texture2D LoadTGA(Stream TGAStream) { try { using (BinaryReader r = new BinaryReader(TGAStream)) { TgaHeader th = LoadTgaHeader(r); // Skip some header info we don't care about. // Even if we did care, we have to move the stream seek point to the beginning, // as the previous method in the workflow left it at the end. //r.BaseStream.Seek( 12, SeekOrigin.Begin ); short width = (short)th.width; short height = (short)th.height; int bitDepth = th.bits; //bool hflip = (th.tiDescriptor & 16) == 16; bool vflip = (th.descriptor & 32) == 32; //// Skip a byte of header information we don't care about. //r.BaseStream.Seek( 1, SeekOrigin.Current ); Texture2D tex = new Texture2D(width, height); Color32[] pulledColors = new Color32[width * height]; int length = width * height; if (bitDepth == 32) { for (int row = 1; row <= height; row++) { for (int col = 0; col < width; col++) { byte red = r.ReadByte(); byte green = r.ReadByte(); byte blue = r.ReadByte(); byte alpha = r.ReadByte(); // pulledColors [i] = new Color32(blue, green, red, alpha); int idx; if (vflip) idx = length - row * width + col; else idx = length - ((height - row + 1) * width) + col; pulledColors[idx] = new Color32(blue, green, red, alpha); } } } else if (bitDepth == 24) { for (int row = 1; row <= height; row++) { for (int col = 0; col < width; col++) { byte red = r.ReadByte(); byte green = r.ReadByte(); byte blue = r.ReadByte(); int idx; if (vflip) idx = length - row * width + col; else idx = length - ((height - row + 1) * width) + col; pulledColors[idx] = new Color32(blue, green, red, 255); } } } else { throw new Exception("TGA texture had non 32/24 bit depth."); } tex.SetPixels32(pulledColors); tex.Apply(); return tex; } } catch (Exception e) { // let everything else load even if this TGA loading failed Debug.LogWarning(e); return null; } } private static TgaHeader LoadTgaHeader(BinaryReader r) { TgaHeader th = new TgaHeader(); r.BaseStream.Seek(0, SeekOrigin.Current); // fread(&th, sizeof(gvImgTGAHeader), 1, fp); // due to byte alignment read the components one at a time th.identSize = r.ReadByte(); th.colorMapType = r.ReadByte(); th.imageType = r.ReadByte(); th.colorMapStart = r.ReadUInt16(); th.colorMapLength = r.ReadUInt16(); th.colorMapBits = r.ReadByte(); th.xStart = r.ReadUInt16(); th.ySstart = r.ReadUInt16(); th.width = r.ReadUInt16(); th.height = r.ReadUInt16(); th.bits = r.ReadByte(); th.descriptor = r.ReadByte(); Debug.LogFormat("TGA descriptor = {0}", th.descriptor); // check if the image contains no data if (th.imageType == 0) new Exception("TGA image contains no data."); // GV_IMG_ERROR_NO_DATA; // check for other types (compressed images) if (th.imageType > 10) new Exception("compressed TGA not supported."); //GV_IMG_ERROR_COMPRESSED_FILE; // check if the image is color indexed if (th.imageType == 1 || th.imageType == 9) new Exception("color indexed TGA not supported."); //GV_IMG_ERROR_INDEXED_COLOR; // for now we only consider 24bit rgb or rle images if (th.bits != 24 && th.bits != 32) throw new Exception("only 24/32 bits TGA supported."); //GV_IMG_ERROR_BITS; // width and height must be valid ones if (th.width <= 0 || th.height <= 0) throw new Exception("TGA texture has invalid size.");// GV_IMG_ERROR_SIZE; // skips id header r.BaseStream.Seek(th.identSize, SeekOrigin.Current); return th; } private class TgaHeader { public byte identSize; public byte colorMapType; public byte imageType; public ushort colorMapStart; public ushort colorMapLength; public byte colorMapBits; public ushort xStart; public ushort ySstart; public ushort width; public ushort height; public byte bits; public byte descriptor; } } }