/// <summary> /// Gets Unity Texture2D from Daggerfall texture with more options. /// </summary> /// <param name="archive">Archive index.</param> /// <param name="record">Record index.</param> /// <param name="frame">Frame index.</param> /// <param name="alphaIndex">Index to receive transparent alpha.</param> /// <param name="rectOut">Receives UV rect for texture inside border.</param> /// <param name="border">Number of pixels border to add around image.</param> /// <param name="dilate">Blend texture into surrounding empty pixels. Requires border.</param> /// <param name="copyToOppositeBorder">Copy texture edges to opposite border. Requires border, will overwrite dilate.</param> /// <returns>Texture2D or null.</returns> public Texture2D GetTexture2D( int archive, int record, int frame, int alphaIndex, out Rect rectOut, int border = 0, bool dilate = false, bool copyToOppositeBorder = false, bool makeNoLongerReadable = true) { // Ready check if (!ReadyCheck()) { rectOut = new Rect(); return(null); } // Load texture file textureFile.Load(Path.Combine(Arena2Path, TextureFile.IndexToFileName(archive)), FileUsage.UseMemory, true); // Get Color32 array DFSize sz; Color32[] colors = textureFile.GetColors32(record, frame, alphaIndex, border, out sz); // Dilate edges if (border > 0 && dilate && !copyToOppositeBorder) { ImageProcessing.DilateColors(ref colors, sz); } // Copy to opposite border if (border > 0 && copyToOppositeBorder) { ImageProcessing.WrapBorder(ref colors, sz, border); } // Create Texture2D Texture2D texture; if (alphaIndex < 0) { texture = new Texture2D(sz.Width, sz.Height, TextureFormat.RGB24, MipMaps); } else { texture = new Texture2D(sz.Width, sz.Height, TextureFormat.RGBA32, MipMaps); } texture.SetPixels32(colors); texture.Apply(true, makeNoLongerReadable); // Shrink UV rect to compensate for internal border float ru = 1f / sz.Width; float rv = 1f / sz.Height; rectOut = new Rect(border * ru, border * rv, (sz.Width - border * 2) * ru, (sz.Height - border * 2) * rv); return(texture); }
/// <summary> /// Gets specially packed tileset atlas for terrains. /// This needs to be improved to create each mip level manually to further reduce artifacts. /// </summary> /// <param name="archive">Archive index.</param> /// <param name="stayReadable">Texture should stay readable.</param> /// <param name="nonAlphaFormat">Non-alpha TextureFormat.</param> /// <returns></returns> public GetTextureResults GetTerrainTilesetTexture( int archive, bool stayReadable = false, SupportedNonAlphaTextureFormats nonAlphaFormat = SupportedNonAlphaTextureFormats.RGB24) { const int atlasDim = 2048; const int gutterSize = 32; GetTextureResults results = new GetTextureResults(); // Load texture file and check count matches terrain tiles TextureFile textureFile = new TextureFile(Path.Combine(Arena2Path, TextureFile.IndexToFileName(archive)), FileUsage.UseMemory, true); if (textureFile.RecordCount != 56) { return(results); } // Rollout tiles into atlas. // This is somewhat inefficient, but fortunately atlases only // need to be generated once and can be prepared offline where // startup time is critical. int x = 0, y = 0; Color32[] atlasColors = new Color32[atlasDim * atlasDim]; for (int record = 0; record < textureFile.RecordCount; record++) { // Create base image with gutter DFSize sz; Color32[] albedo = textureFile.GetColors32(record, 0, -1, gutterSize, out sz); // Wrap and clamp textures based on tile switch (record) { // Textures that do not tile in any direction case 5: case 7: case 10: case 12: case 15: case 17: case 20: case 22: case 25: case 27: case 30: case 32: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 55: ImageProcessing.ClampBorder(ref albedo, sz, gutterSize); break; // Textures that clamp horizontally and tile vertically case 6: case 11: case 16: case 21: case 26: case 31: ImageProcessing.WrapBorder(ref albedo, sz, gutterSize, false); ImageProcessing.ClampBorder(ref albedo, sz, gutterSize, true, false); break; // Textures that tile in all directions default: ImageProcessing.WrapBorder(ref albedo, sz, gutterSize); break; } // Create variants Color32[] rotate = ImageProcessing.RotateColors(ref albedo, sz.Width, sz.Height); Color32[] flip = ImageProcessing.FlipColors(ref albedo, sz.Width, sz.Height); Color32[] rotateFlip = ImageProcessing.RotateColors(ref flip, sz.Width, sz.Height); // Insert into atlas ImageProcessing.InsertColors(ref albedo, ref atlasColors, x, y, sz.Width, sz.Height, atlasDim, atlasDim); ImageProcessing.InsertColors(ref rotate, ref atlasColors, x + sz.Width, y, sz.Width, sz.Height, atlasDim, atlasDim); ImageProcessing.InsertColors(ref flip, ref atlasColors, x + sz.Width * 2, y, sz.Width, sz.Height, atlasDim, atlasDim); ImageProcessing.InsertColors(ref rotateFlip, ref atlasColors, x + sz.Width * 3, y, sz.Width, sz.Height, atlasDim, atlasDim); // Increment position x += sz.Width * 4; if (x >= atlasDim) { y += sz.Height; x = 0; } } // Create Texture2D Texture2D albedoAtlas = new Texture2D(atlasDim, atlasDim, ParseTextureFormat(nonAlphaFormat), MipMaps); albedoAtlas.SetPixels32(atlasColors); albedoAtlas.Apply(true, !stayReadable); // Change settings for these textures albedoAtlas.wrapMode = TextureWrapMode.Clamp; albedoAtlas.anisoLevel = 8; // Store results results.albedoMap = albedoAtlas; return(results); }