(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -0,0 +1,551 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using MonoGame.Utilities;
|
||||
using MonoGame.Utilities.Png;
|
||||
|
||||
#if IOS
|
||||
using UIKit;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using System.Drawing;
|
||||
#endif
|
||||
|
||||
#if OPENGL
|
||||
using MonoGame.OpenGL;
|
||||
using GLPixelFormat = MonoGame.OpenGL.PixelFormat;
|
||||
using PixelFormat = MonoGame.OpenGL.PixelFormat;
|
||||
|
||||
#if ANDROID
|
||||
using Android.Graphics;
|
||||
#endif
|
||||
#endif // OPENGL
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
public partial class Texture2D : Texture
|
||||
{
|
||||
private void PlatformConstruct(int width, int height, bool mipmap, SurfaceFormat format, SurfaceType type, bool shared)
|
||||
{
|
||||
this.glTarget = TextureTarget.Texture2D;
|
||||
format.GetGLFormat(GraphicsDevice, out glInternalFormat, out glFormat, out glType);
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
GenerateGLTextureIfRequired();
|
||||
int w = width;
|
||||
int h = height;
|
||||
int level = 0;
|
||||
while (true)
|
||||
{
|
||||
if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats)
|
||||
{
|
||||
int imageSize = 0;
|
||||
// PVRTC has explicit calculations for imageSize
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
|
||||
if (format == SurfaceFormat.RgbPvrtc2Bpp || format == SurfaceFormat.RgbaPvrtc2Bpp)
|
||||
{
|
||||
imageSize = (Math.Max(w, 16) * Math.Max(h, 8) * 2 + 7) / 8;
|
||||
}
|
||||
else if (format == SurfaceFormat.RgbPvrtc4Bpp || format == SurfaceFormat.RgbaPvrtc4Bpp)
|
||||
{
|
||||
imageSize = (Math.Max(w, 8) * Math.Max(h, 8) * 4 + 7) / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
int blockSize = format.GetSize();
|
||||
int blockWidth, blockHeight;
|
||||
format.GetBlockSize(out blockWidth, out blockHeight);
|
||||
int wBlocks = (w + (blockWidth - 1)) / blockWidth;
|
||||
int hBlocks = (h + (blockHeight - 1)) / blockHeight;
|
||||
imageSize = wBlocks * hBlocks * blockSize;
|
||||
}
|
||||
GL.CompressedTexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, imageSize, IntPtr.Zero);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, glFormat, glType, IntPtr.Zero);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
if ((w == 1 && h == 1) || !mipmap)
|
||||
break;
|
||||
if (w > 1)
|
||||
w = w / 2;
|
||||
if (h > 1)
|
||||
h = h / 2;
|
||||
++level;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void PlatformSetData<T>(int level, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
int w, h;
|
||||
GetSizeForLevel(Width, Height, level, out w, out h);
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
var elementSizeInByte = ReflectionHelpers.SizeOf<T>.Get();
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
// Use try..finally to make sure dataHandle is freed in case of an error
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * elementSizeInByte;
|
||||
var dataPtr = new IntPtr(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
// Store the current bound texture.
|
||||
var prevTexture = GraphicsExtensions.GetBoundTexture2D();
|
||||
|
||||
if (prevTexture != glTexture)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, glTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
GenerateGLTextureIfRequired();
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, Math.Min(_format.GetSize(), 8));
|
||||
|
||||
if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats)
|
||||
{
|
||||
GL.CompressedTexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, elementCount * elementSizeInByte, dataPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, glFormat, glType, dataPtr);
|
||||
}
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
#if !ANDROID
|
||||
// Required to make sure that any texture uploads on a thread are completed
|
||||
// before the main thread tries to use the texture.
|
||||
GL.Finish();
|
||||
GraphicsExtensions.CheckGLError();
|
||||
#endif
|
||||
// Restore the bound texture.
|
||||
if (prevTexture != glTexture)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, prevTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void PlatformSetData<T>(int level, int arraySlice, Rectangle rect, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
var elementSizeInByte = ReflectionHelpers.SizeOf<T>.Get();
|
||||
var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
// Use try..finally to make sure dataHandle is freed in case of an error
|
||||
try
|
||||
{
|
||||
var startBytes = startIndex * elementSizeInByte;
|
||||
var dataPtr = new IntPtr(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes);
|
||||
// Store the current bound texture.
|
||||
var prevTexture = GraphicsExtensions.GetBoundTexture2D();
|
||||
|
||||
if (prevTexture != glTexture)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, glTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
GenerateGLTextureIfRequired();
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, Math.Min(_format.GetSize(), 8));
|
||||
|
||||
if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats)
|
||||
{
|
||||
GL.CompressedTexSubImage2D(TextureTarget.Texture2D, level, rect.X, rect.Y, rect.Width, rect.Height,
|
||||
(PixelInternalFormat)glInternalFormat, elementCount * elementSizeInByte, dataPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, level, rect.X, rect.Y,
|
||||
rect.Width, rect.Height, glFormat, glType, dataPtr);
|
||||
}
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
#if !ANDROID
|
||||
// Required to make sure that any texture uploads on a thread are completed
|
||||
// before the main thread tries to use the texture.
|
||||
GL.Finish();
|
||||
GraphicsExtensions.CheckGLError();
|
||||
#endif
|
||||
// Restore the bound texture.
|
||||
if (prevTexture != glTexture)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, prevTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
dataHandle.Free();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void PlatformGetData<T>(int level, int arraySlice, Rectangle rect, T[] data, int startIndex, int elementCount) where T : struct
|
||||
{
|
||||
Threading.EnsureUIThread();
|
||||
|
||||
#if GLES
|
||||
// TODO: check for for non renderable formats (formats that can't be attached to FBO)
|
||||
|
||||
var framebufferId = 0;
|
||||
GL.GenFramebuffers(1, out framebufferId);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebufferId);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, this.glTexture, 0);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
GL.ReadPixels(rect.X, rect.Y, rect.Width, rect.Height, this.glFormat, this.glType, data);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GraphicsDevice.DisposeFramebuffer(framebufferId);
|
||||
#else
|
||||
var tSizeInByte = ReflectionHelpers.SizeOf<T>.Get();
|
||||
GL.BindTexture(TextureTarget.Texture2D, this.glTexture);
|
||||
GL.PixelStore(PixelStoreParameter.PackAlignment, Math.Min(tSizeInByte, 8));
|
||||
|
||||
if (glFormat == (PixelFormat) GLPixelFormat.CompressedTextureFormats)
|
||||
{
|
||||
// Note: for compressed format Format.GetSize() returns the size of a 4x4 block
|
||||
var pixelToT = Format.GetSize() / tSizeInByte;
|
||||
var tFullWidth = Math.Max(this.width >> level, 1) / 4 * pixelToT;
|
||||
var temp = new T[Math.Max(this.height >> level, 1) / 4 * tFullWidth];
|
||||
GL.GetCompressedTexImage(TextureTarget.Texture2D, level, temp);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
var rowCount = rect.Height / 4;
|
||||
var tRectWidth = rect.Width / 4 * Format.GetSize() / tSizeInByte;
|
||||
for (var r = 0; r < rowCount; r++)
|
||||
{
|
||||
var tempStart = rect.X / 4 * pixelToT + (rect.Top / 4 + r) * tFullWidth;
|
||||
var dataStart = startIndex + r * tRectWidth;
|
||||
Array.Copy(temp, tempStart, data, dataStart, tRectWidth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we need to convert from our format size to the size of T here
|
||||
var tFullWidth = Math.Max(this.width >> level, 1) * Format.GetSize() / tSizeInByte;
|
||||
var temp = new T[Math.Max(this.height >> level, 1) * tFullWidth];
|
||||
GL.GetTexImage(TextureTarget.Texture2D, level, glFormat, glType, temp);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
var pixelToT = Format.GetSize() / tSizeInByte;
|
||||
var rowCount = rect.Height;
|
||||
var tRectWidth = rect.Width * pixelToT;
|
||||
for (var r = 0; r < rowCount; r++)
|
||||
{
|
||||
var tempStart = rect.X * pixelToT + (r + rect.Top) * tFullWidth;
|
||||
var dataStart = startIndex + r * tRectWidth;
|
||||
Array.Copy(temp, tempStart, data, dataStart, tRectWidth);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private unsafe static Texture2D PlatformFromStream(GraphicsDevice graphicsDevice, Stream stream)
|
||||
{
|
||||
int width, height, channels;
|
||||
|
||||
// The data returned is always four channel BGRA
|
||||
var data = ImageReader.Read(stream, out width, out height, out channels, Imaging.STBI_rgb_alpha);
|
||||
|
||||
// XNA blacks out any pixels with an alpha of zero.
|
||||
if (channels == 4)
|
||||
{
|
||||
fixed (byte* b = &data[0])
|
||||
{
|
||||
for (var i = 0; i < data.Length; i += 4)
|
||||
{
|
||||
if (b[i + 3] == 0)
|
||||
{
|
||||
b[i + 0] = 0;
|
||||
b[i + 1] = 0;
|
||||
b[i + 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Texture2D texture = null;
|
||||
texture = new Texture2D(graphicsDevice, width, height);
|
||||
texture.SetData(data);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
#if IOS
|
||||
[CLSCompliant(false)]
|
||||
public static Texture2D FromStream(GraphicsDevice graphicsDevice, UIImage uiImage)
|
||||
{
|
||||
return PlatformFromStream(graphicsDevice, uiImage.CGImage);
|
||||
}
|
||||
#elif ANDROID
|
||||
[CLSCompliant(false)]
|
||||
public static Texture2D FromStream(GraphicsDevice graphicsDevice, Bitmap bitmap)
|
||||
{
|
||||
return PlatformFromStream(graphicsDevice, bitmap);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public void Reload(Bitmap image)
|
||||
{
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
if ((width != image.Width) || (height != image.Height))
|
||||
{
|
||||
using (Bitmap imagePadded = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888))
|
||||
{
|
||||
Canvas canvas = new Canvas(imagePadded);
|
||||
canvas.DrawARGB(0, 0, 0, 0);
|
||||
canvas.DrawBitmap(image, 0, 0, null);
|
||||
imagePadded.GetPixels(pixels, 0, width, 0, 0, width, height);
|
||||
imagePadded.Recycle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image.GetPixels(pixels, 0, width, 0, 0, width, height);
|
||||
}
|
||||
|
||||
image.Recycle();
|
||||
|
||||
this.SetData<int>(pixels);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IOS
|
||||
private static Texture2D PlatformFromStream(GraphicsDevice graphicsDevice, CGImage cgImage)
|
||||
{
|
||||
var width = cgImage.Width;
|
||||
var height = cgImage.Height;
|
||||
|
||||
var data = new byte[width * height * 4];
|
||||
|
||||
var colorSpace = CGColorSpace.CreateDeviceRGB();
|
||||
var bitmapContext = new CGBitmapContext(data, width, height, 8, width * 4, colorSpace, CGBitmapFlags.PremultipliedLast);
|
||||
bitmapContext.DrawImage(new RectangleF(0, 0, width, height), cgImage);
|
||||
bitmapContext.Dispose();
|
||||
colorSpace.Dispose();
|
||||
|
||||
Texture2D texture = null;
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
texture = new Texture2D(graphicsDevice, (int)width, (int)height, false, SurfaceFormat.Color);
|
||||
texture.SetData(data);
|
||||
});
|
||||
|
||||
return texture;
|
||||
}
|
||||
#elif ANDROID
|
||||
private static Texture2D PlatformFromStream(GraphicsDevice graphicsDevice, Bitmap image)
|
||||
{
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
if ((width != image.Width) || (height != image.Height))
|
||||
{
|
||||
using (Bitmap imagePadded = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888))
|
||||
{
|
||||
Canvas canvas = new Canvas(imagePadded);
|
||||
canvas.DrawARGB(0, 0, 0, 0);
|
||||
canvas.DrawBitmap(image, 0, 0, null);
|
||||
imagePadded.GetPixels(pixels, 0, width, 0, 0, width, height);
|
||||
imagePadded.Recycle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image.GetPixels(pixels, 0, width, 0, 0, width, height);
|
||||
}
|
||||
image.Recycle();
|
||||
|
||||
// Convert from ARGB to ABGR
|
||||
ConvertToABGR(height, width, pixels);
|
||||
|
||||
Texture2D texture = null;
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
texture = new Texture2D(graphicsDevice, width, height, false, SurfaceFormat.Color);
|
||||
texture.SetData<int>(pixels);
|
||||
});
|
||||
|
||||
return texture;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void FillTextureFromStream(Stream stream)
|
||||
{
|
||||
#if ANDROID
|
||||
using (Bitmap image = BitmapFactory.DecodeStream(stream, null, new BitmapFactory.Options
|
||||
{
|
||||
InScaled = false,
|
||||
InDither = false,
|
||||
InJustDecodeBounds = false,
|
||||
InPurgeable = true,
|
||||
InInputShareable = true,
|
||||
}))
|
||||
{
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
image.GetPixels(pixels, 0, width, 0, 0, width, height);
|
||||
|
||||
// Convert from ARGB to ABGR
|
||||
ConvertToABGR(height, width, pixels);
|
||||
|
||||
this.SetData<int>(pixels);
|
||||
image.Recycle();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void PlatformSaveAsJpeg(Stream stream, int width, int height)
|
||||
{
|
||||
#if DESKTOPGL
|
||||
SaveAsImage(stream, width, height, ImageWriterFormat.Jpg);
|
||||
#elif ANDROID
|
||||
SaveAsImage(stream, width, height, Bitmap.CompressFormat.Jpeg);
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void PlatformSaveAsPng(Stream stream, int width, int height)
|
||||
{
|
||||
#if DESKTOPGL
|
||||
SaveAsImage(stream, width, height, ImageWriterFormat.Png);
|
||||
#elif ANDROID
|
||||
SaveAsImage(stream, width, height, Bitmap.CompressFormat.Png);
|
||||
#else
|
||||
var pngWriter = new PngWriter();
|
||||
pngWriter.Write(this, stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DESKTOPGL
|
||||
internal void SaveAsImage(Stream stream, int width, int height, ImageWriterFormat format)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException("stream", "'stream' cannot be null (Nothing in Visual Basic)");
|
||||
}
|
||||
if (width <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("width", width, "'width' cannot be less than or equal to zero");
|
||||
}
|
||||
if (height <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("height", height, "'height' cannot be less than or equal to zero");
|
||||
}
|
||||
byte[] data = null;
|
||||
try
|
||||
{
|
||||
data = new byte[width * height * 4];
|
||||
GetData(data);
|
||||
|
||||
var writer = new ImageWriter();
|
||||
writer.Write(data, width, height, 4, format, stream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif ANDROID
|
||||
private void SaveAsImage(Stream stream, int width, int height, Bitmap.CompressFormat format)
|
||||
{
|
||||
int[] data = new int[width * height];
|
||||
GetData(data);
|
||||
// internal structure is BGR while bitmap expects RGB
|
||||
for (int i = 0; i < data.Length; ++i)
|
||||
{
|
||||
uint pixel = (uint)data[i];
|
||||
data[i] = (int)((pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16));
|
||||
}
|
||||
using (Bitmap bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888))
|
||||
{
|
||||
bitmap.SetPixels(data, 0, width, 0, 0, width, height);
|
||||
bitmap.Compress(format, 100, stream);
|
||||
bitmap.Recycle();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// This method allows games that use Texture2D.FromStream
|
||||
// to reload their textures after the GL context is lost.
|
||||
private void PlatformReload(Stream textureStream)
|
||||
{
|
||||
var prev = GraphicsExtensions.GetBoundTexture2D();
|
||||
|
||||
GenerateGLTextureIfRequired();
|
||||
FillTextureFromStream(textureStream);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, prev);
|
||||
}
|
||||
|
||||
private void GenerateGLTextureIfRequired()
|
||||
{
|
||||
if (this.glTexture < 0)
|
||||
{
|
||||
GL.GenTextures(1, out this.glTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
// For best compatibility and to keep the default wrap mode of XNA, only set ClampToEdge if either
|
||||
// dimension is not a power of two.
|
||||
var wrap = TextureWrapMode.Repeat;
|
||||
if (((width & (width - 1)) != 0) || ((height & (height - 1)) != 0))
|
||||
wrap = TextureWrapMode.ClampToEdge;
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, this.glTexture);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
|
||||
(_levelCount > 1) ? (int)TextureMinFilter.LinearMipmapLinear : (int)TextureMinFilter.Linear);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter,
|
||||
(int)TextureMagFilter.Linear);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)wrap);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)wrap);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
// Set mipmap levels
|
||||
#if !GLES
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
|
||||
#endif
|
||||
GraphicsExtensions.CheckGLError();
|
||||
if (GraphicsDevice.GraphicsCapabilities.SupportsTextureMaxLevel)
|
||||
{
|
||||
if (_levelCount > 0)
|
||||
{
|
||||
GL.TexParameter(TextureTarget.Texture2D, SamplerState.TextureParameterNameTextureMaxLevel, _levelCount - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexParameter(TextureTarget.Texture2D, SamplerState.TextureParameterNameTextureMaxLevel, 1000);
|
||||
}
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user