/// <summary> /// Render this submesh<para/> /// Отрисовка этого меша /// </summary> /// <param name="td">Textures to use<para/>Текстуры для использования</param> /// <param name="trans">Transparent mode<para/>Полупрозрачный режим</param> public void Render(RendererBase renderer, TextureDictionary td, bool trans, bool force = false) { if (State != ReadyState.Obsolette) { if (State == ReadyState.Empty) { Build(); State = ReadyState.NotSent; } else if (State == ReadyState.Complete) { DrawGL(renderer, td, trans, force); } } ParentModel.UseCount++; }
/// <summary> /// Bind material data<para/> /// Присвоение материала /// </summary> void BindMaterial(RendererBase renderer, Surface surf, TextureDictionary td) { Material mat = surf.Material; if (mat.Textures != null) { Texture t = (Texture)mat.Textures[0]; TextureDictionary.Texture tex = t.CachedTexture; // Caching texture // Кешируем текстуру if (tex != null) { if (tex.State == TextureDictionary.ReadyState.Obsolette) { tex = null; } } if (tex == null) { string lname = t.Name.ToLower(); if (td.Textures.ContainsKey(lname)) { tex = td.Textures[lname]; t.CachedTexture = tex; } } // Binding texture coord array // Установка массива текстурных координат GL.EnableClientState(ArrayCap.TextureCoordArray); GL.BindBuffer(BufferTarget.ArrayBuffer, tex1Buffer); GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero); // Binding it // Установка текстуры if (tex != null) { if (tex.State == TextureDictionary.ReadyState.Complete) { // Binding tex // Установка текстуры tex.Bind(); // Setting up addressing and filtering // Установка адресации и фильтрации TextureFile.FilterMode fm = t.Filter; if (true) //!tex.Mipmapped) { { switch (t.Filter) { case TextureFile.FilterMode.MipNearest: fm = TextureFile.FilterMode.Nearest; break; case TextureFile.FilterMode.MipLinear: fm = TextureFile.FilterMode.Nearest; break; case TextureFile.FilterMode.LinearMipNearest: fm = TextureFile.FilterMode.Linear; break; case TextureFile.FilterMode.LinearMipLinear: fm = TextureFile.FilterMode.Linear; break; } } switch (fm) { case TextureFile.FilterMode.Nearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.Linear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; case TextureFile.FilterMode.MipNearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.NearestMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.MipLinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.NearestMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.LinearMipNearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; case TextureFile.FilterMode.LinearMipLinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; default: throw new Exception("[Model] Invalid value for FilterMode"); } // U addressing // Адресация текстуры по горизонтали switch (t.AddressU) { case TextureFile.AddressMode.Repeat: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Repeat); break; case TextureFile.AddressMode.Mirror: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.MirroredRepeat); break; case TextureFile.AddressMode.Clamp: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); break; default: throw new Exception("[Model] Invalid value for AddressMode"); } // V addressing // Адресация текстуры по вертикали switch (t.AddressV) { case TextureFile.AddressMode.Repeat: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Repeat); break; case TextureFile.AddressMode.Mirror: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.MirroredRepeat); break; case TextureFile.AddressMode.Clamp: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); break; default: throw new Exception("[Model] Invalid value for AddressMode"); } } } else { GL.BindTexture(TextureTarget.Texture2D, Renderer.EmptyTexture); } } else { GL.BindTexture(TextureTarget.Texture2D, Renderer.EmptyTexture); } renderer.SetupSurface(surf, mat, geometry); }
/// <summary> /// Drawing GL data<para/> /// Отрисовка GL-данных /// </summary> void DrawGL(RendererBase renderer, TextureDictionary td, bool trans, bool force) { // Sending vertex data // Отправка вершинных данных if (vertexBuffer != 0) { GL.EnableClientState(ArrayCap.VertexArray); GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer); GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero); } // Sending normals // Отправка нормалей if (normalBuffer != 0) { GL.EnableClientState(ArrayCap.NormalArray); GL.BindBuffer(BufferTarget.ArrayBuffer, normalBuffer); GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero); } // Sending colors // Отправка цветов if (colorBuffer != 0) { GL.EnableClientState(ArrayCap.ColorArray); GL.BindBuffer(BufferTarget.ArrayBuffer, colorBuffer); GL.ColorPointer(4, ColorPointerType.UnsignedByte, 0, IntPtr.Zero); } // Drawing surfaces // Отрисовка поверхностей foreach (Surface s in Surfaces) { if (s.IndexBuffer != 0 && (s.Material.HasAlpha == trans || force)) { // Binding material // Присвоение материала BindMaterial(renderer, s, td); // Drawing tris // Отрисовка треугольников PrimitiveType pt = PrimitiveType.Triangles; int triCount = s.IndexCount / 3; if (s.IsTriangleStrip) { pt = PrimitiveType.TriangleStrip; triCount = s.IndexCount - 2; } GL.BindBuffer(BufferTarget.ElementArrayBuffer, s.IndexBuffer); GL.DrawElements(pt, s.IndexCount, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.DisableClientState(ArrayCap.TextureCoordArray); // Incrementing counters // Увеличение счётчиков Renderer.TrisRendered += triCount; Renderer.DrawCalls++; } } // Unbinding the buffers // Отключаем буфферы GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); // Disabling states // Отключение стейтов if (vertexBuffer != 0) { GL.DisableClientState(ArrayCap.VertexArray); } if (normalBuffer != 0) { GL.DisableClientState(ArrayCap.NormalArray); } if (colorBuffer != 0) { GL.DisableClientState(ArrayCap.ColorArray); } }
/// <summary> /// Create texture from dictionary<para/> /// Создание текстуры из архива /// </summary> /// <param name="texName">Texture name<para/>Имя текстуры в архиве</param> /// <param name="parent">Parental texture dictionary<para/>Текстурный архив</param> public Texture(string texName, TextureDictionary parent) { Parent = parent; name = texName; State = ReadyState.NotSent; }
/// <summary> /// Initialize predefined textures<para/> /// Инициализация предзаданных текстур /// </summary> public static void Init() { // Checking for extensions // Проверка расширений CompressionSupported = GLExtensions.Supported("GL_EXT_Texture_Compression_S3TC"); FrameBufferSupported = GLExtensions.Supported("GL_ARB_Framebuffer_Object"); // Load DAT-defined texture dictionaries // Загрузка предопределенных архивов текстур foreach (string TXD in FileManager.TextureFiles) { string name = Path.GetFileNameWithoutExtension(TXD).ToLower(); string path = PathManager.GetAbsolute(TXD); TextureFile f = new TextureFile(path, true); CachedFiles.TryAdd(name, f); TextureDictionary td = new TextureDictionary(f, true, true); Cached.TryAdd(name, td); } // Starting TextureFile thread // Запуск потока чтения TextureFile fileReaderThread = new Thread(FileLoaderProcess); fileReaderThread.IsBackground = true; fileReaderThread.Priority = ThreadPriority.BelowNormal; fileReaderThread.Start(); // Starting model builder thread // Запуск потока постройки Model textureBuilderThread = new Thread(TextureBuilderProcess); textureBuilderThread.IsBackground = true; textureBuilderThread.Priority = ThreadPriority.BelowNormal; textureBuilderThread.Start(); }
/// <summary> /// Process mesh internals<para/> /// Обработка данных меша /// </summary> public void Process(bool needed) { if (needed) { if (GroupModel != null) { if (GroupTextures != null) { if (GroupModel.State == Model.ReadyState.Complete && GroupTextures.State == TextureDictionary.ReadyState.Complete) { // Surface is ready to render // Поверхность готова к отрисовке Ready = true; Model.SubMesh[] subs = GroupModel.GetAllSubMeshes(); Renderers = new StaticRenderer[subs.Length]; Coords.Position = Coords.Position; for (int i = 0; i < Renderers.Length; i++) { Renderers[i] = new StaticRenderer() { BaseMatrix = Coords.Matrix, SubmeshMatrix = subs[i].Parent.Matrix, SubMesh = subs[i], Textures = GroupTextures, Fading = false, FadingDelta = 1 }; } } else { // Check for model state // Проверка состояния модели if (GroupModel.State != Model.ReadyState.Complete) { if (GroupModel.File.State == Files.RenderWareFile.LoadState.Complete) { if (!ModelManager.IsProcessing(GroupModel)) { ModelManager.ModelProcessQueue.Enqueue(GroupModel); } } } // Check for texture dictionary state // Проверка состояния архива текстур if (GroupTextures.State != TextureDictionary.ReadyState.Complete) { if (GroupTextures.File.State == Files.RenderWareFile.LoadState.Complete) { if (!TextureManager.IsProcessing(GroupTextures)) { TextureManager.TextureProcessQueue.Enqueue(GroupTextures); } } } } } else { // Texture not found - get it // Текстура не найдена - получаем её string tname = ObjectManager.Definitions[Definition.ID].TexDictionary; if (TextureManager.Cached.ContainsKey(tname)) { GroupTextures = TextureManager.Cached[tname]; } else { TextureFile tf = null; if (TextureManager.CachedFiles.ContainsKey(tname)) { tf = TextureManager.CachedFiles[tname]; } else { tf = new TextureFile(ArchiveManager.Get(tname + ".txd"), false); TextureManager.CachedFiles.TryAdd(tname, tf); TextureManager.TextureFileProcessQueue.Enqueue(tf); } GroupTextures = new TextureDictionary(tf); TextureManager.Cached.TryAdd(tname, GroupTextures); } GroupTextures.UseCount++; } } else { // Model not found - get it // Модель не найдена - получаем её string mname = ObjectManager.Definitions[Definition.ID].ModelName; if (ModelManager.Cached.ContainsKey(mname)) { GroupModel = ModelManager.Cached[mname]; } else { ModelFile mf = null; if (ModelManager.CachedFiles.ContainsKey(mname)) { mf = ModelManager.CachedFiles[mname]; } else { mf = new ModelFile(ArchiveManager.Get(mname + ".dff"), false); ModelManager.CachedFiles.TryAdd(mname, mf); ModelManager.ModelFileProcessQueue.Enqueue(mf); } GroupModel = new Model(mf); ModelManager.Cached.TryAdd(mname, GroupModel); } GroupModel.UseCount++; } } else { // Cleaning all the usings // Очистка использований if (GroupModel != null) { if (!GroupModel.Important) { GroupModel.UseCount--; } GroupModel = null; } if (GroupTextures != null) { if (!GroupTextures.Important) { GroupTextures.UseCount--; } GroupTextures = null; } if (Renderers!=null) { Renderers = null; } Ready = false; } }
/// <summary> /// Check if currently background thread is processing this dictionary<para/> /// Проверка, обрабатывается ли указанный текстурный архив /// </summary> /// <param name="texture">Archive to check<para/>Архив для проверки</param> /// <returns>True if archive is processing<para/>True если архив обрабатывается</returns> public static bool IsProcessing(TextureDictionary texture) { return TextureProcessQueue.Contains(texture) || ReadyTextureQueue.Contains(texture); }
/// <summary> /// Bind material data<para/> /// Присвоение материала /// </summary> void BindMaterial(RendererBase renderer, Surface surf, TextureDictionary td) { Material mat = surf.Material; if (mat.Textures!=null) { Texture t = (Texture)mat.Textures[0]; TextureDictionary.Texture tex = t.CachedTexture; // Caching texture // Кешируем текстуру if (tex != null) { if (tex.State == TextureDictionary.ReadyState.Obsolette) { tex = null; } } if (tex == null) { string lname = t.Name.ToLower(); if (td.Textures.ContainsKey(lname)) { tex = td.Textures[lname]; t.CachedTexture = tex; } } // Binding texture coord array // Установка массива текстурных координат GL.EnableClientState(ArrayCap.TextureCoordArray); GL.BindBuffer(BufferTarget.ArrayBuffer, tex1Buffer); GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero); // Binding it // Установка текстуры if (tex!=null) { if (tex.State == TextureDictionary.ReadyState.Complete) { // Binding tex // Установка текстуры tex.Bind(); // Setting up addressing and filtering // Установка адресации и фильтрации TextureFile.FilterMode fm = t.Filter; if (true) {//!tex.Mipmapped) { switch (t.Filter) { case TextureFile.FilterMode.MipNearest: fm = TextureFile.FilterMode.Nearest; break; case TextureFile.FilterMode.MipLinear: fm = TextureFile.FilterMode.Nearest; break; case TextureFile.FilterMode.LinearMipNearest: fm = TextureFile.FilterMode.Linear; break; case TextureFile.FilterMode.LinearMipLinear: fm = TextureFile.FilterMode.Linear; break; } } switch (fm) { case TextureFile.FilterMode.Nearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.Linear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; case TextureFile.FilterMode.MipNearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.NearestMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.MipLinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.NearestMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest); break; case TextureFile.FilterMode.LinearMipNearest: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; case TextureFile.FilterMode.LinearMipLinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); break; default: throw new Exception("[Model] Invalid value for FilterMode"); } // U addressing // Адресация текстуры по горизонтали switch (t.AddressU) { case TextureFile.AddressMode.Repeat: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Repeat); break; case TextureFile.AddressMode.Mirror: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.MirroredRepeat); break; case TextureFile.AddressMode.Clamp: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Clamp); break; default: throw new Exception("[Model] Invalid value for AddressMode"); } // V addressing // Адресация текстуры по вертикали switch (t.AddressV) { case TextureFile.AddressMode.Repeat: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Repeat); break; case TextureFile.AddressMode.Mirror: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.MirroredRepeat); break; case TextureFile.AddressMode.Clamp: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Clamp); break; default: throw new Exception("[Model] Invalid value for AddressMode"); } } } else { GL.BindTexture(TextureTarget.Texture2D, Renderer.EmptyTexture); } }else{ GL.BindTexture(TextureTarget.Texture2D, Renderer.EmptyTexture); } renderer.SetupSurface(surf, mat, geometry); }
/// <summary> /// Drawing GL data<para/> /// Отрисовка GL-данных /// </summary> void DrawGL(RendererBase renderer, TextureDictionary td, bool trans, bool force) { // Sending vertex data // Отправка вершинных данных if (vertexBuffer!=0) { GL.EnableClientState(ArrayCap.VertexArray); GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer); GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero); } // Sending normals // Отправка нормалей if (normalBuffer!=0) { GL.EnableClientState(ArrayCap.NormalArray); GL.BindBuffer(BufferTarget.ArrayBuffer, normalBuffer); GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero); } // Sending colors // Отправка цветов if (colorBuffer != 0) { GL.EnableClientState(ArrayCap.ColorArray); GL.BindBuffer(BufferTarget.ArrayBuffer, colorBuffer); GL.ColorPointer(4, ColorPointerType.UnsignedByte, 0, IntPtr.Zero); } // Drawing surfaces // Отрисовка поверхностей foreach (Surface s in Surfaces) { if (s.IndexBuffer != 0 && (s.Material.HasAlpha == trans || force)) { // Binding material // Присвоение материала BindMaterial(renderer, s, td); // Drawing tris // Отрисовка треугольников PrimitiveType pt = PrimitiveType.Triangles; int triCount = s.IndexCount/3; if (s.IsTriangleStrip) { pt = PrimitiveType.TriangleStrip; triCount = s.IndexCount - 2; } GL.BindBuffer(BufferTarget.ElementArrayBuffer, s.IndexBuffer); GL.DrawElements(pt, s.IndexCount, DrawElementsType.UnsignedShort, IntPtr.Zero); GL.DisableClientState(ArrayCap.TextureCoordArray); // Incrementing counters // Увеличение счётчиков Renderer.TrisRendered += triCount; Renderer.DrawCalls++; } } // Unbinding the buffers // Отключаем буфферы GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); // Disabling states // Отключение стейтов if (vertexBuffer != 0) { GL.DisableClientState(ArrayCap.VertexArray); } if (normalBuffer != 0) { GL.DisableClientState(ArrayCap.NormalArray); } if (colorBuffer != 0) { GL.DisableClientState(ArrayCap.ColorArray); } }
/// <summary> /// Render this submesh<para/> /// Отрисовка этого меша /// </summary> /// <param name="td">Textures to use<para/>Текстуры для использования</param> /// <param name="trans">Transparent mode<para/>Полупрозрачный режим</param> public void Render(RendererBase renderer, TextureDictionary td, bool trans, bool force = false) { if (State != ReadyState.Obsolette) { if (State == ReadyState.Empty) { Build(); State = ReadyState.NotSent; } else if (State == ReadyState.Complete) { DrawGL(renderer, td, trans, force); } } ParentModel.UseCount++; }
/// <summary> /// Create texture from dictionary<para/> /// Создание текстуры из архива /// </summary> /// <param name="texName">Texture name<para/>Имя текстуры в архиве</param> /// <param name="parent">Parental texture dictionary<para/>Текстурный архив</param> public Texture(string texName, TextureDictionary parent) { Parent = parent; name = texName; State = ReadyState.NotSent; }