public void MultipleTextures_CorrectIndices() { var atlas = new TextureAtlas(); var texture0 = atlas.AddTexture(); var texture1 = atlas.AddTexture(); var texture2 = atlas.AddTexture(); Assert.AreEqual(0, texture0.Index); Assert.AreEqual(1, texture1.Index); Assert.AreEqual(2, texture2.Index); Assert.AreEqual(texture0, atlas.GetTexture(0)); Assert.AreEqual(texture1, atlas.GetTexture(1)); Assert.AreEqual(texture2, atlas.GetTexture(2)); }
public void AddTexture() { var atlas = new TextureAtlas(); var texture = atlas.AddTexture(); Assert.IsNotNull(texture); Assert.AreEqual(atlas, texture.Atlas); Assert.AreEqual(0, texture.Index); Assert.AreEqual(texture, atlas.GetTexture(0)); }
public Texture(Resource TextureResource) { if (TextureResource == null) { Logger.Log(new LogMessage(LogSeverity.Error, $"Cannot load texture resource is null, please use Texture.Empty instead")); return; } // Store it so that we can refer to it later Resource = TextureResource; Logger.Log(new LogMessage(LogSeverity.Debug, $"Loading texture {TextureResource.Name}")); if (TextureResource.Path == null && TextureResource.Stream == null) { Logger.Log(new LogMessage(LogSeverity.Error, $"Cannot load texture resource {TextureResource.Name}, both the underlying stream and file path are null")); return; } if (!File.Exists(TextureResource.Path)) { var _tmp = Path.GetTempFileName(); using var _writer = File.Create(_tmp); TextureResource.Stream.BaseStream.CopyTo(_writer); TextureImage = Image.Load <Rgba32>(_tmp); File.Delete(_tmp); } else { TextureImage = Image.Load <Rgba32>(Resource.Path); } Logger.Log(new LogMessage(LogSeverity.Debug, $"Created new texture: {TextureImage.Width * TextureImage.Height} pixels, dimensions {TextureImage.Width}*{TextureImage.Height}")); id = counter++; TextureAtlas.AddTexture(this); }
IEnumerator ConnectAsynchronously() { string serverUrl = FixURL(ServerField.text); GameSession.Login = LoginField.text; GameSession.ServerUrl = serverUrl; TextureAtlas.Init(); LoadingScreen.SetActive(true); // Download and parse main json ResourcesInfo resourcesInfo; using (var request = UnityWebRequest.Get("http://" + serverUrl + "/main.json")) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } resourcesInfo = JsonUtility.FromJson <ResourcesInfo>('{' + request.downloadHandler.text + '}'); resourcesInfo.resourcesUrl = FixURL(resourcesInfo.resourcesUrl); } // Download and parse remapper json RemapperInfo remapperInfo; using (var request = resourcesInfo.DownloadText(resourcesInfo.remapper)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } remapperInfo = JsonUtility.FromJson <RemapperInfo>('{' + request.downloadHandler.text + '}'); GameSession.SetRemapper(remapperInfo.GetFlattenBlocks()); } // Download and apply foliage colormap using (var request = resourcesInfo.DownloadTexture(resourcesInfo.foliageColormap)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } GameSession.FoliageColormap.Load(DownloadHandlerTexture.GetContent(request)); } // Download and apply grass colormap using (var request = resourcesInfo.DownloadTexture(resourcesInfo.grassColormap)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } GameSession.GrassColormap.Load(DownloadHandlerTexture.GetContent(request)); } // Download and parse blocks json BlocksInfo blocksInfo; using (var request = resourcesInfo.DownloadText(resourcesInfo.blocks)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } blocksInfo = JsonUtility.FromJson <BlocksInfo>('{' + request.downloadHandler.text + '}'); } // Load all blocks GameSession.Palette = new Block[blocksInfo.list.Length + 1]; for (int i = 1; i < blocksInfo.list.Length + 1; i++) { TempBlock block = blocksInfo.list[i - 1]; Vector3[] faces = new Vector3[block.textures.Length]; for (int j = 0; j < faces.Length; j++) { string textureName = block.textures[j]; using (var request = resourcesInfo.DownloadTexture(textureName)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } faces[j] = TextureAtlas.AddTexture(textureName, DownloadHandlerTexture.GetContent(request), null); } } RenderType renderType = block.renderType == null ? RenderType.Block : (RenderType)Enum.Parse(typeof(RenderType), block.renderType); ShaderType shaderType = block.shaderType == null ? ShaderType.Block : (ShaderType)Enum.Parse(typeof(ShaderType), block.shaderType); BiomedType biomed = block.biomed == null ? BiomedType.None : (BiomedType)Enum.Parse(typeof(BiomedType), block.biomed); ColliderType colliderType = block.colliderType == null ? ColliderType.Block : (ColliderType)Enum.Parse(typeof(ColliderType), block.colliderType); Vector3 colliderMin = new Vector3(block.colliderMinX, block.colliderMinY, block.colliderMinZ); Vector3 colliderMax = new Vector3(block.colliderMaxX, block.colliderMaxY, block.colliderMaxZ); Block grassOverlay = null; if (block.grassOverlay != null) { using (var request = resourcesInfo.DownloadTexture(block.grassOverlay)) { request.SendWebRequest(); while (!request.isDone) { Slider.value = request.downloadProgress; yield return(null); } if (request.isHttpError || request.isNetworkError) { LoadingScreen.SetActive(false); yield break; } grassOverlay = new Block("", new Vector3[] { TextureAtlas.AddTexture( block.grassOverlay, DownloadHandlerTexture.GetContent(request), null) }, ColliderType.None, colliderMin, colliderMax); } } GameSession.Palette[i] = new Block(block.name, faces, colliderType, colliderMin, colliderMax, renderType, shaderType, biomed, grassOverlay, block.renderParam); } AsyncOperation operation = SceneManager.LoadSceneAsync("GameScene"); while (!operation.isDone) { float progress = Mathf.Clamp01(operation.progress / 0.9f); Slider.value = progress; yield return(null); } }
/// <summary> /// Generates the texture atlasses /// </summary> public void GenerateTextureAtlasses() { uint id = 1000; int cnt = 1; string baseName = "Textures/TA_" + ID + "_"; mTextureAtlasses.Clear(); TextureAtlas atlas = null; // Get a sorted list of views based on # of used textures List <GUIView> sortedViews = new List <GUIView>(Views); sortedViews.Sort((a, b) => (b.TextureIDs.Count - a.TextureIDs.Count)); List <int> allTextureIDs = new List <int>(); foreach (GUIView view in sortedViews) { allTextureIDs.AddRange(view.TextureIDs); } foreach (TextureInfo info in Textures) { allTextureIDs.Add(info.ID); } allTextureIDs = new List <int>(allTextureIDs.Distinct()); foreach (int texId in allTextureIDs) { TextureInfo info = this.GetTextureInfo(texId); if (info == null) { continue; } bool bExists = false; // This texture has already been added before. foreach (TextureAtlas tmpAtlas in mTextureAtlasses) { if (tmpAtlas.FindNode(info) != null) { bExists = false; } } if (bExists) { continue; } if (info.NoAtlas) { continue; } bool clear = (info.AtlasBorderType == TextureInfo.AtlasBorder.Clear); int padding = (info.AtlasPadding < 0) ? mAtlasPadding : info.AtlasPadding; Bitmap bitmap = Utils.ExpandImageBorder(Image.FromFile(GUIProject.CurrentProject.ProjectDirectory + "/" + info.Filename), padding, clear); if (bitmap == null) { continue; } if (atlas == null || !atlas.AddTexture(bitmap, info)) { uint finalID = (((uint)this.ID) << 24) | ((uint)2 << 16) | (((uint)id++) & 0x0000FFFF); atlas = new TextureAtlas(finalID, 2048, 2048, baseName + cnt + ".png"); if (atlas.AddTexture(bitmap, info)) { mTextureAtlasses.Add(atlas); cnt++; } else { atlas = null; } } } }
/// <summary> /// Reloads the font /// </summary> public void ReloadFont() { if (mProject == null) { return; } int borderWidth = 2; string fullPath = mProject.ProjectDirectory + "/" + mFontFile; if (System.IO.File.Exists(fullPath)) { // Ensure that the character list ALWAYS contains at least the ? character. if (!Characters.Contains('?')) { Characters.Add('?'); } // Load the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) { imageGlyph.Load(mProject.ProjectDirectory); } if (mFontData != null) { mFontData.Dispose(); } mFontData = new FontBuilder.FontData(Characters, Images); FontBuilder.Glyph[] glyphs = mFontData.GetGlyphs(fullPath, mFontSize); // Clear out our existing textures and texture atlasses foreach (TextureAtlas atlas in mTextureAtlasses) { DisposeAtlasNode(atlas.mRoot); } mTextureAtlasses.Clear(); mTextures.Clear(); mCharInfoList.Clear(); mMaxTop = -99999; Image texture = null; Bitmap textureBitmap = null; if (File.Exists(mProject.ProjectDirectory + "/" + mTextureFile)) { texture = Image.FromFile(mProject.ProjectDirectory + "/" + mTextureFile); textureBitmap = new Bitmap(texture); } TextureAtlas curAtlas = null; foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) { continue; } if (mMaxTop < glyph.mTop) { mMaxTop = glyph.mTop; } Bitmap finalBitmap = null; if (glyph.mBitmap != null) { finalBitmap = (borderWidth == 0) ? new Bitmap(glyph.mBitmap) : Utils.ExpandImageBorder(glyph.mBitmap, borderWidth, true); if (finalBitmap == null) { continue; } Bitmap outlinedBitmap = null; Bitmap texturedBitmap = null; if (OutlineAmount > 0.0f && OutlineColor.A != 0) { float s = Math.Min(1.0f, Math.Max(OutlineSharpness, 0.0f)); outlinedBitmap = BlurBitmap(finalBitmap, OutlineAmount, OutlineSharpness, OutlineColor); finalBitmap.Dispose(); finalBitmap = outlinedBitmap; } BitmapData texturedBitmapData = null; if (textureBitmap != null && glyph.mImageGlyph == 0) { texturedBitmap = ApplyTexture(textureBitmap, glyph.mBitmap, mTextureBaseline, glyph.mTop); texturedBitmapData = texturedBitmap.LockBits(new Rectangle(0, 0, texturedBitmap.Width, texturedBitmap.Height), ImageLockMode.ReadOnly, texturedBitmap.PixelFormat); } // Now we need to use the original bitmap (from the glyph) and reapply it to the new // bitmap (that may or may not have been blurred) with the fill color BitmapData sourceBitmapData = glyph.mBitmap.LockBits(new Rectangle(0, 0, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.ReadOnly, glyph.mBitmap.PixelFormat); BitmapData targetBitmapData = finalBitmap.LockBits(new Rectangle((finalBitmap.Width - glyph.mBitmap.Width) / 2, (finalBitmap.Height - glyph.mBitmap.Height) / 2, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.WriteOnly, finalBitmap.PixelFormat); try { for (int x = 0; x < sourceBitmapData.Width; x++) { for (int y = 0; y < sourceBitmapData.Height; y++) { IntPtr sourcePixel = (IntPtr)((int)sourceBitmapData.Scan0 + sourceBitmapData.Stride * y + x * 4); IntPtr targetPixel = (IntPtr)((int)targetBitmapData.Scan0 + targetBitmapData.Stride * y + x * 4); IntPtr texturePixel = IntPtr.Zero; if (texturedBitmapData != null) { texturePixel = (IntPtr)((int)texturedBitmapData.Scan0 + texturedBitmapData.Stride * y + x * 4); } Color srcColor = Color.FromArgb(Marshal.ReadInt32(sourcePixel)); Color tgtColor = Color.FromArgb(Marshal.ReadInt32(targetPixel)); Color texColor = (texturePixel != IntPtr.Zero) ? Color.FromArgb(Marshal.ReadInt32(texturePixel)) : Color.White; float alpha = srcColor.A / 255.0f; if (alpha == 0.0f) { continue; } byte r = (byte)(tgtColor.R * (1.0f - alpha) + FillColor.R * (srcColor.R / 255.0f) * (texColor.R / 255.0f) * alpha); byte g = (byte)(tgtColor.G * (1.0f - alpha) + FillColor.G * (srcColor.G / 255.0f) * (texColor.G / 255.0f) * alpha); byte b = (byte)(tgtColor.B * (1.0f - alpha) + FillColor.B * (srcColor.B / 255.0f) * (texColor.B / 255.0f) * alpha); byte a = (byte)(tgtColor.A * (1.0f - alpha) + FillColor.A * (srcColor.A / 255.0f) * (texColor.A / 255.0f) * alpha); Color finalColor = Color.FromArgb(a, r, g, b); Marshal.WriteInt32(targetPixel, finalColor.ToArgb()); } } } catch (Exception ex) { System.Console.WriteLine("Exception : " + ex); } glyph.mBitmap.UnlockBits(sourceBitmapData); finalBitmap.UnlockBits(targetBitmapData); if (texturedBitmapData != null) { texturedBitmap.UnlockBits(texturedBitmapData); } } else { finalBitmap = new Bitmap(4, 4); } if (curAtlas == null || !curAtlas.AddTexture(finalBitmap, glyph)) { curAtlas = new TextureAtlas(0, AtlasSize.Width, AtlasSize.Height, "tmp"); mTextureAtlasses.Add(curAtlas); curAtlas.AddTexture(finalBitmap, glyph); } } if (textureBitmap != null) { textureBitmap.Dispose(); } if (texture != null) { texture.Dispose(); } // Unload the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) { imageGlyph.Unload(); } // Then iterate and add to the texture atlas(ses). if (Otter.Interface.Graphics.Instance != null) { foreach (int textureID in mTextures) { Otter.Interface.Graphics.Instance.UnloadTexture(textureID); } foreach (TextureAtlas atlas in mTextureAtlasses) { Bitmap bitmap = atlas.GetBitmap(); // BitmapData BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); // Get the address of the first line. IntPtr ptr = bitmapData.Scan0; // Declare an array to hold the bytes of the bitmap. int size = Math.Abs(bitmapData.Stride) * bitmap.Height; byte[] bytes = new byte[size]; System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, size); int textureID = Otter.Interface.Graphics.Instance.LoadTexture(bytes, bitmap.Width, bitmap.Height, 32); bitmap.UnlockBits(bitmapData); mTextures.Add(textureID); bitmap.Dispose(); // SLOW foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) { continue; } AtlasNode node = atlas.FindNode(glyph); if (node != null) { NewCharInfo info = new NewCharInfo(); int diffW = node.mRectangle.Width - borderWidth * 2 - glyph.mW; int diffH = node.mRectangle.Height - borderWidth * 2 - glyph.mH; info.mCharCode = glyph.mCharCode; info.mImageGlyph = glyph.mImageGlyph; info.mX = node.mRectangle.X + borderWidth; info.mY = node.mRectangle.Y + borderWidth; info.mW = glyph.mW + diffW; info.mH = glyph.mH + diffH; info.mTop = glyph.mTop + diffH / 2; info.mAdvance = glyph.mAdvance; info.mLeftBearing = glyph.mLeftBearing - diffW / 2; info.mAtlasIndex = mTextureAtlasses.IndexOf(atlas); mCharInfoList.Add(info); } } } MemoryStream stream = new MemoryStream(); Platform platform = new Platform(); platform.Endianness = Endian.Little; platform.ColorFormat = ColorFormat.ARGB; PlatformBinaryWriter bw = new PlatformBinaryWriter(stream, platform); this.Export(bw); mFontID = Otter.Interface.Graphics.Instance.LoadFont(this.Name, stream.GetBuffer(), mTextures); bw.Close(); stream.Close(); } } }
static Texture() { blank = new(ResourceManager.GetFile("white texture")); blank.id = counter++; TextureAtlas.AddTexture(blank); }